jcs's openbsd hax
openbsd
1/* $OpenBSD: ftpd.c,v 1.235 2025/05/08 15:22:49 deraadt Exp $ */
2/* $NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $ */
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
35 * The Regents of the University of California. All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62/*
63 * FTP server.
64 */
65#include <sys/stat.h>
66#include <sys/ioctl.h>
67#include <sys/socket.h>
68#include <sys/wait.h>
69#include <sys/mman.h>
70
71#include <netinet/in.h>
72#include <netinet/ip.h>
73#include <netinet/tcp.h>
74
75#define FTP_NAMES
76#include <arpa/ftp.h>
77#include <arpa/inet.h>
78#include <arpa/telnet.h>
79
80#include <bsd_auth.h>
81#include <ctype.h>
82#include <dirent.h>
83#include <errno.h>
84#include <fcntl.h>
85#include <glob.h>
86#include <limits.h>
87#include <login_cap.h>
88#include <netdb.h>
89#include <pwd.h>
90#include <signal.h>
91#include <stdarg.h>
92#include <stdio.h>
93#include <stdlib.h>
94#include <string.h>
95#include <syslog.h>
96#include <time.h>
97#include <vis.h>
98#include <unistd.h>
99#include <utmp.h>
100#include <poll.h>
101
102#include "pathnames.h"
103#include "monitor.h"
104#include "extern.h"
105
106extern off_t restart_point;
107extern char cbuf[];
108
109union sockunion ctrl_addr;
110union sockunion data_source;
111union sockunion data_dest;
112union sockunion his_addr;
113union sockunion pasv_addr;
114
115sigset_t allsigs;
116
117int daemon_mode = 0;
118int data;
119int logged_in;
120struct passwd *pw;
121int debug = 0;
122int timeout = 900; /* timeout after 15 minutes of inactivity */
123int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
124int logging;
125int anon_ok = 1;
126int anon_only = 0;
127unsigned int minuid = 1000;
128int multihome = 0;
129int guest;
130int stats;
131int statfd = -1;
132int portcheck = 1;
133int dochroot;
134int type;
135int form;
136int stru; /* avoid C keyword */
137int mode;
138int doutmp = 0; /* update utmp file */
139int nowtmp = 0; /* do not update wtmp file */
140int usedefault = 1; /* for data transfers */
141int pdata = -1; /* for passive mode */
142int family = AF_UNSPEC;
143volatile sig_atomic_t transflag;
144off_t file_size;
145off_t byte_count;
146mode_t defumask = S_IWGRP|S_IWOTH; /* default umask value */
147int umaskchange = 1; /* allow user to change umask value. */
148char tmpline[7];
149char hostname[HOST_NAME_MAX+1];
150char remotehost[HOST_NAME_MAX+1];
151char dhostname[HOST_NAME_MAX+1];
152char *guestpw;
153char ttyline[20];
154static struct utmp utmp; /* for utmp */
155static login_cap_t *lc;
156static auth_session_t *as;
157static volatile sig_atomic_t recvurg;
158
159int epsvall = 0;
160
161/*
162 * Timeout intervals for retrying connections
163 * to hosts that don't accept PORT cmds. This
164 * is a kludge, but given the problems with TCP...
165 */
166#define SWAITMAX 90 /* wait at most 90 seconds */
167#define SWAITINT 5 /* interval between retries */
168
169int swaitmax = SWAITMAX;
170int swaitint = SWAITINT;
171
172char proctitle[BUFSIZ]; /* initial part of title */
173
174#define LOGCMD(cmd, file) \
175 if (logging > 1) \
176 syslog(LOG_INFO,"%s %s%s", cmd, \
177 *(file) == '/' ? "" : curdir(), file);
178#define LOGCMD2(cmd, file1, file2) \
179 if (logging > 1) \
180 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
181 *(file1) == '/' ? "" : curdir(), file1, \
182 *(file2) == '/' ? "" : curdir(), file2);
183#define LOGBYTES(cmd, file, cnt) \
184 if (logging > 1) { \
185 if ((cnt) == -1) \
186 syslog(LOG_INFO,"%s %s%s", cmd, \
187 *(file) == '/' ? "" : curdir(), file); \
188 else \
189 syslog(LOG_INFO, "%s %s%s = %lld bytes", \
190 cmd, (*(file) == '/') ? "" : curdir(), file, \
191 (long long)(cnt)); \
192 }
193
194static void ack(const char *);
195static void sigurg(int);
196static void myoob(void);
197static int checkuser(char *, const char *);
198static FILE *dataconn(const char *, off_t, char *);
199static void dolog(struct sockaddr *);
200static char *copy_dir(char *, struct passwd *);
201static char *curdir(void);
202static void end_login(void);
203static FILE *getdatasock(char *);
204static int guniquefd(const char *, char **);
205static void lostconn(int);
206static void sigquit(int);
207static int receive_data(FILE *, FILE *);
208static void replydirname(const char *, const char *);
209static int send_data(FILE *, FILE *, off_t, off_t, int);
210static struct passwd *
211 sgetpwnam(const char *, struct passwd *);
212static void reapchild(int);
213static void usage(void);
214
215void logxfer(const char *, off_t, time_t);
216void set_slave_signals(void);
217
218static char *
219curdir(void)
220{
221 static char path[PATH_MAX+1]; /* path + '/' */
222
223 if (getcwd(path, sizeof(path)-1) == NULL)
224 return ("");
225 if (path[1] != '\0') /* special case for root dir. */
226 strlcat(path, "/", sizeof path);
227 /* For guest account, skip / since it's chrooted */
228 return (guest ? path+1 : path);
229}
230
231char *argstr = "AdDhnlm:MSt:T:u:PUvW46";
232
233static void
234usage(void)
235{
236 syslog(LOG_ERR,
237 "usage: ftpd [-46ADdlMnPSUW] [-m minuid] [-T maxtimeout] "
238 "[-t timeout] [-u mask]");
239 exit(2);
240}
241
242int
243main(int argc, char *argv[])
244{
245 socklen_t addrlen;
246 int ch, on = 1, tos;
247 char line[LINE_MAX];
248 FILE *fp;
249 struct hostent *hp;
250 struct sigaction sa;
251 int error = 0;
252 const char *errstr;
253
254 tzset(); /* in case no timezone database in ~ftp */
255 sigfillset(&allsigs); /* used to block signals while root */
256 sigemptyset(&sa.sa_mask);
257 sa.sa_flags = SA_RESTART;
258
259 while ((ch = getopt(argc, argv, argstr)) != -1) {
260 switch (ch) {
261 case 'A':
262 anon_only = 1;
263 break;
264
265 case 'd':
266 case 'v': /* deprecated */
267 debug = 1;
268 break;
269
270 case 'D':
271 daemon_mode = 1;
272 break;
273
274 case 'P':
275 portcheck = 0;
276 break;
277
278 case 'h': /* deprecated */
279 break;
280
281 case 'l':
282 logging++; /* > 1 == extra logging */
283 break;
284
285 case 'm':
286 minuid = strtonum(optarg, 0, UINT_MAX, &errstr);
287 if (errstr) {
288 syslog(LOG_ERR,
289 "%s is a bad value for -m, aborting",
290 optarg);
291 exit(2);
292 }
293 break;
294
295 case 'M':
296 multihome = 1;
297 break;
298
299 case 'n':
300 anon_ok = 0;
301 break;
302
303 case 'S':
304 stats = 1;
305 break;
306
307 case 't':
308 timeout = strtonum(optarg, 0, INT_MAX, &errstr);
309 if (errstr) {
310 syslog(LOG_ERR,
311 "%s is a bad value for -t, aborting",
312 optarg);
313 exit(2);
314 }
315 if (maxtimeout < timeout)
316 maxtimeout = timeout;
317 break;
318
319 case 'T':
320 maxtimeout = strtonum(optarg, 0, INT_MAX,
321 &errstr);
322 if (errstr) {
323 syslog(LOG_ERR,
324 "%s is a bad value for -T, aborting",
325 optarg);
326 exit(2);
327 }
328 if (timeout > maxtimeout)
329 timeout = maxtimeout;
330 break;
331
332 case 'u':
333 {
334 long val = 0;
335 char *p;
336 umaskchange = 0;
337
338 val = strtol(optarg, &p, 8);
339 if (*optarg == '\0' || *p != '\0' || val < 0 ||
340 (val & ~ACCESSPERMS)) {
341 syslog(LOG_ERR,
342 "%s is a bad value for -u, aborting",
343 optarg);
344 exit(2);
345 }
346 defumask = val;
347 break;
348 }
349
350 case 'U':
351 doutmp = 1;
352 break;
353
354 case 'W':
355 nowtmp = 1;
356 break;
357
358 case '4':
359 family = AF_INET;
360 break;
361
362 case '6':
363 family = AF_INET6;
364 break;
365
366 default:
367 usage();
368 break;
369 }
370 }
371
372 if (nowtmp && doutmp) {
373 syslog(LOG_ERR, "options 'U' and 'W' are mutually exclusive");
374 exit(1);
375 }
376
377 (void) freopen(_PATH_DEVNULL, "w", stderr);
378
379 /*
380 * LOG_NDELAY sets up the logging connection immediately,
381 * necessary for anonymous ftp's that chroot and can't do it later.
382 */
383 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
384
385 if (getpwnam(FTPD_PRIVSEP_USER) == NULL) {
386 syslog(LOG_ERR, "privilege separation user %s not found",
387 FTPD_PRIVSEP_USER);
388 exit(1);
389 }
390
391 if (daemon_mode) {
392 int *fds, fd;
393 struct pollfd *pfds;
394 struct addrinfo hints, *res, *res0;
395 nfds_t n, i;
396
397 /*
398 * Detach from parent.
399 */
400 if (daemon(1, 1) == -1) {
401 syslog(LOG_ERR, "failed to become a daemon");
402 exit(1);
403 }
404 sa.sa_handler = reapchild;
405 (void) sigaction(SIGCHLD, &sa, NULL);
406
407 memset(&hints, 0, sizeof(hints));
408 hints.ai_family = family;
409 hints.ai_socktype = SOCK_STREAM;
410 hints.ai_protocol = IPPROTO_TCP;
411 hints.ai_flags = AI_PASSIVE;
412 error = getaddrinfo(NULL, "ftp", &hints, &res0);
413 if (error) {
414 syslog(LOG_ERR, "%s", gai_strerror(error));
415 exit(1);
416 }
417
418 n = 0;
419 for (res = res0; res; res = res->ai_next)
420 n++;
421
422 fds = calloc(n, sizeof(int));
423 pfds = calloc(n, sizeof(struct pollfd));
424 if (!fds || !pfds) {
425 syslog(LOG_ERR, "%s", strerror(errno));
426 exit(1);
427 }
428
429 /*
430 * Open sockets, bind it to the FTP port, and start
431 * listening.
432 */
433 n = 0;
434 for (res = res0; res; res = res->ai_next) {
435 fds[n] = socket(res->ai_family, res->ai_socktype,
436 res->ai_protocol);
437 if (fds[n] == -1)
438 continue;
439
440 if (setsockopt(fds[n], SOL_SOCKET, SO_KEEPALIVE,
441 &on, sizeof(on)) == -1) {
442 close(fds[n]);
443 fds[n] = -1;
444 continue;
445 }
446
447 if (setsockopt(fds[n], SOL_SOCKET, SO_REUSEADDR,
448 &on, sizeof(on)) == -1) {
449 close(fds[n]);
450 fds[n] = -1;
451 continue;
452 }
453
454 if (bind(fds[n], res->ai_addr, res->ai_addrlen) == -1) {
455 close(fds[n]);
456 fds[n] = -1;
457 continue;
458 }
459 if (listen(fds[n], 32) == -1) {
460 close(fds[n]);
461 fds[n] = -1;
462 continue;
463 }
464
465 pfds[n].fd = fds[n];
466 pfds[n].events = POLLIN;
467 n++;
468 }
469 freeaddrinfo(res0);
470
471 if (n == 0) {
472 syslog(LOG_ERR, "could not open control socket");
473 exit(1);
474 }
475
476 /*
477 * Loop forever accepting connection requests and forking off
478 * children to handle them.
479 */
480 while (1) {
481 if (poll(pfds, n, INFTIM) == -1) {
482 if (errno == EINTR)
483 continue;
484 syslog(LOG_ERR, "poll: %m");
485 exit(1);
486 }
487 for (i = 0; i < n; i++)
488 if (pfds[i].revents & POLLIN) {
489 addrlen = sizeof(his_addr);
490 fd = accept(pfds[i].fd,
491 (struct sockaddr *)&his_addr,
492 &addrlen);
493 if (fd != -1) {
494 if (fork() == 0)
495 goto child;
496 close(fd);
497 }
498 }
499 }
500
501 child:
502 /* child */
503 (void)dup2(fd, STDIN_FILENO);
504 (void)dup2(fd, STDOUT_FILENO);
505 for (i = 0; i < n; i++)
506 close(fds[i]);
507 } else {
508 addrlen = sizeof(his_addr);
509 if (getpeername(0, (struct sockaddr *)&his_addr,
510 &addrlen) == -1) {
511 /* syslog(LOG_ERR, "getpeername (%s): %m", argv[0]); */
512 exit(1);
513 }
514 }
515
516 /* set this here so klogin can use it... */
517 (void)snprintf(ttyline, sizeof(ttyline), "ftp%ld", (long)getpid());
518
519 set_slave_signals();
520
521 addrlen = sizeof(ctrl_addr);
522 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) == -1) {
523 syslog(LOG_ERR, "getsockname: %m");
524 exit(1);
525 }
526 if (his_addr.su_family == AF_INET6 &&
527 IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) {
528 syslog(LOG_WARNING,
529 "Connection from IPv4 mapped address is not supported.");
530 reply(530, "System not available.");
531 exit(1);
532 }
533 tos = IPTOS_LOWDELAY;
534 switch (his_addr.su_family) {
535 case AF_INET:
536 if (setsockopt(0, IPPROTO_IP, IP_TOS, &tos,
537 sizeof(int)) == -1)
538 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
539 break;
540 case AF_INET6:
541 if (setsockopt(0, IPPROTO_IPV6, IPV6_TCLASS, &tos,
542 sizeof(int)) == -1)
543 syslog(LOG_WARNING, "setsockopt (IPV6_TCLASS): %m");
544 break;
545 }
546 data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
547
548 /* Try to handle urgent data inline */
549 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) == -1)
550 syslog(LOG_ERR, "setsockopt: %m");
551
552 dolog((struct sockaddr *)&his_addr);
553
554 /*
555 * Set up default state
556 */
557 data = -1;
558 type = TYPE_A;
559 form = FORM_N;
560 stru = STRU_F;
561 mode = MODE_S;
562 tmpline[0] = '\0';
563
564 /* If logins are disabled, print out the message. */
565 if ((fp = fopen(_PATH_NOLOGIN, "r")) != NULL) {
566 while (fgets(line, sizeof(line), fp) != NULL) {
567 line[strcspn(line, "\n")] = '\0';
568 lreply(530, "%s", line);
569 }
570 (void) fclose(fp);
571 reply(530, "System not available.");
572 exit(0);
573 }
574 if ((fp = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
575 while (fgets(line, sizeof(line), fp) != NULL) {
576 line[strcspn(line, "\n")] = '\0';
577 lreply(220, "%s", line);
578 }
579 (void) fclose(fp);
580 /* reply(220,) must follow */
581 }
582 (void) gethostname(hostname, sizeof(hostname));
583
584 /* Make sure hostname is fully qualified. */
585 hp = gethostbyname(hostname);
586 if (hp != NULL)
587 strlcpy(hostname, hp->h_name, sizeof(hostname));
588
589 if (multihome) {
590 error = getnameinfo((struct sockaddr *)&ctrl_addr,
591 ctrl_addr.su_len, dhostname, sizeof(dhostname), NULL, 0, 0);
592 }
593
594 if (error != 0)
595 reply(220, "FTP server ready.");
596 else
597 reply(220, "%s FTP server ready.",
598 (multihome ? dhostname : hostname));
599
600 monitor_init();
601
602 for (;;)
603 (void) yyparse();
604 /* NOTREACHED */
605}
606
607/*
608 * Signal handlers.
609 */
610static void
611lostconn(int signo)
612{
613 struct syslog_data sdata = SYSLOG_DATA_INIT;
614
615 sdata.log_fac = LOG_FTP;
616 if (debug)
617 syslog_r(LOG_DEBUG, &sdata, "lost connection");
618 dologout(1);
619}
620
621static void
622sigquit(int signo)
623{
624 struct syslog_data sdata = SYSLOG_DATA_INIT;
625
626 sdata.log_fac = LOG_FTP;
627 syslog_r(LOG_DEBUG, &sdata, "got signal %s", sys_signame[signo]);
628 dologout(1);
629}
630
631/*
632 * Save the result of a getpwnam. Used for USER command, since
633 * the data returned must not be clobbered by any other command
634 * (e.g., globbing).
635 */
636static struct passwd *
637sgetpwnam(const char *name, struct passwd *pw)
638{
639 static struct passwd *save;
640 struct passwd *old;
641
642 if (pw == NULL && (pw = getpwnam(name)) == NULL)
643 return (NULL);
644 old = save;
645 save = pw_dup(pw);
646 if (save == NULL) {
647 perror_reply(421, "Local resource failure: malloc");
648 dologout(1);
649 /* NOTREACHED */
650 }
651 if (old) {
652 explicit_bzero(old->pw_passwd, strlen(old->pw_passwd));
653 free(old);
654 }
655 return (save);
656}
657
658static int login_attempts; /* number of failed login attempts */
659static int askpasswd; /* had user command, ask for passwd */
660static char curname[LOGIN_NAME_MAX]; /* current USER name */
661
662/*
663 * USER command.
664 * Sets global passwd pointer pw if named account exists and is acceptable;
665 * sets askpasswd if a PASS command is expected. If logged in previously,
666 * need to reset state. If name is "ftp" or "anonymous", the name is not in
667 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
668 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
669 * requesting login privileges. Disallow anyone who does not have a standard
670 * shell as returned by getusershell(). Disallow anyone mentioned in the file
671 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
672 */
673void
674user(char *name)
675{
676 char *cp, *shell, *style, *host;
677 char *class = NULL;
678
679 if (logged_in) {
680 kill_slave("user already logged in");
681 end_login();
682 }
683
684 /* Close session from previous user if there was one. */
685 if (as) {
686 auth_close(as);
687 as = NULL;
688 }
689 if (lc) {
690 login_close(lc);
691 lc = NULL;
692 }
693
694 if ((style = strchr(name, ':')) != NULL)
695 *style++ = 0;
696
697 guest = 0;
698 askpasswd = 0;
699 host = multihome ? dhostname : hostname;
700 if (anon_ok &&
701 (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0)) {
702 if (checkuser(_PATH_FTPUSERS, "ftp") ||
703 checkuser(_PATH_FTPUSERS, "anonymous"))
704 reply(530, "User %s access denied.", name);
705 else if ((pw = sgetpwnam("ftp", NULL)) != NULL) {
706 if ((lc = login_getclass(pw->pw_class)) == NULL ||
707 (as = auth_open()) == NULL ||
708 auth_setpwd(as, pw) != 0 ||
709 auth_setoption(as, "FTPD_HOST", host) < 0) {
710 if (as) {
711 auth_close(as);
712 as = NULL;
713 }
714 if (lc) {
715 login_close(lc);
716 lc = NULL;
717 }
718 reply(421, "Local resource failure");
719 return;
720 }
721 guest = 1;
722 askpasswd = 1;
723 reply(331,
724 "Guest login ok, send your email address as password.");
725 } else
726 reply(530, "User %s unknown.", name);
727 if (!askpasswd && logging)
728 syslog(LOG_NOTICE,
729 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
730 return;
731 }
732
733 shell = _PATH_BSHELL;
734 if ((pw = sgetpwnam(name, NULL))) {
735 class = pw->pw_class;
736 if (pw->pw_shell != NULL && *pw->pw_shell != '\0')
737 shell = pw->pw_shell;
738 while ((cp = getusershell()) != NULL)
739 if (strcmp(cp, shell) == 0)
740 break;
741 shell = cp;
742 endusershell();
743 }
744
745 /* Get login class; if invalid style treat like unknown user. */
746 lc = login_getclass(class);
747 if (lc && (style = login_getstyle(lc, style, "auth-ftp")) == NULL) {
748 login_close(lc);
749 lc = NULL;
750 pw = NULL;
751 }
752
753 /* Do pre-authentication setup. */
754 if (lc && ((as = auth_open()) == NULL ||
755 (pw != NULL && auth_setpwd(as, pw) != 0) ||
756 auth_setitem(as, AUTHV_STYLE, style) < 0 ||
757 auth_setitem(as, AUTHV_NAME, name) < 0 ||
758 auth_setitem(as, AUTHV_CLASS, class) < 0 ||
759 auth_setoption(as, "login", "yes") < 0 ||
760 auth_setoption(as, "notickets", "yes") < 0 ||
761 auth_setoption(as, "FTPD_HOST", host) < 0)) {
762 if (as) {
763 auth_close(as);
764 as = NULL;
765 }
766 login_close(lc);
767 lc = NULL;
768 reply(421, "Local resource failure");
769 return;
770 }
771 if (logging)
772 strlcpy(curname, name, sizeof(curname));
773
774 dochroot = (lc && login_getcapbool(lc, "ftp-chroot", 0)) ||
775 checkuser(_PATH_FTPCHROOT, name);
776 if (anon_only && !dochroot) {
777 reply(530, "User %s access denied.", name);
778 return;
779 }
780 if (pw) {
781 if (pw->pw_uid < minuid) {
782 reply(530, "User %s access denied.", name);
783 if (logging)
784 syslog(LOG_NOTICE,
785 "FTP LOGIN REFUSED FROM %s, %s (UID))",
786 remotehost, name);
787 return;
788 }
789 if ((!shell && !dochroot) || checkuser(_PATH_FTPUSERS, name)) {
790 reply(530, "User %s access denied.", name);
791 if (logging)
792 syslog(LOG_NOTICE,
793 "FTP LOGIN REFUSED FROM %s, %s",
794 remotehost, name);
795 pw = NULL;
796 return;
797 }
798 }
799
800 if (as != NULL && (cp = auth_challenge(as)) != NULL)
801 reply(331, "%s", cp);
802 else
803 reply(331, "Password required for %s.", name);
804
805 askpasswd = 1;
806 /*
807 * Delay before reading passwd after first failed
808 * attempt to slow down passwd-guessing programs.
809 */
810 if (login_attempts)
811 sleep((unsigned) login_attempts);
812}
813
814/*
815 * Check if a user is in the file "fname"
816 */
817static int
818checkuser(char *fname, const char *name)
819{
820 FILE *fp;
821 int found = 0;
822 char *p, line[BUFSIZ];
823
824 if ((fp = fopen(fname, "r")) != NULL) {
825 while (fgets(line, sizeof(line), fp) != NULL)
826 if ((p = strchr(line, '\n')) != NULL) {
827 *p = '\0';
828 if (line[0] == '#')
829 continue;
830 if (strcmp(line, name) == 0) {
831 found = 1;
832 break;
833 }
834 }
835 (void) fclose(fp);
836 }
837 return (found);
838}
839
840/*
841 * Terminate login as previous user, if any, resetting state;
842 * used when USER command is given or login fails.
843 */
844static void
845end_login(void)
846{
847 sigprocmask (SIG_BLOCK, &allsigs, NULL);
848 if (logged_in) {
849 if (!nowtmp)
850 ftpdlogwtmp(ttyline, "", "");
851 if (doutmp)
852 ftpd_logout(utmp.ut_line);
853 }
854 reply(530, "Please reconnect to work as another user");
855 _exit(0);
856}
857
858enum auth_ret
859pass(char *passwd)
860{
861 int authok;
862 unsigned int flags;
863 FILE *fp;
864 static char homedir[PATH_MAX];
865 char *motd, *dir, rootdir[PATH_MAX];
866 size_t sz_pw_dir;
867
868 if (logged_in || askpasswd == 0) {
869 reply(503, "Login with USER first.");
870 return (AUTH_FAILED);
871 }
872 askpasswd = 0;
873 if (!guest) { /* "ftp" is only account allowed no password */
874 authok = 0;
875 if (pw == NULL || pw->pw_passwd[0] == '\0') {
876 useconds_t us;
877
878 /* Sleep between 1 and 3 seconds to emulate a crypt. */
879 us = arc4random_uniform(3000000);
880 usleep(us);
881 if (as != NULL) {
882 auth_close(as);
883 as = NULL;
884 }
885 } else {
886 authok = auth_userresponse(as, passwd, 0);
887 as = NULL;
888 }
889 if (authok == 0) {
890 reply(530, "Login incorrect.");
891 if (logging)
892 syslog(LOG_NOTICE,
893 "FTP LOGIN FAILED FROM %s, %s",
894 remotehost, curname);
895 pw = NULL;
896 if (login_attempts++ >= 5) {
897 syslog(LOG_NOTICE,
898 "repeated login failures from %s",
899 remotehost);
900 kill_slave("repeated login failures");
901 _exit(0);
902 }
903 return (AUTH_FAILED);
904 }
905 } else if (lc != NULL) {
906 /* Save anonymous' password. */
907 free(guestpw);
908 guestpw = strdup(passwd);
909 if (guestpw == NULL) {
910 kill_slave("out of mem");
911 fatal("Out of memory.");
912 }
913
914 authok = auth_approval(as, lc, pw->pw_name, "ftp");
915 auth_close(as);
916 as = NULL;
917 if (authok == 0) {
918 syslog(LOG_INFO|LOG_AUTH,
919 "FTP LOGIN FAILED (HOST) as %s: approval failure.",
920 pw->pw_name);
921 reply(530, "Approval failure.");
922 kill_slave("approval failure");
923 _exit(0);
924 }
925 } else {
926 syslog(LOG_INFO|LOG_AUTH,
927 "FTP LOGIN CLASS %s MISSING for %s: approval failure.",
928 pw->pw_class, pw->pw_name);
929 reply(530, "Permission denied.");
930 kill_slave("permission denied");
931 _exit(0);
932 }
933
934 if (monitor_post_auth() == 1) {
935 /* Post-auth monitor process */
936 logged_in = 1;
937 return (AUTH_MONITOR);
938 }
939
940 login_attempts = 0; /* this time successful */
941 /* set umask via setusercontext() unless -u flag was given. */
942 flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
943 if (umaskchange)
944 flags |= LOGIN_SETUMASK;
945 else
946 (void) umask(defumask);
947 if (setusercontext(lc, pw, 0, flags) != 0) {
948 perror_reply(421, "Local resource failure: setusercontext");
949 syslog(LOG_NOTICE, "setusercontext: %m");
950 dologout(1);
951 /* NOTREACHED */
952 }
953
954 /* open wtmp before chroot */
955 if (!nowtmp)
956 ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
957
958 /* open utmp before chroot */
959 if (doutmp) {
960 memset(&utmp, 0, sizeof(utmp));
961 (void)time(&utmp.ut_time);
962 (void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
963 (void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
964 (void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
965 ftpd_login(&utmp);
966 }
967
968 /* open stats file before chroot */
969 if (guest && (stats == 1) && (statfd < 0))
970 if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) == -1)
971 stats = 0;
972
973 logged_in = 1;
974
975 if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
976 char *newdir;
977
978 newdir = copy_dir(dir, pw);
979 if (newdir == NULL) {
980 perror_reply(421, "Local resource failure: malloc");
981 dologout(1);
982 /* NOTREACHED */
983 }
984 pw->pw_dir = newdir;
985 pw = sgetpwnam(NULL, pw);
986 free(dir);
987 free(newdir);
988 }
989
990 /* make sure pw->pw_dir is big enough to hold "/" */
991 sz_pw_dir = strlen(pw->pw_dir) + 1;
992 if (sz_pw_dir < 2) {
993 pw->pw_dir = "/";
994 pw = sgetpwnam(NULL, pw);
995 sz_pw_dir = 2;
996 }
997
998 if (guest || dochroot) {
999 if (multihome && guest) {
1000 struct stat ts;
1001
1002 /* Compute root directory. */
1003 snprintf(rootdir, sizeof(rootdir), "%s/%s",
1004 pw->pw_dir, dhostname);
1005 if (stat(rootdir, &ts) == -1) {
1006 snprintf(rootdir, sizeof(rootdir), "%s/%s",
1007 pw->pw_dir, hostname);
1008 }
1009 } else
1010 strlcpy(rootdir, pw->pw_dir, sizeof(rootdir));
1011 }
1012 if (guest) {
1013 /*
1014 * We MUST do a chdir() after the chroot. Otherwise
1015 * the old current directory will be accessible as "."
1016 * outside the new root!
1017 */
1018 if (chroot(rootdir) == -1 || chdir("/") == -1) {
1019 reply(550, "Can't set guest privileges.");
1020 goto bad;
1021 }
1022 strlcpy(pw->pw_dir, "/", sz_pw_dir);
1023 if (setenv("HOME", "/", 1) == -1) {
1024 reply(550, "Can't setup environment.");
1025 goto bad;
1026 }
1027 } else if (dochroot) {
1028 if (chroot(rootdir) == -1 || chdir("/") == -1) {
1029 reply(550, "Can't change root.");
1030 goto bad;
1031 }
1032 strlcpy(pw->pw_dir, "/", sz_pw_dir);
1033 if (setenv("HOME", "/", 1) == -1) {
1034 reply(550, "Can't setup environment.");
1035 goto bad;
1036 }
1037 } else if (chdir(pw->pw_dir) == -1) {
1038 if (chdir("/") == -1) {
1039 reply(530, "User %s: can't change directory to %s.",
1040 pw->pw_name, pw->pw_dir);
1041 goto bad;
1042 } else
1043 lreply(230, "No directory! Logging in with home=/");
1044 }
1045 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) {
1046 reply(550, "Can't set gid.");
1047 goto bad;
1048 }
1049 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
1050 reply(550, "Can't set uid.");
1051 goto bad;
1052 }
1053 sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1054
1055 /*
1056 * Set home directory so that use of ~ (tilde) works correctly.
1057 */
1058 if (getcwd(homedir, PATH_MAX) != NULL) {
1059 if (setenv("HOME", homedir, 1) == -1) {
1060 reply(550, "Can't setup environment.");
1061 goto bad;
1062 }
1063 }
1064
1065 /*
1066 * Display a login message, if it exists.
1067 * N.B. reply(230,) must follow the message.
1068 */
1069 motd = login_getcapstr(lc, "welcome", NULL, NULL);
1070 if ((fp = fopen(motd ? motd : _PATH_FTPLOGINMESG, "r")) != NULL) {
1071 char line[LINE_MAX];
1072
1073 while (fgets(line, sizeof(line), fp) != NULL) {
1074 line[strcspn(line, "\n")] = '\0';
1075 lreply(230, "%s", line);
1076 }
1077 (void) fclose(fp);
1078 }
1079 free(motd);
1080 if (guest) {
1081 reply(230, "Guest login ok, access restrictions apply.");
1082 snprintf(proctitle, sizeof(proctitle),
1083 "%s: anonymous/%.*s", remotehost,
1084 (int)(sizeof(proctitle) - sizeof(remotehost) -
1085 sizeof(": anonymous/")), passwd);
1086 setproctitle("%s", proctitle);
1087 if (logging)
1088 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1089 remotehost, passwd);
1090 } else {
1091 reply(230, "User %s logged in.", pw->pw_name);
1092 snprintf(proctitle, sizeof(proctitle),
1093 "%s: %s", remotehost, pw->pw_name);
1094 setproctitle("%s", proctitle);
1095 if (logging)
1096 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1097 remotehost, pw->pw_name);
1098 }
1099 login_close(lc);
1100 lc = NULL;
1101 return (AUTH_SLAVE);
1102bad:
1103 /* Forget all about it... */
1104 login_close(lc);
1105 lc = NULL;
1106 end_login();
1107 return (AUTH_FAILED);
1108}
1109
1110void
1111retrieve(enum ret_cmd cmd, const char *name)
1112{
1113 FILE *fin, *dout;
1114 struct stat st;
1115 pid_t pid;
1116 time_t start;
1117
1118 if (cmd == RET_FILE) {
1119 fin = fopen(name, "r");
1120 st.st_size = 0;
1121 } else {
1122 fin = ftpd_ls(name, &pid);
1123 st.st_size = -1;
1124 st.st_blksize = BUFSIZ;
1125 }
1126 if (fin == NULL) {
1127 if (errno != 0) {
1128 perror_reply(550, name);
1129 if (cmd == RET_FILE) {
1130 LOGCMD("get", name);
1131 }
1132 }
1133 return;
1134 }
1135 byte_count = -1;
1136 if (cmd == RET_FILE &&
1137 (fstat(fileno(fin), &st) == -1 || !S_ISREG(st.st_mode))) {
1138 reply(550, "%s: not a plain file.", name);
1139 goto done;
1140 }
1141 if (restart_point) {
1142 if (type == TYPE_A) {
1143 off_t i, n;
1144 int c;
1145
1146 n = restart_point;
1147 i = 0;
1148 while (i++ < n) {
1149 if ((c = getc(fin)) == EOF) {
1150 if (ferror(fin)) {
1151 perror_reply(550, name);
1152 goto done;
1153 } else
1154 break;
1155 }
1156 if (c == '\n')
1157 i++;
1158 }
1159 } else if (lseek(fileno(fin), restart_point, SEEK_SET) == -1) {
1160 perror_reply(550, name);
1161 goto done;
1162 }
1163 }
1164 dout = dataconn(name, st.st_size, "w");
1165 if (dout == NULL)
1166 goto done;
1167 time(&start);
1168 send_data(fin, dout, st.st_blksize, st.st_size,
1169 (restart_point == 0 && cmd == RET_FILE && S_ISREG(st.st_mode)));
1170 if ((cmd == RET_FILE) && stats)
1171 logxfer(name, byte_count, start);
1172 (void) fclose(dout);
1173 data = -1;
1174done:
1175 if (pdata >= 0)
1176 (void) close(pdata);
1177 pdata = -1;
1178 if (cmd == RET_FILE) {
1179 LOGBYTES("get", name, byte_count);
1180 fclose(fin);
1181 } else {
1182 ftpd_pclose(fin, pid);
1183 }
1184}
1185
1186void
1187store(const char *name, const char *mode, int unique)
1188{
1189 FILE *fout, *din;
1190 int (*closefunc)(FILE *);
1191 struct stat st;
1192 int fd;
1193
1194 if (restart_point && *mode != 'a')
1195 mode = "r+";
1196
1197 if (unique && stat(name, &st) == 0) {
1198 char *nam;
1199
1200 fd = guniquefd(name, &nam);
1201 if (fd == -1) {
1202 LOGCMD(*mode == 'w' ? "put" : "append", name);
1203 return;
1204 }
1205 name = nam;
1206 fout = fdopen(fd, mode);
1207 } else
1208 fout = fopen(name, mode);
1209
1210 closefunc = fclose;
1211 if (fout == NULL) {
1212 perror_reply(553, name);
1213 LOGCMD(*mode == 'w' ? "put" : "append", name);
1214 return;
1215 }
1216 byte_count = -1;
1217 if (restart_point) {
1218 if (type == TYPE_A) {
1219 off_t i, n;
1220 int c;
1221
1222 n = restart_point;
1223 i = 0;
1224 while (i++ < n) {
1225 if ((c = getc(fout)) == EOF) {
1226 if (ferror(fout)) {
1227 perror_reply(550, name);
1228 goto done;
1229 } else
1230 break;
1231 }
1232 if (c == '\n')
1233 i++;
1234 }
1235 /*
1236 * We must do this seek to "current" position
1237 * because we are changing from reading to
1238 * writing.
1239 */
1240 if (fseek(fout, 0, SEEK_CUR) == -1) {
1241 perror_reply(550, name);
1242 goto done;
1243 }
1244 } else if (lseek(fileno(fout), restart_point, SEEK_SET) == -1) {
1245 perror_reply(550, name);
1246 goto done;
1247 }
1248 }
1249 din = dataconn(name, -1, "r");
1250 if (din == NULL)
1251 goto done;
1252 if (receive_data(din, fout) == 0) {
1253 if (unique)
1254 reply(226, "Transfer complete (unique file name:%s).",
1255 name);
1256 else
1257 reply(226, "Transfer complete.");
1258 }
1259 (void) fclose(din);
1260 data = -1;
1261 pdata = -1;
1262done:
1263 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1264 (*closefunc)(fout);
1265}
1266
1267static FILE *
1268getdatasock(char *mode)
1269{
1270 int opt, s, t, tries;
1271
1272 if (data >= 0)
1273 return (fdopen(data, mode));
1274 sigprocmask (SIG_BLOCK, &allsigs, NULL);
1275 s = monitor_socket(ctrl_addr.su_family);
1276 if (s < 0)
1277 goto bad;
1278 opt = 1;
1279 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1280 &opt, sizeof(opt)) == -1)
1281 goto bad;
1282 /* anchor socket to avoid multi-homing problems */
1283 data_source = ctrl_addr;
1284 data_source.su_port = htons(20); /* ftp-data port */
1285 for (tries = 1; ; tries++) {
1286 if (monitor_bind(s, (struct sockaddr *)&data_source,
1287 data_source.su_len) >= 0)
1288 break;
1289 if (errno != EADDRINUSE || tries > 10)
1290 goto bad;
1291 sleep((unsigned int)tries);
1292 }
1293 sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1294
1295 opt = IPTOS_THROUGHPUT;
1296 switch (ctrl_addr.su_family) {
1297 case AF_INET:
1298 if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt,
1299 sizeof(opt)) == -1)
1300 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1301 break;
1302 case AF_INET6:
1303 if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &opt,
1304 sizeof(opt)) == -1)
1305 syslog(LOG_WARNING, "setsockopt (IPV6_TCLASS): %m");
1306 break;
1307 }
1308 /*
1309 * Turn off push flag to keep sender TCP from sending short packets
1310 * at the boundaries of each write(). Should probably do a SO_SNDBUF
1311 * to set the send buffer size as well, but that may not be desirable
1312 * in heavy-load situations.
1313 */
1314 opt = 1;
1315 if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt)) == -1)
1316 syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1317 opt = 65536;
1318 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) == -1)
1319 syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1320
1321 return (fdopen(s, mode));
1322bad:
1323 /* Return the real value of errno (close may change it) */
1324 t = errno;
1325 sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1326 if (s >= 0)
1327 (void) close(s);
1328 errno = t;
1329 return (NULL);
1330}
1331
1332static FILE *
1333dataconn(const char *name, off_t size, char *mode)
1334{
1335 char sizebuf[32];
1336 FILE *file = NULL;
1337 int retry = 0;
1338 in_port_t *p;
1339 u_char *fa, *ha;
1340 size_t alen;
1341 int error;
1342
1343 file_size = size;
1344 byte_count = 0;
1345 if (size != -1) {
1346 (void) snprintf(sizebuf, sizeof(sizebuf), " (%lld bytes)",
1347 (long long)size);
1348 } else
1349 sizebuf[0] = '\0';
1350 if (pdata >= 0) {
1351 union sockunion from;
1352 int s;
1353 socklen_t fromlen = sizeof(from);
1354
1355 (void) alarm ((unsigned) timeout);
1356 s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1357 (void) alarm (0);
1358 if (s == -1) {
1359 reply(425, "Can't open data connection.");
1360 (void) close(pdata);
1361 pdata = -1;
1362 return (NULL);
1363 }
1364 switch (from.su_family) {
1365 case AF_INET:
1366 p = (in_port_t *)&from.su_sin.sin_port;
1367 fa = (u_char *)&from.su_sin.sin_addr;
1368 ha = (u_char *)&his_addr.su_sin.sin_addr;
1369 alen = sizeof(struct in_addr);
1370 break;
1371 case AF_INET6:
1372 p = (in_port_t *)&from.su_sin6.sin6_port;
1373 fa = (u_char *)&from.su_sin6.sin6_addr;
1374 ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1375 alen = sizeof(struct in6_addr);
1376 break;
1377 default:
1378 reply(425, "Can't build data connection: "
1379 "unknown address family");
1380 (void) close(pdata);
1381 (void) close(s);
1382 pdata = -1;
1383 return (NULL);
1384 }
1385 if (from.su_family != his_addr.su_family ||
1386 ntohs(*p) < IPPORT_RESERVED) {
1387 reply(425, "Can't build data connection: "
1388 "address family or port error");
1389 (void) close(pdata);
1390 (void) close(s);
1391 pdata = -1;
1392 return (NULL);
1393 }
1394 if (portcheck && memcmp(fa, ha, alen) != 0) {
1395 reply(425, "Can't build data connection: "
1396 "illegal port number");
1397 (void) close(pdata);
1398 (void) close(s);
1399 pdata = -1;
1400 return (NULL);
1401 }
1402 (void) close(pdata);
1403 pdata = s;
1404 reply(150, "Opening %s mode data connection for '%s'%s.",
1405 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1406 return (fdopen(pdata, mode));
1407 }
1408 if (data >= 0) {
1409 reply(125, "Using existing data connection for '%s'%s.",
1410 name, sizebuf);
1411 usedefault = 1;
1412 return (fdopen(data, mode));
1413 }
1414 if (usedefault)
1415 data_dest = his_addr;
1416 usedefault = 1;
1417 do {
1418 if (file != NULL)
1419 (void) fclose(file);
1420 file = getdatasock(mode);
1421 if (file == NULL) {
1422 char hbuf[HOST_NAME_MAX+1], pbuf[10];
1423
1424 error = getnameinfo((struct sockaddr *)&data_source,
1425 data_source.su_len, hbuf, sizeof(hbuf), pbuf,
1426 sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1427 if (error != 0)
1428 reply(425, "Can't create data socket: %s.",
1429 strerror(errno));
1430 else
1431 reply(425,
1432 "Can't create data socket (%s,%s): %s.",
1433 hbuf, pbuf, strerror(errno));
1434 return (NULL);
1435 }
1436
1437 /*
1438 * attempt to connect to reserved port on client machine;
1439 * this looks like an attack
1440 */
1441 switch (data_dest.su_family) {
1442 case AF_INET:
1443 p = (in_port_t *)&data_dest.su_sin.sin_port;
1444 fa = (u_char *)&data_dest.su_sin.sin_addr;
1445 ha = (u_char *)&his_addr.su_sin.sin_addr;
1446 alen = sizeof(struct in_addr);
1447 break;
1448 case AF_INET6:
1449 p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1450 fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1451 ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1452 alen = sizeof(struct in6_addr);
1453 break;
1454 default:
1455 reply(425, "Can't build data connection: "
1456 "unknown address family");
1457 (void) fclose(file);
1458 pdata = -1;
1459 return (NULL);
1460 }
1461 if (data_dest.su_family != his_addr.su_family ||
1462 ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) { /* XXX */
1463 reply(425, "Can't build data connection: "
1464 "address family or port error");
1465 (void) fclose(file);
1466 return NULL;
1467 }
1468 if (portcheck && memcmp(fa, ha, alen) != 0) {
1469 reply(435, "Can't build data connection: "
1470 "illegal port number");
1471 (void) fclose(file);
1472 return NULL;
1473 }
1474
1475 if (connect(fileno(file), (struct sockaddr *)&data_dest,
1476 data_dest.su_len) == 0) {
1477 reply(150, "Opening %s mode data connection for '%s'%s.",
1478 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1479 data = fileno(file);
1480 return (file);
1481 }
1482 if (errno != EADDRINUSE)
1483 break;
1484 sleep((unsigned) swaitint);
1485 retry += swaitint;
1486 } while (retry <= swaitmax);
1487 perror_reply(425, "Can't build data connection");
1488 (void) fclose(file);
1489 return (NULL);
1490}
1491
1492/*
1493 * Transfer the contents of "instr" to "outstr" peer using the appropriate
1494 * encapsulation of the data subject to Mode, Structure, and Type.
1495 *
1496 * NB: Form isn't handled.
1497 */
1498static int
1499send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg)
1500{
1501 int c, cnt, filefd, netfd;
1502 char *buf, *bp;
1503 size_t len;
1504
1505 transflag++;
1506 switch (type) {
1507
1508 case TYPE_A:
1509 while ((c = getc(instr)) != EOF) {
1510 if (recvurg)
1511 goto got_oob;
1512 byte_count++;
1513 if (c == '\n') {
1514 if (ferror(outstr))
1515 goto data_err;
1516 (void) putc('\r', outstr);
1517 }
1518 (void) putc(c, outstr);
1519 }
1520 fflush(outstr);
1521 transflag = 0;
1522 if (ferror(instr))
1523 goto file_err;
1524 if (ferror(outstr))
1525 goto data_err;
1526 reply(226, "Transfer complete.");
1527 return(0);
1528
1529 case TYPE_I:
1530 case TYPE_L:
1531 /*
1532 * isreg is only set if we are not doing restart and we
1533 * are sending a regular file
1534 */
1535 netfd = fileno(outstr);
1536 filefd = fileno(instr);
1537
1538 if (isreg && filesize < 16 * 1024 * 1024) {
1539 size_t fsize = (size_t)filesize;
1540
1541 if (fsize == 0) {
1542 transflag = 0;
1543 reply(226, "Transfer complete.");
1544 return(0);
1545 }
1546
1547 buf = mmap(0, fsize, PROT_READ, MAP_SHARED, filefd, 0);
1548 if (buf == MAP_FAILED) {
1549 syslog(LOG_WARNING, "mmap(%llu): %m",
1550 (unsigned long long)fsize);
1551 goto oldway;
1552 }
1553 bp = buf;
1554 len = fsize;
1555 do {
1556 cnt = write(netfd, bp, len);
1557 if (recvurg) {
1558 munmap(buf, fsize);
1559 goto got_oob;
1560 }
1561 len -= cnt;
1562 bp += cnt;
1563 if (cnt > 0)
1564 byte_count += cnt;
1565 } while(cnt > 0 && len > 0);
1566
1567 transflag = 0;
1568 munmap(buf, fsize);
1569 if (cnt < 0)
1570 goto data_err;
1571 reply(226, "Transfer complete.");
1572 return(0);
1573 }
1574
1575oldway:
1576 if ((buf = malloc((size_t)blksize)) == NULL) {
1577 transflag = 0;
1578 perror_reply(451, "Local resource failure: malloc");
1579 return(-1);
1580 }
1581
1582 while ((cnt = read(filefd, buf, (size_t)blksize)) > 0 &&
1583 write(netfd, buf, cnt) == cnt)
1584 byte_count += cnt;
1585 transflag = 0;
1586 (void)free(buf);
1587 if (cnt != 0) {
1588 if (cnt == -1)
1589 goto file_err;
1590 goto data_err;
1591 }
1592 reply(226, "Transfer complete.");
1593 return(0);
1594 default:
1595 transflag = 0;
1596 reply(550, "Unimplemented TYPE %d in send_data", type);
1597 return(-1);
1598 }
1599
1600data_err:
1601 transflag = 0;
1602 reply(426, "Data connection");
1603 return(-1);
1604
1605file_err:
1606 transflag = 0;
1607 reply(551, "Error on input file");
1608 return(-1);
1609
1610got_oob:
1611 myoob();
1612 recvurg = 0;
1613 transflag = 0;
1614 return(-1);
1615}
1616
1617/*
1618 * Transfer data from peer to "outstr" using the appropriate encapulation of
1619 * the data subject to Mode, Structure, and Type.
1620 *
1621 * N.B.: Form isn't handled.
1622 */
1623static int
1624receive_data(FILE *instr, FILE *outstr)
1625{
1626 int c;
1627 int cnt;
1628 char buf[BUFSIZ];
1629 struct sigaction sa, sa_saved;
1630 volatile int bare_lfs = 0;
1631
1632 transflag++;
1633 switch (type) {
1634
1635 case TYPE_I:
1636 case TYPE_L:
1637 memset(&sa, 0, sizeof(sa));
1638 sigfillset(&sa.sa_mask);
1639 sa.sa_flags = SA_RESTART;
1640 sa.sa_handler = lostconn;
1641 (void) sigaction(SIGALRM, &sa, &sa_saved);
1642 do {
1643 (void) alarm ((unsigned) timeout);
1644 cnt = read(fileno(instr), buf, sizeof(buf));
1645 (void) alarm (0);
1646 if (recvurg)
1647 goto got_oob;
1648
1649 if (cnt > 0) {
1650 if (write(fileno(outstr), buf, cnt) != cnt)
1651 goto file_err;
1652 byte_count += cnt;
1653 }
1654 } while (cnt > 0);
1655 (void) sigaction(SIGALRM, &sa_saved, NULL);
1656 if (cnt == -1)
1657 goto data_err;
1658 transflag = 0;
1659 return (0);
1660
1661 case TYPE_E:
1662 reply(553, "TYPE E not implemented.");
1663 transflag = 0;
1664 return (-1);
1665
1666 case TYPE_A:
1667 while ((c = getc(instr)) != EOF) {
1668 if (recvurg)
1669 goto got_oob;
1670 byte_count++;
1671 if (c == '\n')
1672 bare_lfs++;
1673 while (c == '\r') {
1674 if (ferror(outstr))
1675 goto data_err;
1676 if ((c = getc(instr)) != '\n') {
1677 (void) putc ('\r', outstr);
1678 if (c == '\0' || c == EOF)
1679 goto contin2;
1680 }
1681 }
1682 (void) putc(c, outstr);
1683 contin2: ;
1684 }
1685 fflush(outstr);
1686 if (ferror(instr))
1687 goto data_err;
1688 if (ferror(outstr))
1689 goto file_err;
1690 transflag = 0;
1691 if (bare_lfs) {
1692 lreply(226,
1693 "WARNING! %d bare linefeeds received in ASCII mode",
1694 bare_lfs);
1695 printf(" File may not have transferred correctly.\r\n");
1696 }
1697 return (0);
1698 default:
1699 reply(550, "Unimplemented TYPE %d in receive_data", type);
1700 transflag = 0;
1701 return (-1);
1702 }
1703
1704data_err:
1705 transflag = 0;
1706 reply(426, "Data Connection");
1707 return (-1);
1708
1709file_err:
1710 transflag = 0;
1711 reply(452, "Error writing file");
1712 return (-1);
1713
1714got_oob:
1715 myoob();
1716 recvurg = 0;
1717 transflag = 0;
1718 return (-1);
1719}
1720
1721void
1722statfilecmd(const char *filename)
1723{
1724 FILE *fin;
1725 int c;
1726 int atstart;
1727 pid_t pid;
1728 fin = ftpd_ls(filename, &pid);
1729 if (fin == NULL) {
1730 reply(451, "Local resource failure");
1731 return;
1732 }
1733 lreply(211, "status of %s:", filename);
1734 atstart = 1;
1735 while ((c = getc(fin)) != EOF) {
1736 if (c == '\n') {
1737 if (ferror(stdout)){
1738 perror_reply(421, "control connection");
1739 (void) ftpd_pclose(fin, pid);
1740 dologout(1);
1741 /* NOTREACHED */
1742 }
1743 if (ferror(fin)) {
1744 perror_reply(551, filename);
1745 (void) ftpd_pclose(fin, pid);
1746 return;
1747 }
1748 (void) putc('\r', stdout);
1749 }
1750 if (atstart && isdigit(c))
1751 (void) putc(' ', stdout);
1752 (void) putc(c, stdout);
1753 atstart = (c == '\n');
1754 }
1755 (void) ftpd_pclose(fin, pid);
1756 reply(211, "End of Status");
1757}
1758
1759void
1760statcmd(void)
1761{
1762 union sockunion *su;
1763 u_char *a, *p;
1764 char hbuf[HOST_NAME_MAX+1];
1765 int ispassive;
1766 int error;
1767
1768 lreply(211, "%s FTP server status:", hostname);
1769 error = getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1770 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1771 printf(" Connected to %s", remotehost);
1772 if (error == 0 && strcmp(remotehost, hbuf) != 0)
1773 printf(" (%s)", hbuf);
1774 printf("\r\n");
1775 if (logged_in) {
1776 if (guest)
1777 printf(" Logged in anonymously\r\n");
1778 else
1779 printf(" Logged in as %s\r\n", pw->pw_name);
1780 } else if (askpasswd)
1781 printf(" Waiting for password\r\n");
1782 else
1783 printf(" Waiting for user name\r\n");
1784 printf(" TYPE: %s", typenames[type]);
1785 if (type == TYPE_A || type == TYPE_E)
1786 printf(", FORM: %s", formnames[form]);
1787 if (type == TYPE_L)
1788 printf(" 8");
1789 printf("; STRUcture: %s; transfer MODE: %s\r\n",
1790 strunames[stru], modenames[mode]);
1791 ispassive = 0;
1792 if (data != -1)
1793 printf(" Data connection open\r\n");
1794 else if (pdata != -1) {
1795 printf(" in Passive mode\r\n");
1796 su = (union sockunion *)&pasv_addr;
1797 ispassive++;
1798 goto printaddr;
1799 } else if (usedefault == 0) {
1800 size_t alen, i;
1801 int af;
1802
1803 su = (union sockunion *)&data_dest;
1804printaddr:
1805 /* PASV/PORT */
1806 if (su->su_family == AF_INET) {
1807 if (ispassive)
1808 printf("211- PASV ");
1809 else
1810 printf("211- PORT ");
1811 a = (u_char *)&su->su_sin.sin_addr;
1812 p = (u_char *)&su->su_sin.sin_port;
1813 printf("(%u,%u,%u,%u,%u,%u)\r\n",
1814 a[0], a[1], a[2], a[3],
1815 p[0], p[1]);
1816 }
1817
1818 /* LPSV/LPRT */
1819 alen = 0;
1820 switch (su->su_family) {
1821 case AF_INET:
1822 a = (u_char *)&su->su_sin.sin_addr;
1823 p = (u_char *)&su->su_sin.sin_port;
1824 alen = sizeof(su->su_sin.sin_addr);
1825 af = 4;
1826 break;
1827 case AF_INET6:
1828 a = (u_char *)&su->su_sin6.sin6_addr;
1829 p = (u_char *)&su->su_sin6.sin6_port;
1830 alen = sizeof(su->su_sin6.sin6_addr);
1831 af = 6;
1832 break;
1833 default:
1834 af = 0;
1835 break;
1836 }
1837 if (af) {
1838 if (ispassive)
1839 printf("211- LPSV ");
1840 else
1841 printf("211- LPRT ");
1842 printf("(%u,%llu", af, (unsigned long long)alen);
1843 for (i = 0; i < alen; i++)
1844 printf(",%u", a[i]);
1845 printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1846 }
1847
1848 /* EPRT/EPSV */
1849 switch (su->su_family) {
1850 case AF_INET:
1851 af = 1;
1852 break;
1853 case AF_INET6:
1854 af = 2;
1855 break;
1856 default:
1857 af = 0;
1858 break;
1859 }
1860 if (af) {
1861 char pbuf[10];
1862 union sockunion tmp = *su;
1863
1864 if (tmp.su_family == AF_INET6)
1865 tmp.su_sin6.sin6_scope_id = 0;
1866 if (getnameinfo((struct sockaddr *)&tmp, tmp.su_len,
1867 hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1868 NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
1869 if (ispassive)
1870 printf("211- EPSV ");
1871 else
1872 printf("211- EPRT ");
1873 printf("(|%u|%s|%s|)\r\n",
1874 af, hbuf, pbuf);
1875 }
1876 }
1877 } else
1878 printf(" No data connection\r\n");
1879 reply(211, "End of status");
1880}
1881
1882void
1883fatal(const char *s)
1884{
1885
1886 reply(451, "Error in server: %s", s);
1887 reply(221, "Closing connection due to server error.");
1888 dologout(0);
1889 /* NOTREACHED */
1890}
1891
1892void
1893reply(int n, const char *fmt, ...)
1894{
1895 char *buf, *p, *next;
1896 int rval;
1897 va_list ap;
1898
1899 va_start(ap, fmt);
1900 rval = vasprintf(&buf, fmt, ap);
1901 va_end(ap);
1902 if (rval == -1 || buf == NULL) {
1903 printf("421 Local resource failure: malloc\r\n");
1904 fflush(stdout);
1905 dologout(1);
1906 }
1907 next = buf;
1908 while ((p = strsep(&next, "\n\r"))) {
1909 printf("%d%s %s\r\n", n, (next != NULL) ? "-" : "", p);
1910 if (debug)
1911 syslog(LOG_DEBUG, "<--- %d%s %s", n,
1912 (next != NULL) ? "-" : "", p);
1913 }
1914 (void)fflush(stdout);
1915 free(buf);
1916}
1917
1918
1919void
1920reply_r(int n, const char *fmt, ...)
1921{
1922 char *p, *next;
1923 char msg[BUFSIZ];
1924 char buf[BUFSIZ];
1925 va_list ap;
1926 struct syslog_data sdata = SYSLOG_DATA_INIT;
1927
1928 sdata.log_fac = LOG_FTP;
1929 va_start(ap, fmt);
1930 vsnprintf(msg, sizeof(msg), fmt, ap);
1931 va_end(ap);
1932
1933 next = msg;
1934
1935 while ((p = strsep(&next, "\n\r"))) {
1936 snprintf(buf, sizeof(buf), "%d%s %s\r\n", n,
1937 (next != NULL) ? "-" : "", p);
1938 write(STDOUT_FILENO, buf, strlen(buf));
1939 if (debug) {
1940 buf[strlen(buf) - 2] = '\0';
1941 syslog_r(LOG_DEBUG, &sdata, "<--- %s", buf);
1942 }
1943 }
1944}
1945
1946void
1947lreply(int n, const char *fmt, ...)
1948{
1949 va_list ap;
1950
1951 va_start(ap, fmt);
1952 (void)printf("%d- ", n);
1953 (void)vprintf(fmt, ap);
1954 va_end(ap);
1955 (void)printf("\r\n");
1956 (void)fflush(stdout);
1957 if (debug) {
1958 va_start(ap, fmt);
1959 syslog(LOG_DEBUG, "<--- %d- ", n);
1960 vsyslog(LOG_DEBUG, fmt, ap);
1961 va_end(ap);
1962 }
1963}
1964
1965static void
1966ack(const char *s)
1967{
1968
1969 reply(250, "%s command successful.", s);
1970}
1971
1972void
1973nack(const char *s)
1974{
1975
1976 reply(502, "%s command not implemented.", s);
1977}
1978
1979void
1980yyerror(char *s)
1981{
1982 cbuf[strcspn(cbuf, "\n")] = '\0';
1983 reply(500, "'%s': command not understood.", cbuf);
1984}
1985
1986void
1987delete(const char *name)
1988{
1989 struct stat st;
1990
1991 LOGCMD("delete", name);
1992 if (stat(name, &st) == -1) {
1993 perror_reply(550, name);
1994 return;
1995 }
1996 if ((st.st_mode&S_IFMT) == S_IFDIR) {
1997 if (rmdir(name) == -1) {
1998 perror_reply(550, name);
1999 return;
2000 }
2001 goto done;
2002 }
2003 if (unlink(name) == -1) {
2004 perror_reply(550, name);
2005 return;
2006 }
2007done:
2008 ack("DELE");
2009}
2010
2011void
2012cwd(char *path)
2013{
2014 FILE *message;
2015
2016 if (chdir(path) == -1)
2017 perror_reply(550, path);
2018 else {
2019 if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
2020 char line[LINE_MAX];
2021
2022 while (fgets(line, sizeof(line), message) != NULL) {
2023 line[strcspn(line, "\n")] = '\0';
2024 lreply(250, "%s", line);
2025 }
2026 (void) fclose(message);
2027 }
2028 ack("CWD");
2029 }
2030}
2031
2032void
2033replydirname(const char *name, const char *message)
2034{
2035 char *p, *ep;
2036 char npath[PATH_MAX * 2];
2037
2038 p = npath;
2039 ep = &npath[sizeof(npath) - 1];
2040 while (*name) {
2041 if (*name == '"') {
2042 if (ep - p < 2)
2043 break;
2044 *p++ = *name++;
2045 *p++ = '"';
2046 } else {
2047 if (ep - p < 1)
2048 break;
2049 *p++ = *name++;
2050 }
2051 }
2052 *p = '\0';
2053 reply(257, "\"%s\" %s", npath, message);
2054}
2055
2056void
2057makedir(const char *name)
2058{
2059
2060 LOGCMD("mkdir", name);
2061 if (mkdir(name, 0777) == -1)
2062 perror_reply(550, name);
2063 else
2064 replydirname(name, "directory created.");
2065}
2066
2067void
2068removedir(const char *name)
2069{
2070
2071 LOGCMD("rmdir", name);
2072 if (rmdir(name) == -1)
2073 perror_reply(550, name);
2074 else
2075 ack("RMD");
2076}
2077
2078void
2079pwd(void)
2080{
2081 char path[PATH_MAX];
2082
2083 if (getcwd(path, sizeof(path)) == NULL)
2084 perror_reply(550, "Can't get current directory");
2085 else
2086 replydirname(path, "is current directory.");
2087}
2088
2089char *
2090renamefrom(char *name)
2091{
2092 struct stat st;
2093
2094 if (stat(name, &st) == -1) {
2095 perror_reply(550, name);
2096 return (NULL);
2097 }
2098 reply(350, "File exists, ready for destination name");
2099 return (name);
2100}
2101
2102void
2103renamecmd(const char *from, const char *to)
2104{
2105
2106 LOGCMD2("rename", from, to);
2107 if (rename(from, to) == -1)
2108 perror_reply(550, "rename");
2109 else
2110 ack("RNTO");
2111}
2112
2113static void
2114dolog(struct sockaddr *sa)
2115{
2116 char hbuf[sizeof(remotehost)];
2117
2118 if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0) == 0)
2119 (void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2120 else
2121 (void) strlcpy(remotehost, "unknown", sizeof(remotehost));
2122
2123 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2124 setproctitle("%s", proctitle);
2125
2126 if (logging) {
2127 int error;
2128 error = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf),
2129 NULL, 0, NI_NUMERICHOST);
2130 syslog(LOG_INFO, "connection from %s [%s]", remotehost,
2131 error ? gai_strerror(error) : hbuf);
2132 }
2133}
2134
2135/*
2136 * Record logout in wtmp file and exit with supplied status.
2137 * NOTE: because this is called from signal handlers it cannot
2138 * use stdio (or call other functions that use stdio).
2139 */
2140void
2141dologout(int status)
2142{
2143
2144 transflag = 0;
2145
2146 if (logged_in) {
2147 sigprocmask(SIG_BLOCK, &allsigs, NULL);
2148 if (!nowtmp)
2149 ftpdlogwtmp(ttyline, "", "");
2150 if (doutmp)
2151 ftpd_logout(utmp.ut_line);
2152 }
2153 /* beware of flushing buffers after a SIGPIPE */
2154 _exit(status);
2155}
2156
2157static void
2158sigurg(int signo)
2159{
2160
2161 recvurg = 1;
2162}
2163
2164static void
2165myoob(void)
2166{
2167 char *cp;
2168 int ret;
2169
2170 /* only process if transfer occurring */
2171 if (!transflag)
2172 return;
2173 cp = tmpline;
2174 ret = get_line(cp, sizeof(tmpline)-1);
2175 if (ret == -1) {
2176 reply(221, "You could at least say goodbye.");
2177 dologout(0);
2178 } else if (ret == -2) {
2179 /* Ignore truncated command */
2180 return;
2181 }
2182 upper(cp);
2183 if (strcmp(cp, "ABOR\r\n") == 0) {
2184 tmpline[0] = '\0';
2185 reply(426, "Transfer aborted. Data connection closed.");
2186 reply(226, "Abort successful");
2187 }
2188 if (strcmp(cp, "STAT\r\n") == 0) {
2189 tmpline[0] = '\0';
2190 if (file_size != -1)
2191 reply(213, "Status: %lld of %lld bytes transferred",
2192 (long long)byte_count, (long long)file_size);
2193 else
2194 reply(213, "Status: %lld bytes transferred",
2195 (long long)byte_count);
2196 }
2197}
2198
2199/*
2200 * Note: a response of 425 is not mentioned as a possible response to
2201 * the PASV command in RFC959. However, it has been blessed as
2202 * a legitimate response by Jon Postel in a telephone conversation
2203 * with Rick Adams on 25 Jan 89.
2204 */
2205void
2206passive(void)
2207{
2208 socklen_t len;
2209 int on = 1;
2210 u_char *p, *a;
2211
2212 if (pw == NULL) {
2213 reply(530, "Please login with USER and PASS");
2214 return;
2215 }
2216 if (pdata >= 0)
2217 close(pdata);
2218 /*
2219 * XXX
2220 * At this point, it would be nice to have an algorithm that
2221 * inserted a growing delay in an attack scenario. Such a thing
2222 * would look like continual passive sockets being opened, but
2223 * nothing serious being done with them. They're not used to
2224 * move data; the entire attempt is just to use tcp FIN_WAIT
2225 * resources.
2226 */
2227 pdata = socket(AF_INET, SOCK_STREAM, 0);
2228 if (pdata == -1) {
2229 perror_reply(425, "Can't open passive connection");
2230 return;
2231 }
2232
2233 if (setsockopt(pdata, SOL_SOCKET, SO_KEEPALIVE,
2234 &on, sizeof(on)) == -1)
2235 goto pasv_error;
2236
2237 on = IP_PORTRANGE_HIGH;
2238 if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2239 &on, sizeof(on)) == -1)
2240 goto pasv_error;
2241
2242 pasv_addr = ctrl_addr;
2243 pasv_addr.su_sin.sin_port = 0;
2244 if (bind(pdata, (struct sockaddr *)&pasv_addr,
2245 pasv_addr.su_len) == -1)
2246 goto pasv_error;
2247
2248 len = sizeof(pasv_addr);
2249 if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) == -1)
2250 goto pasv_error;
2251 if (listen(pdata, 1) == -1)
2252 goto pasv_error;
2253 a = (u_char *)&pasv_addr.su_sin.sin_addr;
2254 p = (u_char *)&pasv_addr.su_sin.sin_port;
2255
2256 reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2257 a[1], a[2], a[3], p[0], p[1]);
2258 return;
2259
2260pasv_error:
2261 perror_reply(425, "Can't open passive connection");
2262 (void) close(pdata);
2263 pdata = -1;
2264 return;
2265}
2266
2267int
2268epsvproto2af(int proto)
2269{
2270
2271 switch (proto) {
2272 case 1: return AF_INET;
2273 case 2: return AF_INET6;
2274 default: return -1;
2275 }
2276}
2277
2278int
2279af2epsvproto(int af)
2280{
2281
2282 switch (af) {
2283 case AF_INET: return 1;
2284 case AF_INET6: return 2;
2285 default: return -1;
2286 }
2287}
2288
2289/*
2290 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2291 * 229 Entering Extended Passive Mode (|||port|)
2292 */
2293void
2294long_passive(const char *cmd, int pf)
2295{
2296 socklen_t len;
2297 int on = 1;
2298 u_char *p, *a;
2299
2300 if (!logged_in) {
2301 syslog(LOG_NOTICE, "long passive but not logged in");
2302 reply(503, "Login with USER first.");
2303 return;
2304 }
2305
2306 if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2307 /*
2308 * XXX
2309 * only EPRT/EPSV ready clients will understand this
2310 */
2311 if (strcmp(cmd, "EPSV") != 0)
2312 reply(501, "Network protocol mismatch"); /*XXX*/
2313 else
2314 epsv_protounsupp("Network protocol mismatch");
2315
2316 return;
2317 }
2318
2319 if (pdata >= 0)
2320 close(pdata);
2321 /*
2322 * XXX
2323 * At this point, it would be nice to have an algorithm that
2324 * inserted a growing delay in an attack scenario. Such a thing
2325 * would look like continual passive sockets being opened, but
2326 * nothing serious being done with them. They not used to move
2327 * data; the entire attempt is just to use tcp FIN_WAIT
2328 * resources.
2329 */
2330 pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2331 if (pdata == -1) {
2332 perror_reply(425, "Can't open passive connection");
2333 return;
2334 }
2335
2336 if (setsockopt(pdata, SOL_SOCKET, SO_KEEPALIVE,
2337 &on, sizeof(on)) == -1)
2338 goto pasv_error;
2339
2340 switch (ctrl_addr.su_family) {
2341 case AF_INET:
2342 on = IP_PORTRANGE_HIGH;
2343 if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2344 &on, sizeof(on)) == -1)
2345 goto pasv_error;
2346 break;
2347 case AF_INET6:
2348 on = IPV6_PORTRANGE_HIGH;
2349 if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2350 &on, sizeof(on)) == -1)
2351 goto pasv_error;
2352 break;
2353 }
2354
2355 pasv_addr = ctrl_addr;
2356 pasv_addr.su_port = 0;
2357 if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) == -1)
2358 goto pasv_error;
2359 len = pasv_addr.su_len;
2360 if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) == -1)
2361 goto pasv_error;
2362 if (listen(pdata, 1) == -1)
2363 goto pasv_error;
2364 p = (u_char *)&pasv_addr.su_port;
2365
2366 if (strcmp(cmd, "LPSV") == 0) {
2367 switch (pasv_addr.su_family) {
2368 case AF_INET:
2369 a = (u_char *)&pasv_addr.su_sin.sin_addr;
2370 reply(228,
2371 "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2372 4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2373 return;
2374 case AF_INET6:
2375 a = (u_char *)&pasv_addr.su_sin6.sin6_addr;
2376 reply(228,
2377 "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2378 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2379 6, 16, a[0], a[1], a[2], a[3], a[4],
2380 a[5], a[6], a[7], a[8], a[9], a[10],
2381 a[11], a[12], a[13], a[14], a[15],
2382 2, p[0], p[1]);
2383 return;
2384 }
2385 } else if (strcmp(cmd, "EPSV") == 0) {
2386 switch (pasv_addr.su_family) {
2387 case AF_INET:
2388 case AF_INET6:
2389 reply(229, "Entering Extended Passive Mode (|||%u|)",
2390 ntohs(pasv_addr.su_port));
2391 return;
2392 }
2393 } else {
2394 /* more proper error code? */
2395 }
2396
2397 pasv_error:
2398 perror_reply(425, "Can't open passive connection");
2399 (void) close(pdata);
2400 pdata = -1;
2401 return;
2402}
2403
2404/*
2405 * EPRT |proto|addr|port|
2406 */
2407int
2408extended_port(const char *arg)
2409{
2410 char *tmp = NULL;
2411 char *result[3];
2412 char *p, *q;
2413 char delim;
2414 struct addrinfo hints;
2415 struct addrinfo *res = NULL;
2416 int i;
2417 unsigned long proto;
2418
2419 if (epsvall) {
2420 reply(501, "EPRT disallowed after EPSV ALL");
2421 return -1;
2422 }
2423
2424 usedefault = 0;
2425 if (pdata >= 0) {
2426 (void) close(pdata);
2427 pdata = -1;
2428 }
2429
2430 tmp = strdup(arg);
2431 if (!tmp) {
2432 fatal("not enough core.");
2433 /*NOTREACHED*/
2434 }
2435 p = tmp;
2436 delim = p[0];
2437 p++;
2438 memset(result, 0, sizeof(result));
2439 for (i = 0; i < 3; i++) {
2440 q = strchr(p, delim);
2441 if (!q || *q != delim)
2442 goto parsefail;
2443 *q++ = '\0';
2444 result[i] = p;
2445 p = q;
2446 }
2447
2448 /* some more sanity check */
2449 p = NULL;
2450 (void)strtoul(result[2], &p, 10);
2451 if (!*result[2] || *p)
2452 goto protounsupp;
2453 p = NULL;
2454 proto = strtoul(result[0], &p, 10);
2455 if (!*result[0] || *p)
2456 goto protounsupp;
2457
2458 memset(&hints, 0, sizeof(hints));
2459 hints.ai_family = epsvproto2af((int)proto);
2460 if (hints.ai_family < 0)
2461 goto protounsupp;
2462 hints.ai_socktype = SOCK_STREAM;
2463 hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
2464 if (getaddrinfo(result[1], result[2], &hints, &res))
2465 goto parsefail;
2466 if (res->ai_next)
2467 goto parsefail;
2468 if (sizeof(data_dest) < res->ai_addrlen)
2469 goto parsefail;
2470 memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2471 if (his_addr.su_family == AF_INET6 &&
2472 data_dest.su_family == AF_INET6) {
2473 /* XXX more sanity checks! */
2474 data_dest.su_sin6.sin6_scope_id =
2475 his_addr.su_sin6.sin6_scope_id;
2476 }
2477 if (pdata >= 0) {
2478 (void) close(pdata);
2479 pdata = -1;
2480 }
2481 reply(200, "EPRT command successful.");
2482
2483 free(tmp);
2484 if (res)
2485 freeaddrinfo(res);
2486 return 0;
2487
2488parsefail:
2489 reply(500, "Invalid argument, rejected.");
2490 usedefault = 1;
2491 free(tmp);
2492 if (res)
2493 freeaddrinfo(res);
2494 return -1;
2495
2496protounsupp:
2497 epsv_protounsupp("Protocol not supported");
2498 usedefault = 1;
2499 free(tmp);
2500 if (res)
2501 freeaddrinfo(res);
2502 return -1;
2503}
2504
2505/*
2506 * 522 Protocol not supported (proto,...)
2507 * as we assume address family for control and data connections are the same,
2508 * we do not return the list of address families we support - instead, we
2509 * return the address family of the control connection.
2510 */
2511void
2512epsv_protounsupp(const char *message)
2513{
2514 int proto;
2515
2516 proto = af2epsvproto(ctrl_addr.su_family);
2517 if (proto < 0)
2518 reply(501, "%s", message); /*XXX*/
2519 else
2520 reply(522, "%s, use (%d)", message, proto);
2521}
2522
2523/*
2524 * Generate unique name for file with basename "local".
2525 * The file named "local" is already known to exist.
2526 * Generates failure reply on error.
2527 */
2528static int
2529guniquefd(const char *local, char **nam)
2530{
2531 static char new[PATH_MAX];
2532 struct stat st;
2533 size_t len;
2534 int count, fd;
2535 char *cp;
2536
2537 cp = strrchr(local, '/');
2538 if (cp)
2539 *cp = '\0';
2540 if (stat(cp ? local : ".", &st) == -1) {
2541 perror_reply(553, cp ? local : ".");
2542 return (-1);
2543 }
2544 if (cp)
2545 *cp = '/';
2546 len = strlcpy(new, local, sizeof(new));
2547 if (len+2+1 >= sizeof(new)-1)
2548 return (-1);
2549 cp = new + len;
2550 *cp++ = '.';
2551 for (count = 1; count < 100; count++) {
2552 (void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2553 fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2554 if (fd == -1)
2555 continue;
2556 if (nam)
2557 *nam = new;
2558 return (fd);
2559 }
2560 reply(452, "Unique file name cannot be created.");
2561 return (-1);
2562}
2563
2564/*
2565 * Format and send reply containing system error number.
2566 */
2567void
2568perror_reply(int code, const char *string)
2569{
2570
2571 reply(code, "%s: %s.", string, strerror(errno));
2572}
2573
2574static char *onefile[] = {
2575 "",
2576 0
2577};
2578
2579void
2580send_file_list(char *whichf)
2581{
2582 struct stat st;
2583 DIR *dirp = NULL;
2584 struct dirent *dir;
2585 FILE *dout = NULL;
2586 char **dirlist;
2587 char *dirname;
2588 int simple = 0;
2589 volatile int freeglob = 0;
2590 glob_t gl;
2591 size_t prefixlen;
2592
2593 if (strpbrk(whichf, "~{[*?") != NULL) {
2594 memset(&gl, 0, sizeof(gl));
2595 freeglob = 1;
2596 if (glob(whichf,
2597 GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2598 0, &gl)) {
2599 reply(550, "not found");
2600 goto out;
2601 } else if (gl.gl_pathc == 0) {
2602 errno = ENOENT;
2603 perror_reply(550, whichf);
2604 goto out;
2605 }
2606 dirlist = gl.gl_pathv;
2607 } else {
2608 onefile[0] = whichf;
2609 dirlist = onefile;
2610 simple = 1;
2611 }
2612
2613 while ((dirname = *dirlist++)) {
2614 if (stat(dirname, &st) == -1) {
2615 /*
2616 * If user typed "ls -l", etc, and the client
2617 * used NLST, do what the user meant.
2618 */
2619 if (dirname[0] == '-' && *dirlist == NULL &&
2620 transflag == 0) {
2621 retrieve(RET_FILE, dirname);
2622 goto out;
2623 }
2624 perror_reply(550, whichf);
2625 if (dout != NULL) {
2626 (void) fclose(dout);
2627 transflag = 0;
2628 data = -1;
2629 pdata = -1;
2630 }
2631 goto out;
2632 }
2633
2634 if (S_ISREG(st.st_mode)) {
2635 if (dout == NULL) {
2636 dout = dataconn("file list", -1, "w");
2637 if (dout == NULL)
2638 goto out;
2639 transflag++;
2640 }
2641 fprintf(dout, "%s%s\n", dirname,
2642 type == TYPE_A ? "\r" : "");
2643 byte_count += strlen(dirname) + 1;
2644 continue;
2645 } else if (!S_ISDIR(st.st_mode))
2646 continue;
2647
2648 if ((dirp = opendir(dirname)) == NULL)
2649 continue;
2650
2651 if (dirname[0] == '.' && dirname[1] == '\0')
2652 prefixlen = 0;
2653 else
2654 prefixlen = strlen(dirname) + 1;
2655 while ((dir = readdir(dirp)) != NULL) {
2656 if (recvurg) {
2657 myoob();
2658 recvurg = 0;
2659 transflag = 0;
2660 goto out;
2661 }
2662
2663 if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2664 continue;
2665 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2666 dir->d_namlen == 2)
2667 continue;
2668
2669 /*
2670 * We have to do a stat to insure it's
2671 * not a directory or special file.
2672 */
2673 if (simple ||
2674 (fstatat(dirfd(dirp), dir->d_name, &st, 0) == 0 &&
2675 S_ISREG(st.st_mode))) {
2676 if (dout == NULL) {
2677 dout = dataconn("file list", -1, "w");
2678 if (dout == NULL)
2679 goto out;
2680 transflag++;
2681 }
2682
2683 if (prefixlen) {
2684 fprintf(dout, "%s/", dirname);
2685 byte_count += prefixlen;
2686 }
2687 fprintf(dout, "%s%s\n", dir->d_name,
2688 type == TYPE_A ? "\r" : "");
2689 byte_count += dir->d_namlen + 1;
2690 }
2691 }
2692 (void) closedir(dirp);
2693 }
2694
2695 if (dout == NULL)
2696 reply(550, "No files found.");
2697 else if (ferror(dout) != 0)
2698 perror_reply(550, "Data connection");
2699 else
2700 reply(226, "Transfer complete.");
2701
2702 transflag = 0;
2703 if (dout != NULL)
2704 (void) fclose(dout);
2705 else {
2706 if (pdata >= 0)
2707 close(pdata);
2708 }
2709 data = -1;
2710 pdata = -1;
2711out:
2712 if (freeglob) {
2713 freeglob = 0;
2714 globfree(&gl);
2715 }
2716}
2717
2718static void
2719reapchild(int signo)
2720{
2721 int save_errno = errno;
2722 int rval;
2723
2724 do {
2725 rval = waitpid(-1, NULL, WNOHANG);
2726 } while (rval > 0 || (rval == -1 && errno == EINTR));
2727 errno = save_errno;
2728}
2729
2730void
2731logxfer(const char *name, off_t size, time_t start)
2732{
2733 char buf[400 + (HOST_NAME_MAX+1)*4 + PATH_MAX*4];
2734 char dir[PATH_MAX], path[PATH_MAX], rpath[PATH_MAX];
2735 char vremotehost[(HOST_NAME_MAX+1)*4], vpath[PATH_MAX*4];
2736 char *vpw;
2737 time_t now;
2738 int len;
2739
2740 if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2741 char *cnow;
2742
2743 time(&now);
2744 cnow = ctime(&now);
2745
2746 vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2747 if (vpw == NULL)
2748 return;
2749
2750 snprintf(path, sizeof(path), "%s/%s", dir, name);
2751 if (realpath(path, rpath) == NULL)
2752 strlcpy(rpath, path, sizeof(rpath));
2753 strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2754
2755 strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2756 strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2757
2758 len = snprintf(buf, sizeof(buf),
2759 "%.24s %lld %s %lld %s %c %s %c %c %s ftp %d %s %s\n",
2760 cnow ? cnow : "?",
2761 (long long)(now - start + (now == start)),
2762 vremotehost, (long long)size, vpath,
2763 ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2764 'o', ((guest) ? 'a' : 'r'),
2765 vpw, 0 /* none yet */,
2766 ((guest) ? "*" : pw->pw_name), dhostname);
2767 free(vpw);
2768
2769 if (len < 0 || len >= sizeof(buf)) {
2770 if ((len = strlen(buf)) == 0)
2771 return; /* should not happen */
2772 buf[len - 1] = '\n';
2773 }
2774 write(statfd, buf, len);
2775 }
2776}
2777
2778void
2779set_slave_signals(void)
2780{
2781 struct sigaction sa;
2782
2783 sigemptyset(&sa.sa_mask);
2784 sa.sa_flags = SA_RESTART;
2785
2786 sa.sa_handler = SIG_DFL;
2787 (void) sigaction(SIGCHLD, &sa, NULL);
2788
2789 sa.sa_handler = sigurg;
2790 sa.sa_flags = 0; /* don't restart syscalls for SIGURG */
2791 (void) sigaction(SIGURG, &sa, NULL);
2792
2793 sigfillset(&sa.sa_mask); /* block all signals in handler */
2794 sa.sa_flags = SA_RESTART;
2795 sa.sa_handler = sigquit;
2796 (void) sigaction(SIGHUP, &sa, NULL);
2797 (void) sigaction(SIGINT, &sa, NULL);
2798 (void) sigaction(SIGQUIT, &sa, NULL);
2799 (void) sigaction(SIGTERM, &sa, NULL);
2800
2801 sa.sa_handler = lostconn;
2802 (void) sigaction(SIGPIPE, &sa, NULL);
2803
2804 sa.sa_handler = toolong;
2805 (void) sigaction(SIGALRM, &sa, NULL);
2806
2807 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
2808 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
2809}
2810
2811/*
2812 * Allocate space and return a copy of the specified dir.
2813 * If 'dir' begins with a tilde (~), expand it.
2814 */
2815char *
2816copy_dir(char *dir, struct passwd *pw)
2817{
2818 char *cp;
2819 char *newdir;
2820 char *user = NULL;
2821
2822 /* Nothing to expand */
2823 if (dir[0] != '~')
2824 return (strdup(dir));
2825
2826 /* "dir" is of form ~user/some/dir, lookup user. */
2827 if (dir[1] != '/' && dir[1] != '\0') {
2828 if ((cp = strchr(dir + 1, '/')) == NULL)
2829 cp = dir + strlen(dir);
2830 if ((user = malloc((size_t)(cp - dir))) == NULL)
2831 return (NULL);
2832 strlcpy(user, dir + 1, (size_t)(cp - dir));
2833
2834 /* Only do lookup if it is a different user. */
2835 if (strcmp(user, pw->pw_name) != 0) {
2836 if ((pw = getpwnam(user)) == NULL) {
2837 /* No such user, interpret literally */
2838 free(user);
2839 return(strdup(dir));
2840 }
2841 }
2842 free(user);
2843 }
2844
2845 /*
2846 * If there is no directory separator (/) then it is just pw_dir.
2847 * Otherwise, replace ~foo with pw_dir.
2848 */
2849 if ((cp = strchr(dir + 1, '/')) == NULL) {
2850 newdir = strdup(pw->pw_dir);
2851 } else {
2852 if (asprintf(&newdir, "%s%s", pw->pw_dir, cp) == -1)
2853 return (NULL);
2854 }
2855
2856 return(newdir);
2857}