1 /* $NetBSD: ftpd.c,v 1.208 2023/09/30 18:06:24 shm Exp $ */
2
3 /*
4 * Copyright (c) 1997-2023 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61 /*
62 * Copyright (C) 1997 and 1998 WIDE Project.
63 * All rights reserved.
64 *
65 * Redistribution and use in source and binary forms, with or without
66 * modification, are permitted provided that the following conditions
67 * are met:
68 * 1. Redistributions of source code must retain the above copyright
69 * notice, this list of conditions and the following disclaimer.
70 * 2. Redistributions in binary form must reproduce the above copyright
71 * notice, this list of conditions and the following disclaimer in the
72 * documentation and/or other materials provided with the distribution.
73 * 3. Neither the name of the project nor the names of its contributors
74 * may be used to endorse or promote products derived from this software
75 * without specific prior written permission.
76 *
77 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
78 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
79 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
80 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
81 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
83 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
84 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
85 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
86 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87 * SUCH DAMAGE.
88 */
89
90 #include <sys/cdefs.h>
91 #ifndef lint
92 __COPYRIGHT("@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\
93 The Regents of the University of California. All rights reserved.");
94 #endif /* not lint */
95
96 #ifndef lint
97 #if 0
98 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
99 #else
100 __RCSID("$NetBSD: ftpd.c,v 1.208 2023/09/30 18:06:24 shm Exp $");
101 #endif
102 #endif /* not lint */
103
104 /*
105 * FTP server.
106 */
107 #include <sys/param.h>
108 #include <sys/stat.h>
109 #include <sys/ioctl.h>
110 #include <sys/socket.h>
111 #include <sys/wait.h>
112 #include <sys/mman.h>
113 #include <sys/resource.h>
114
115 #include <netinet/in.h>
116 #include <netinet/in_systm.h>
117 #include <netinet/ip.h>
118
119 #define FTP_NAMES
120 #include <arpa/ftp.h>
121 #include <arpa/inet.h>
122 #include <arpa/telnet.h>
123
124 #include <ctype.h>
125 #include <dirent.h>
126 #include <err.h>
127 #include <errno.h>
128 #include <fcntl.h>
129 #include <fnmatch.h>
130 #include <glob.h>
131 #include <grp.h>
132 #include <limits.h>
133 #include <netdb.h>
134 #include <pwd.h>
135 #include <poll.h>
136 #include <signal.h>
137 #include <stdarg.h>
138 #include <stdio.h>
139 #include <stdlib.h>
140 #include <string.h>
141 #include <syslog.h>
142 #include <time.h>
143 #include <tzfile.h>
144 #include <unistd.h>
145 #include <util.h>
146 #ifdef SUPPORT_UTMP
147 #include <utmp.h>
148 #endif
149 #ifdef SUPPORT_UTMPX
150 #include <utmpx.h>
151 #endif
152 #ifdef SKEY
153 #include <skey.h>
154 #endif
155 #ifdef KERBEROS5
156 #include <com_err.h>
157 #include <krb5/krb5.h>
158 #endif
159
160 #ifdef LOGIN_CAP
161 #include <login_cap.h>
162 #endif
163
164 #ifdef USE_PAM
165 #include <security/pam_appl.h>
166 #endif
167
168 #include "pfilter.h"
169
170 #define GLOBAL
171 #include "extern.h"
172 #include "pathnames.h"
173 #include "version.h"
174
175 static sig_atomic_t transflag;
176 static sig_atomic_t urgflag;
177
178 int data;
179 int Dflag;
180 int fflag;
181 int sflag;
182 int stru; /* avoid C keyword */
183 int mode;
184 int dataport; /* use specific data port */
185 int dopidfile; /* maintain pid file */
186 int doutmp; /* update utmp file */
187 int dowtmp; /* update wtmp file */
188 int doxferlog; /* syslog/write wu-ftpd style xferlog entries */
189 int xferlogfd; /* fd to write wu-ftpd xferlog entries to */
190 int getnameopts; /* flags for use with getname() */
191 int dropprivs; /* if privileges should or have been dropped */
192 int mapped; /* IPv4 connection on AF_INET6 socket */
193 off_t file_size;
194 off_t byte_count;
195 static char ttyline[20];
196
197 #ifdef USE_PAM
198 static int auth_pam(void);
199 pam_handle_t *pamh = NULL;
200 #endif
201
202 #ifdef SUPPORT_UTMP
203 static struct utmp utmp; /* for utmp */
204 #endif
205 #ifdef SUPPORT_UTMPX
206 static struct utmpx utmpx; /* for utmpx */
207 #endif
208
209 static const char *anondir = NULL;
210 static const char *confdir = _DEFAULT_CONFDIR;
211
212 static char *curname; /* current USER name */
213 static size_t curname_len; /* length of curname (include NUL) */
214
215 #if defined(KERBEROS) || defined(KERBEROS5)
216 int has_ccache = 0;
217 int notickets = 1;
218 char *krbtkfile_env = NULL;
219 char *tty = ttyline;
220 int login_krb5_forwardable_tgt = 0;
221 #endif
222
223 int epsvall = 0;
224
225 /*
226 * Timeout intervals for retrying connections
227 * to hosts that don't accept PORT cmds. This
228 * is a kludge, but given the problems with TCP...
229 */
230 #define SWAITMAX 90 /* wait at most 90 seconds */
231 #define SWAITINT 5 /* interval between retries */
232
233 int swaitmax = SWAITMAX;
234 int swaitint = SWAITINT;
235
236 enum send_status {
237 SS_SUCCESS,
238 SS_ABORTED, /* transfer aborted */
239 SS_NO_TRANSFER, /* no transfer made yet */
240 SS_FILE_ERROR, /* file read error */
241 SS_DATA_ERROR /* data send error */
242 };
243
244 static int bind_pasv_addr(void);
245 static int checkuser(const char *, const char *, int, int, char **);
246 static int checkaccess(const char *);
247 static int checkpassword(const struct passwd *, const char *);
248 static void do_pass(int, int, const char *);
249 static void end_login(void);
250 static FILE *getdatasock(const char *);
251 static char *gunique(const char *);
252 static void login_utmp(const char *, const char *, const char *,
253 struct sockinet *);
254 static void logremotehost(struct sockinet *);
255 __dead static void lostconn(int);
256 __dead static void toolong(int);
257 __dead static void sigquit(int);
258 static void sigurg(int);
259 static int handleoobcmd(void);
260 static int receive_data(FILE *, FILE *);
261 static int send_data(FILE *, FILE *, const struct stat *, int);
262 static struct passwd *sgetpwnam(const char *);
263 static int write_data(int, char *, size_t, off_t *, struct timeval *,
264 int);
265 static enum send_status
266 send_data_with_read(int, int, const struct stat *, int);
267 static enum send_status
268 send_data_with_mmap(int, int, const struct stat *, int);
269 static void logrusage(const struct rusage *, const struct rusage *);
270 static void logout_utmp(void);
271
272 int main(int, char *[]);
273
274 #if defined(KERBEROS)
275 int klogin(struct passwd *, char *, char *, char *);
276 void kdestroy(void);
277 #endif
278 #if defined(KERBEROS5)
279 int k5login(struct passwd *, char *, char *, char *);
280 void k5destroy(void);
281 #endif
282
283 int
main(int argc,char * argv[])284 main(int argc, char *argv[])
285 {
286 int ch, on = 1, tos, keepalive;
287 socklen_t addrlen;
288 #ifdef KERBEROS5
289 krb5_error_code kerror;
290 #endif
291 char *p;
292 const char *xferlogname = NULL;
293 long l;
294 struct sigaction sa;
295 sa_family_t af = AF_UNSPEC;
296
297 connections = 1;
298 ftpd_debug = 0;
299 logging = 0;
300 pdata = -1;
301 Dflag = 0;
302 fflag = 0;
303 sflag = 0;
304 dataport = 0;
305 dopidfile = 1; /* default: DO use a pid file to count users */
306 doutmp = 0; /* default: Do NOT log to utmp */
307 dowtmp = 1; /* default: DO log to wtmp */
308 doxferlog = 0; /* default: Do NOT syslog xferlog */
309 xferlogfd = -1; /* default: Do NOT write xferlog file */
310 getnameopts = 0; /* default: xlate addrs to name */
311 dropprivs = 0;
312 mapped = 0;
313 usedefault = 1;
314 emailaddr = NULL;
315 hostname[0] = '\0';
316 homedir[0] = '\0';
317 gidcount = 0;
318 is_oob = 0;
319 version = FTPD_VERSION;
320
321 /*
322 * LOG_NDELAY sets up the logging connection immediately,
323 * necessary for anonymous ftp's that chroot and can't do it later.
324 */
325 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
326
327 while ((ch = getopt(argc, argv,
328 "46a:c:C:Dde:fh:HlL:nP:qQrst:T:uUvV:wWX")) != -1) {
329 switch (ch) {
330 case '4':
331 af = AF_INET;
332 break;
333
334 case '6':
335 af = AF_INET6;
336 break;
337
338 case 'a':
339 anondir = optarg;
340 break;
341
342 case 'c':
343 confdir = optarg;
344 break;
345
346 case 'C':
347 if ((p = strchr(optarg, '@')) != NULL) {
348 *p++ = '\0';
349 strlcpy(remotehost, p, MAXHOSTNAMELEN + 1);
350 if (inet_pton(AF_INET, p,
351 &his_addr.su_addr) == 1) {
352 his_addr.su_family = AF_INET;
353 his_addr.su_len =
354 sizeof(his_addr.si_su.su_sin);
355 #ifdef INET6
356 } else if (inet_pton(AF_INET6, p,
357 &his_addr.su_6addr) == 1) {
358 his_addr.su_family = AF_INET6;
359 his_addr.su_len =
360 sizeof(his_addr.si_su.su_sin6);
361 #endif
362 } else
363 his_addr.su_family = AF_UNSPEC;
364 }
365 pw = sgetpwnam(optarg);
366 exit(checkaccess(optarg) ? 0 : 1);
367 /* NOTREACHED */
368
369 case 'D':
370 Dflag = 1;
371 break;
372
373 case 'd':
374 case 'v': /* deprecated */
375 ftpd_debug = 1;
376 break;
377
378 case 'e':
379 emailaddr = optarg;
380 break;
381
382 case 'f':
383 fflag = 1;
384 break;
385
386 case 'h':
387 strlcpy(hostname, optarg, sizeof(hostname));
388 break;
389
390 case 'H':
391 if (gethostname(hostname, sizeof(hostname)) == -1)
392 hostname[0] = '\0';
393 hostname[sizeof(hostname) - 1] = '\0';
394 break;
395
396 case 'l':
397 logging++; /* > 1 == extra logging */
398 break;
399
400 case 'L':
401 xferlogname = optarg;
402 break;
403
404 case 'n':
405 getnameopts = NI_NUMERICHOST;
406 break;
407
408 case 'P':
409 errno = 0;
410 p = NULL;
411 l = strtol(optarg, &p, 10);
412 if (errno || *optarg == '\0' || *p != '\0' ||
413 l < IPPORT_RESERVED ||
414 l > IPPORT_ANONMAX) {
415 syslog(LOG_WARNING, "Invalid dataport %s",
416 optarg);
417 dataport = 0;
418 }
419 dataport = (int)l;
420 break;
421
422 case 'q':
423 dopidfile = 1;
424 break;
425
426 case 'Q':
427 dopidfile = 0;
428 break;
429
430 case 'r':
431 dropprivs = 1;
432 break;
433
434 case 's':
435 sflag = 1;
436 break;
437
438 case 't':
439 case 'T':
440 syslog(LOG_WARNING,
441 "-%c has been deprecated in favour of ftpd.conf",
442 ch);
443 break;
444
445 case 'u':
446 doutmp = 1;
447 break;
448
449 case 'U':
450 doutmp = 0;
451 break;
452
453 case 'V':
454 if (EMPTYSTR(optarg) || strcmp(optarg, "-") == 0)
455 version = NULL;
456 else
457 version = ftpd_strdup(optarg);
458 break;
459
460 case 'w':
461 dowtmp = 1;
462 break;
463
464 case 'W':
465 dowtmp = 0;
466 break;
467
468 case 'X':
469 doxferlog |= 1;
470 break;
471
472 default:
473 if (optopt == 'a' || optopt == 'C')
474 exit(1);
475 syslog(LOG_WARNING, "unknown flag -%c ignored", optopt);
476 break;
477 }
478 }
479 if (EMPTYSTR(confdir))
480 confdir = _DEFAULT_CONFDIR;
481
482 pfilter_open();
483
484 if (dowtmp) {
485 #ifdef SUPPORT_UTMPX
486 ftpd_initwtmpx();
487 #endif
488 #ifdef SUPPORT_UTMP
489 ftpd_initwtmp();
490 #endif
491 }
492 errno = 0;
493 l = sysconf(_SC_LOGIN_NAME_MAX);
494 if (l == -1 && errno != 0) {
495 syslog(LOG_ERR, "sysconf _SC_LOGIN_NAME_MAX: %m");
496 exit(1);
497 } else if (l <= 0) {
498 syslog(LOG_WARNING, "using conservative LOGIN_NAME_MAX value");
499 curname_len = _POSIX_LOGIN_NAME_MAX;
500 } else
501 curname_len = (size_t)l;
502 curname = malloc(curname_len);
503 if (curname == NULL) {
504 syslog(LOG_ERR, "malloc: %m");
505 exit(1);
506 }
507 curname[0] = '\0';
508
509 if (Dflag) {
510 int error, fd, i, n, *socks;
511 struct pollfd *fds;
512 struct addrinfo hints, *res, *res0;
513
514 if (!fflag && daemon(1, 0) == -1) {
515 syslog(LOG_ERR, "failed to daemonize: %m");
516 exit(1);
517 }
518 (void)memset(&sa, 0, sizeof(sa));
519 sa.sa_handler = SIG_IGN;
520 sa.sa_flags = SA_NOCLDWAIT;
521 sigemptyset(&sa.sa_mask);
522 (void)sigaction(SIGCHLD, &sa, NULL);
523
524 (void)memset(&hints, 0, sizeof(hints));
525 hints.ai_flags = AI_PASSIVE;
526 hints.ai_family = af;
527 hints.ai_socktype = SOCK_STREAM;
528 error = getaddrinfo(NULL, "ftp", &hints, &res0);
529 if (error) {
530 syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error));
531 exit(1);
532 }
533
534 for (n = 0, res = res0; res != NULL; res = res->ai_next)
535 n++;
536 if (n == 0) {
537 syslog(LOG_ERR, "no addresses available");
538 exit(1);
539 }
540 socks = malloc(n * sizeof(int));
541 fds = malloc(n * sizeof(struct pollfd));
542 if (socks == NULL || fds == NULL) {
543 syslog(LOG_ERR, "malloc: %m");
544 exit(1);
545 }
546
547 for (n = 0, res = res0; res != NULL; res = res->ai_next) {
548 socks[n] = socket(res->ai_family, res->ai_socktype,
549 res->ai_protocol);
550 if (socks[n] == -1)
551 continue;
552 (void)setsockopt(socks[n], SOL_SOCKET, SO_REUSEADDR,
553 &on, sizeof(on));
554 if (bind(socks[n], res->ai_addr, res->ai_addrlen)
555 == -1) {
556 (void)close(socks[n]);
557 continue;
558 }
559 if (listen(socks[n], 12) == -1) {
560 (void)close(socks[n]);
561 continue;
562 }
563
564 fds[n].fd = socks[n];
565 fds[n].events = POLLIN;
566 n++;
567 }
568 if (n == 0) {
569 syslog(LOG_ERR, "%m");
570 exit(1);
571 }
572 freeaddrinfo(res0);
573
574 if (pidfile(NULL) == -1)
575 syslog(LOG_ERR, "failed to write a pid file: %m");
576
577 for (;;) {
578 if (poll(fds, n, INFTIM) == -1) {
579 if (errno == EINTR)
580 continue;
581 syslog(LOG_ERR, "poll: %m");
582 exit(1);
583 }
584 for (i = 0; i < n; i++) {
585 if (fds[i].revents & POLLIN) {
586 fd = accept(fds[i].fd, NULL, NULL);
587 if (fd == -1) {
588 syslog(LOG_ERR, "accept: %m");
589 continue;
590 }
591 switch (fork()) {
592 case -1:
593 syslog(LOG_ERR, "fork: %m");
594 break;
595 case 0:
596 goto child;
597 /* NOTREACHED */
598 }
599 (void)close(fd);
600 }
601 }
602 }
603 child:
604 (void)dup2(fd, STDIN_FILENO);
605 (void)dup2(fd, STDOUT_FILENO);
606 (void)dup2(fd, STDERR_FILENO);
607 for (i = 0; i < n; i++)
608 (void)close(socks[i]);
609 }
610
611 memset((char *)&his_addr, 0, sizeof(his_addr));
612 addrlen = sizeof(his_addr.si_su);
613 if (getpeername(0, (struct sockaddr *)&his_addr.si_su, &addrlen) < 0) {
614 syslog((errno == ENOTCONN) ? LOG_NOTICE : LOG_ERR,
615 "getpeername (%s): %m",argv[0]);
616 exit(1);
617 }
618 his_addr.su_len = addrlen;
619 memset((char *)&ctrl_addr, 0, sizeof(ctrl_addr));
620 addrlen = sizeof(ctrl_addr.si_su);
621 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
622 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
623 exit(1);
624 }
625 ctrl_addr.su_len = addrlen;
626 #ifdef INET6
627 if (his_addr.su_family == AF_INET6
628 && IN6_IS_ADDR_V4MAPPED(&his_addr.su_6addr)) {
629 #if 1
630 /*
631 * IPv4 control connection arrived to AF_INET6 socket.
632 * I hate to do this, but this is the easiest solution.
633 *
634 * The assumption is untrue on SIIT environment.
635 */
636 struct sockinet tmp_addr;
637 const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
638
639 tmp_addr = his_addr;
640 memset(&his_addr, 0, sizeof(his_addr));
641 his_addr.su_family = AF_INET;
642 his_addr.su_len = sizeof(his_addr.si_su.su_sin);
643 memcpy(&his_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
644 sizeof(his_addr.su_addr));
645 his_addr.su_port = tmp_addr.su_port;
646
647 tmp_addr = ctrl_addr;
648 memset(&ctrl_addr, 0, sizeof(ctrl_addr));
649 ctrl_addr.su_family = AF_INET;
650 ctrl_addr.su_len = sizeof(ctrl_addr.si_su.su_sin);
651 memcpy(&ctrl_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
652 sizeof(ctrl_addr.su_addr));
653 ctrl_addr.su_port = tmp_addr.su_port;
654 #else
655 while (fgets(line, sizeof(line), fd) != NULL) {
656 if ((cp = strchr(line, '\n')) != NULL)
657 *cp = '\0';
658 reply(-530, "%s", line);
659 }
660 (void) fflush(stdout);
661 (void) fclose(fd);
662 reply(530,
663 "Connection from IPv4 mapped address is not supported.");
664 exit(0);
665 #endif
666
667 mapped = 1;
668 } else
669 #endif /* INET6 */
670 mapped = 0;
671 #ifdef IP_TOS
672 if (!mapped && his_addr.su_family == AF_INET) {
673 tos = IPTOS_LOWDELAY;
674 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
675 sizeof(int)) < 0)
676 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
677 }
678 #endif
679 /* if the hostname hasn't been given, attempt to determine it */
680 if (hostname[0] == '\0') {
681 if (getnameinfo((struct sockaddr *)&ctrl_addr.si_su,
682 ctrl_addr.su_len, hostname, sizeof(hostname), NULL, 0,
683 getnameopts) != 0)
684 (void)gethostname(hostname, sizeof(hostname));
685 hostname[sizeof(hostname) - 1] = '\0';
686 }
687
688 /* set this here so klogin can use it... */
689 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
690
691 (void) freopen(_PATH_DEVNULL, "w", stderr);
692
693 memset(&sa, 0, sizeof(sa));
694 sa.sa_handler = SIG_DFL;
695 sa.sa_flags = SA_RESTART;
696 sigemptyset(&sa.sa_mask);
697 (void) sigaction(SIGCHLD, &sa, NULL);
698
699 sa.sa_handler = sigquit;
700 sa.sa_flags = SA_RESTART;
701 sigfillset(&sa.sa_mask); /* block all sigs in these handlers */
702 (void) sigaction(SIGHUP, &sa, NULL);
703 (void) sigaction(SIGINT, &sa, NULL);
704 (void) sigaction(SIGQUIT, &sa, NULL);
705 (void) sigaction(SIGTERM, &sa, NULL);
706 sa.sa_handler = lostconn;
707 (void) sigaction(SIGPIPE, &sa, NULL);
708 sa.sa_handler = toolong;
709 (void) sigaction(SIGALRM, &sa, NULL);
710 sa.sa_handler = sigurg;
711 (void) sigaction(SIGURG, &sa, NULL);
712
713 /* Try to handle urgent data inline */
714 #ifdef SO_OOBINLINE
715 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
716 syslog(LOG_WARNING, "setsockopt: %m");
717 #endif
718 /* Set keepalives on the socket to detect dropped connections. */
719 #ifdef SO_KEEPALIVE
720 keepalive = 1;
721 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
722 sizeof(int)) < 0)
723 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
724 #endif
725
726 #ifdef F_SETOWN
727 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
728 syslog(LOG_WARNING, "fcntl F_SETOWN: %m");
729 #endif
730 logremotehost(&his_addr);
731 /*
732 * Set up default state
733 */
734 data = -1;
735 type = TYPE_A;
736 form = FORM_N;
737 stru = STRU_F;
738 mode = MODE_S;
739 tmpline[0] = '\0';
740 hasyyerrored = 0;
741
742 #ifdef KERBEROS5
743 kerror = krb5_init_context(&kcontext);
744 if (kerror) {
745 syslog(LOG_ERR, "%s when initializing Kerberos context",
746 error_message(kerror));
747 exit(0);
748 }
749 #endif /* KERBEROS5 */
750
751 init_curclass();
752 curclass.timeout = 300; /* 5 minutes, as per login(1) */
753 curclass.type = CLASS_REAL;
754
755 /* If logins are disabled, print out the message. */
756 if (display_file(_PATH_NOLOGIN, 530)) {
757 reply(530, "System not available.");
758 exit(0);
759 }
760 (void)display_file(conffilename(_NAME_FTPWELCOME), 220);
761 /* reply(220,) must follow */
762 if (EMPTYSTR(version))
763 reply(220, "%s FTP server ready.", hostname);
764 else
765 reply(220, "%s FTP server (%s) ready.", hostname, version);
766
767 if (xferlogname != NULL) {
768 xferlogfd = open(xferlogname, O_WRONLY | O_APPEND | O_CREAT,
769 0660);
770 if (xferlogfd == -1)
771 syslog(LOG_WARNING, "open xferlog `%s': %m",
772 xferlogname);
773 else
774 doxferlog |= 2;
775 }
776
777 ftp_loop();
778 /* NOTREACHED */
779 }
780
781 static void
lostconn(int signo __unused)782 lostconn(int signo __unused)
783 {
784
785 if (ftpd_debug)
786 syslog(LOG_DEBUG, "lost connection");
787 dologout(1);
788 }
789
790 static void
toolong(int signo __unused)791 toolong(int signo __unused)
792 {
793
794 /* XXXSIGRACE */
795 reply(421,
796 "Timeout (" LLF " seconds): closing control connection.",
797 (LLT)curclass.timeout);
798 if (logging)
799 syslog(LOG_INFO, "User %s timed out after " LLF " seconds",
800 (pw ? pw->pw_name : "unknown"), (LLT)curclass.timeout);
801 dologout(1);
802 }
803
804 static void
sigquit(int signo)805 sigquit(int signo)
806 {
807
808 if (ftpd_debug)
809 syslog(LOG_DEBUG, "got signal %d", signo);
810 dologout(1);
811 }
812
813 static void
sigurg(int signo __unused)814 sigurg(int signo __unused)
815 {
816
817 urgflag = 1;
818 }
819
820
821 /*
822 * Save the result of a getpwnam. Used for USER command, since
823 * the data returned must not be clobbered by any other command
824 * (e.g., globbing).
825 */
826 static struct passwd *
sgetpwnam(const char * name)827 sgetpwnam(const char *name)
828 {
829 static struct passwd save;
830 struct passwd *p;
831
832 if ((p = getpwnam(name)) == NULL)
833 return (p);
834 if (save.pw_name) {
835 free((char *)save.pw_name);
836 memset(save.pw_passwd, 0, strlen(save.pw_passwd));
837 free((char *)save.pw_passwd);
838 free((char *)save.pw_gecos);
839 free((char *)save.pw_dir);
840 free((char *)save.pw_shell);
841 }
842 save = *p;
843 save.pw_name = ftpd_strdup(p->pw_name);
844 save.pw_passwd = ftpd_strdup(p->pw_passwd);
845 save.pw_gecos = ftpd_strdup(p->pw_gecos);
846 save.pw_dir = ftpd_strdup(p->pw_dir);
847 save.pw_shell = ftpd_strdup(p->pw_shell);
848 return (&save);
849 }
850
851 static int login_attempts; /* number of failed login attempts */
852 static int askpasswd; /* had USER command, ask for PASSwd */
853 static int permitted; /* USER permitted */
854
855 /*
856 * USER command.
857 * Sets global passwd pointer pw if named account exists and is acceptable;
858 * sets askpasswd if a PASS command is expected. If logged in previously,
859 * need to reset state. If name is "ftp" or "anonymous", the name is not in
860 * _NAME_FTPUSERS, and ftp account exists, set guest and pw, then just return.
861 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
862 * requesting login privileges. Disallow anyone who does not have a standard
863 * shell as returned by getusershell(). Disallow anyone mentioned in the file
864 * _NAME_FTPUSERS to allow people such as root and uucp to be avoided.
865 */
866 void
user(const char * name)867 user(const char *name)
868 {
869 char *class;
870 #ifdef LOGIN_CAP
871 login_cap_t *lc = NULL;
872 #endif
873 #ifdef USE_PAM
874 int e;
875 #endif
876
877 class = NULL;
878 if (logged_in) {
879 switch (curclass.type) {
880 case CLASS_GUEST:
881 reply(530, "Can't change user from guest login.");
882 return;
883 case CLASS_CHROOT:
884 reply(530, "Can't change user from chroot user.");
885 return;
886 case CLASS_REAL:
887 if (dropprivs) {
888 reply(530, "Can't change user.");
889 return;
890 }
891 end_login();
892 break;
893 default:
894 abort();
895 }
896 }
897
898 #if defined(KERBEROS)
899 kdestroy();
900 #endif
901 #if defined(KERBEROS5)
902 k5destroy();
903 #endif
904
905 curclass.type = CLASS_REAL;
906 askpasswd = 0;
907 permitted = 0;
908
909 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
910 /* need `pw' setup for checkaccess() and checkuser () */
911 if ((pw = sgetpwnam("ftp")) == NULL)
912 reply(530, "User %s unknown.", name);
913 else if (! checkaccess("ftp") || ! checkaccess("anonymous"))
914 reply(530, "User %s access denied.", name);
915 else {
916 curclass.type = CLASS_GUEST;
917 askpasswd = 1;
918 reply(331,
919 "Guest login ok, type your name as password.");
920 }
921 if (!askpasswd) {
922 if (logging)
923 syslog(LOG_NOTICE,
924 "ANONYMOUS FTP LOGIN REFUSED FROM %s",
925 remoteloghost);
926 end_login();
927 goto cleanup_user;
928 }
929 name = "ftp";
930 } else
931 pw = sgetpwnam(name);
932
933 strlcpy(curname, name, curname_len);
934
935 /* check user in /etc/ftpusers, and setup class */
936 permitted = checkuser(_NAME_FTPUSERS, curname, 1, 0, &class);
937
938 /* check user in /etc/ftpchroot */
939 #ifdef LOGIN_CAP
940 lc = login_getpwclass(pw);
941 #endif
942 if (checkuser(_NAME_FTPCHROOT, curname, 0, 0, NULL)
943 #ifdef LOGIN_CAP /* Allow login.conf configuration as well */
944 || login_getcapbool(lc, "ftp-chroot", 0)
945 #endif
946 ) {
947 if (curclass.type == CLASS_GUEST) {
948 syslog(LOG_NOTICE,
949 "Can't change guest user to chroot class; remove entry in %s",
950 _NAME_FTPCHROOT);
951 exit(1);
952 }
953 curclass.type = CLASS_CHROOT;
954 }
955
956 /* determine default class */
957 if (class == NULL) {
958 switch (curclass.type) {
959 case CLASS_GUEST:
960 class = ftpd_strdup("guest");
961 break;
962 case CLASS_CHROOT:
963 class = ftpd_strdup("chroot");
964 break;
965 case CLASS_REAL:
966 class = ftpd_strdup("real");
967 break;
968 default:
969 syslog(LOG_ERR, "unknown curclass.type %d; aborting",
970 curclass.type);
971 abort();
972 }
973 }
974 /* parse ftpd.conf, setting up various parameters */
975 parse_conf(class);
976 /* if not guest user, check for valid shell */
977 if (pw == NULL)
978 permitted = 0;
979 else {
980 const char *cp, *shell;
981
982 if ((shell = pw->pw_shell) == NULL || *shell == 0)
983 shell = _PATH_BSHELL;
984 while ((cp = getusershell()) != NULL)
985 if (strcmp(cp, shell) == 0)
986 break;
987 endusershell();
988 if (cp == NULL && curclass.type != CLASS_GUEST)
989 permitted = 0;
990 }
991
992 /* deny quickly (after USER not PASS) if requested */
993 if (CURCLASS_FLAGS_ISSET(denyquick) && !permitted) {
994 reply(530, "User %s may not use FTP.", curname);
995 if (logging)
996 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
997 remoteloghost, curname);
998 end_login();
999 goto cleanup_user;
1000 }
1001
1002 /* if haven't asked yet (i.e, not anon), ask now */
1003 if (!askpasswd) {
1004 askpasswd = 1;
1005 #ifdef USE_PAM
1006 e = auth_pam(); /* this does reply(331, ...) */
1007 do_pass(1, e, "");
1008 goto cleanup_user;
1009 #else /* !USE_PAM */
1010 #ifdef SKEY
1011 if (skey_haskey(curname) == 0) {
1012 const char *myskey;
1013
1014 myskey = skey_keyinfo(curname);
1015 reply(331, "Password [ %s ] required for %s.",
1016 myskey ? myskey : "error getting challenge",
1017 curname);
1018 } else
1019 #endif
1020 reply(331, "Password required for %s.", curname);
1021 #endif /* !USE_PAM */
1022 }
1023
1024 cleanup_user:
1025 #ifdef LOGIN_CAP
1026 login_close(lc);
1027 #endif
1028 /*
1029 * Delay before reading passwd after first failed
1030 * attempt to slow down passwd-guessing programs.
1031 */
1032 if (login_attempts)
1033 sleep((unsigned) login_attempts);
1034
1035 if (class)
1036 free(class);
1037 }
1038
1039 /*
1040 * Determine whether something is to happen (allow access, chroot)
1041 * for a user. Each line is a shell-style glob followed by
1042 * `yes' or `no'.
1043 *
1044 * For backward compatibility, `allow' and `deny' are synonymns
1045 * for `yes' and `no', respectively.
1046 *
1047 * Each glob is matched against the username in turn, and the first
1048 * match found is used. If no match is found, the result is the
1049 * argument `def'. If a match is found but without and explicit
1050 * `yes'/`no', the result is the opposite of def.
1051 *
1052 * If the file doesn't exist at all, the result is the argument
1053 * `nofile'
1054 *
1055 * Any line starting with `#' is considered a comment and ignored.
1056 *
1057 * Returns 0 if the user is denied, or 1 if they are allowed.
1058 *
1059 * NOTE: needs struct passwd *pw setup before use.
1060 */
1061 static int
checkuser(const char * fname,const char * name,int def,int nofile,char ** retclass)1062 checkuser(const char *fname, const char *name, int def, int nofile,
1063 char **retclass)
1064 {
1065 FILE *fd;
1066 int retval;
1067 char *word, *perm, *class, *buf, *p;
1068 size_t len, line;
1069
1070 retval = def;
1071 if (retclass != NULL)
1072 *retclass = NULL;
1073 if ((fd = fopen(conffilename(fname), "r")) == NULL)
1074 return nofile;
1075
1076 line = 0;
1077 for (;
1078 (buf = fparseln(fd, &len, &line, NULL, FPARSELN_UNESCCOMM |
1079 FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
1080 free(buf), buf = NULL) {
1081 word = perm = class = NULL;
1082 p = buf;
1083 if (len < 1)
1084 continue;
1085 if (p[len - 1] == '\n')
1086 p[--len] = '\0';
1087 if (EMPTYSTR(p))
1088 continue;
1089
1090 NEXTWORD(p, word);
1091 NEXTWORD(p, perm);
1092 NEXTWORD(p, class);
1093 if (EMPTYSTR(word))
1094 continue;
1095 if (!EMPTYSTR(class)) {
1096 if (strcasecmp(class, "all") == 0 ||
1097 strcasecmp(class, "none") == 0) {
1098 syslog(LOG_WARNING,
1099 "%s line %d: illegal user-defined class `%s' - skipping entry",
1100 fname, (int)line, class);
1101 continue;
1102 }
1103 }
1104
1105 /* have a host specifier */
1106 if ((p = strchr(word, '@')) != NULL) {
1107 unsigned char net[16], mask[16], *addr;
1108 int addrlen, bits, bytes, a;
1109
1110 *p++ = '\0';
1111 /* check against network or CIDR */
1112 memset(net, 0x00, sizeof(net));
1113 if ((bits = inet_net_pton(his_addr.su_family, p, net,
1114 sizeof(net))) != -1) {
1115 #ifdef INET6
1116 if (his_addr.su_family == AF_INET) {
1117 #endif
1118 addrlen = 4;
1119 addr = (unsigned char *)&his_addr.su_addr;
1120 #ifdef INET6
1121 } else {
1122 addrlen = 16;
1123 addr = (unsigned char *)&his_addr.su_6addr;
1124 }
1125 #endif
1126 bytes = bits / 8;
1127 bits = bits % 8;
1128 if (bytes > 0)
1129 memset(mask, 0xFF, bytes);
1130 if (bytes < addrlen)
1131 mask[bytes] = 0xFF << (8 - bits);
1132 if (bytes + 1 < addrlen)
1133 memset(mask + bytes + 1, 0x00,
1134 addrlen - bytes - 1);
1135 for (a = 0; a < addrlen; a++)
1136 if ((addr[a] & mask[a]) != net[a])
1137 break;
1138 if (a < addrlen)
1139 continue;
1140
1141 /* check against hostname glob */
1142 } else if (fnmatch(p, remotehost, FNM_CASEFOLD) != 0)
1143 continue;
1144 }
1145
1146 /* have a group specifier */
1147 if ((p = strchr(word, ':')) != NULL) {
1148 gid_t *groups, *ng;
1149 int gsize, i, found;
1150
1151 if (pw == NULL)
1152 continue; /* no match for unknown user */
1153 *p++ = '\0';
1154 groups = NULL;
1155 gsize = 16;
1156 do {
1157 ng = realloc(groups, gsize * sizeof(gid_t));
1158 if (ng == NULL)
1159 fatal(
1160 "Local resource failure: realloc");
1161 groups = ng;
1162 } while (getgrouplist(pw->pw_name, pw->pw_gid,
1163 groups, &gsize) == -1);
1164 found = 0;
1165 for (i = 0; i < gsize; i++) {
1166 struct group *g;
1167
1168 if ((g = getgrgid(groups[i])) == NULL)
1169 continue;
1170 if (fnmatch(p, g->gr_name, 0) == 0) {
1171 found = 1;
1172 break;
1173 }
1174 }
1175 free(groups);
1176 if (!found)
1177 continue;
1178 }
1179
1180 /* check against username glob */
1181 if (fnmatch(word, name, 0) != 0)
1182 continue;
1183
1184 if (perm != NULL &&
1185 ((strcasecmp(perm, "allow") == 0) ||
1186 (strcasecmp(perm, "yes") == 0)))
1187 retval = 1;
1188 else if (perm != NULL &&
1189 ((strcasecmp(perm, "deny") == 0) ||
1190 (strcasecmp(perm, "no") == 0)))
1191 retval = 0;
1192 else
1193 retval = !def;
1194 if (!EMPTYSTR(class) && retclass != NULL)
1195 *retclass = ftpd_strdup(class);
1196 free(buf);
1197 break;
1198 }
1199 (void) fclose(fd);
1200 return (retval);
1201 }
1202
1203 /*
1204 * Check if user is allowed by /etc/ftpusers
1205 * returns 1 for yes, 0 for no
1206 *
1207 * NOTE: needs struct passwd *pw setup (for checkuser())
1208 */
1209 static int
checkaccess(const char * name)1210 checkaccess(const char *name)
1211 {
1212
1213 return (checkuser(_NAME_FTPUSERS, name, 1, 0, NULL));
1214 }
1215
1216 static void
login_utmp(const char * line,const char * name,const char * host,struct sockinet * haddr)1217 login_utmp(const char *line, const char *name, const char *host,
1218 struct sockinet *haddr)
1219 {
1220 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
1221 struct timeval tv;
1222 (void)gettimeofday(&tv, NULL);
1223 #endif
1224 #ifdef SUPPORT_UTMPX
1225 if (doutmp) {
1226 (void)memset(&utmpx, 0, sizeof(utmpx));
1227 utmpx.ut_tv = tv;
1228 utmpx.ut_pid = getpid();
1229 utmpx.ut_id[0] = 'f';
1230 utmpx.ut_id[1] = 't';
1231 utmpx.ut_id[2] = 'p';
1232 utmpx.ut_id[3] = '*';
1233 utmpx.ut_type = USER_PROCESS;
1234 (void)strncpy(utmpx.ut_name, name, sizeof(utmpx.ut_name));
1235 (void)strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
1236 (void)strncpy(utmpx.ut_host, host, sizeof(utmpx.ut_host));
1237 (void)memcpy(&utmpx.ut_ss, &haddr->si_su, haddr->su_len);
1238 ftpd_loginx(&utmpx);
1239 }
1240 if (dowtmp)
1241 ftpd_logwtmpx(line, name, host, haddr, 0, USER_PROCESS);
1242 #endif
1243 #ifdef SUPPORT_UTMP
1244 if (doutmp) {
1245 (void)memset(&utmp, 0, sizeof(utmp));
1246 (void)time(&utmp.ut_time);
1247 (void)strncpy(utmp.ut_name, name, sizeof(utmp.ut_name));
1248 (void)strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
1249 (void)strncpy(utmp.ut_host, host, sizeof(utmp.ut_host));
1250 ftpd_login(&utmp);
1251 }
1252 if (dowtmp)
1253 ftpd_logwtmp(line, name, host);
1254 #endif
1255 }
1256
1257 static void
logout_utmp(void)1258 logout_utmp(void)
1259 {
1260 #ifdef SUPPORT_UTMPX
1261 int okwtmpx = dowtmp;
1262 #endif
1263 #ifdef SUPPORT_UTMP
1264 int okwtmp = dowtmp;
1265 #endif
1266 if (logged_in) {
1267 #ifdef SUPPORT_UTMPX
1268 if (doutmp)
1269 okwtmpx &= ftpd_logoutx(ttyline, 0, DEAD_PROCESS);
1270 if (okwtmpx)
1271 ftpd_logwtmpx(ttyline, "", "", NULL, 0, DEAD_PROCESS);
1272 #endif
1273 #ifdef SUPPORT_UTMP
1274 if (doutmp)
1275 okwtmp &= ftpd_logout(ttyline);
1276 if (okwtmp)
1277 ftpd_logwtmp(ttyline, "", "");
1278 #endif
1279 }
1280 }
1281
1282 /*
1283 * Terminate login as previous user (if any), resetting state;
1284 * used when USER command is given or login fails.
1285 */
1286 static void
end_login(void)1287 end_login(void)
1288 {
1289 #ifdef USE_PAM
1290 int e;
1291 #endif
1292 logout_utmp();
1293 show_chdir_messages(-1); /* flush chdir cache */
1294 if (pw != NULL && pw->pw_passwd != NULL)
1295 memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
1296 pw = NULL;
1297 logged_in = 0;
1298 askpasswd = 0;
1299 permitted = 0;
1300 quietmessages = 0;
1301 gidcount = 0;
1302 curclass.type = CLASS_REAL;
1303 if (!dropprivs) {
1304 if (seteuid((uid_t)0) < 0) {
1305 syslog(LOG_NOTICE, "end_login: can't seteuid 0: %m");
1306 fatal("Can't reset privileges.");
1307 }
1308 }
1309 #ifdef LOGIN_CAP
1310 setusercontext(NULL, getpwuid(0), 0,
1311 LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1312 #endif
1313 #ifdef USE_PAM
1314 if (pamh) {
1315 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS)
1316 syslog(LOG_ERR, "pam_setcred: %s",
1317 pam_strerror(pamh, e));
1318 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS)
1319 syslog(LOG_ERR, "pam_close_session: %s",
1320 pam_strerror(pamh, e));
1321 if ((e = pam_end(pamh, e)) != PAM_SUCCESS)
1322 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
1323 pamh = NULL;
1324 }
1325 #endif
1326 }
1327
1328 void
pass(const char * passwd)1329 pass(const char *passwd)
1330 {
1331 do_pass(0, 0, passwd);
1332 }
1333
1334 /*
1335 * Perform the passwd confirmation and login.
1336 *
1337 * If pass_checked is zero, confirm passwd is correct, & ignore pass_rval.
1338 * This is the traditional PASS implementation.
1339 *
1340 * If pass_checked is non-zero, use pass_rval and ignore passwd.
1341 * This is used by auth_pam() which has already parsed PASS.
1342 * This only applies to curclass.type != CLASS_GUEST.
1343 */
1344 static void
do_pass(int pass_checked,int pass_rval,const char * passwd)1345 do_pass(int pass_checked, int pass_rval, const char *passwd)
1346 {
1347 int rval;
1348 char root[MAXPATHLEN];
1349 #ifdef LOGIN_CAP
1350 login_cap_t *lc = NULL;
1351 #endif
1352 #ifdef USE_PAM
1353 int e;
1354 #endif
1355
1356 rval = 1;
1357
1358 if (logged_in || askpasswd == 0) {
1359 reply(503, "Login with USER first.");
1360 return;
1361 }
1362 askpasswd = 0;
1363 if (curclass.type != CLASS_GUEST) {
1364 /* "ftp" is the only account allowed with no password */
1365 if (pw == NULL) {
1366 rval = 1; /* failure below */
1367 goto skip;
1368 }
1369 if (pass_checked) { /* password validated in user() */
1370 rval = pass_rval;
1371 goto skip;
1372 }
1373 #ifdef USE_PAM
1374 syslog(LOG_ERR, "do_pass: USE_PAM shouldn't get here");
1375 rval = 1;
1376 goto skip;
1377 #endif
1378 #if defined(KERBEROS)
1379 if (klogin(pw, "", hostname, (char *)passwd) == 0) {
1380 rval = 0;
1381 goto skip;
1382 }
1383 #endif
1384 #if defined(KERBEROS5)
1385 if (k5login(pw, "", hostname, (char *)passwd) == 0) {
1386 rval = 0;
1387 goto skip;
1388 }
1389 #endif
1390 #ifdef SKEY
1391 if (skey_haskey(pw->pw_name) == 0) {
1392 char *p;
1393 int r;
1394
1395 p = ftpd_strdup(passwd);
1396 r = skey_passcheck(pw->pw_name, p);
1397 free(p);
1398 if (r != -1) {
1399 rval = 0;
1400 goto skip;
1401 }
1402 }
1403 #endif
1404 if (!sflag)
1405 rval = checkpassword(pw, passwd);
1406 else
1407 rval = 1;
1408
1409 skip:
1410
1411 /*
1412 * If rval > 0, the user failed the authentication check
1413 * above. If rval == 0, either Kerberos or local
1414 * authentication succeeded.
1415 */
1416 if (rval) {
1417 reply(530, "%s", rval == 2 ? "Password expired." :
1418 "Login incorrect.");
1419 pfilter_notify(1, rval == 2 ? "exppass" : "badpass");
1420 if (logging) {
1421 syslog(LOG_NOTICE,
1422 "FTP LOGIN FAILED FROM %s", remoteloghost);
1423 syslog(LOG_AUTHPRIV | LOG_NOTICE,
1424 "FTP LOGIN FAILED FROM %s, %s",
1425 remoteloghost, curname);
1426 }
1427 pw = NULL;
1428 if (login_attempts++ >= 5) {
1429 syslog(LOG_NOTICE,
1430 "repeated login failures from %s",
1431 remoteloghost);
1432 exit(0);
1433 }
1434 return;
1435 }
1436 }
1437
1438 /* password ok; check if anything else prevents login */
1439 if (! permitted) {
1440 reply(530, "User %s may not use FTP.", pw->pw_name);
1441 if (logging)
1442 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
1443 remoteloghost, pw->pw_name);
1444 goto bad;
1445 }
1446
1447 login_attempts = 0; /* this time successful */
1448 if (setegid((gid_t)pw->pw_gid) < 0) {
1449 syslog(LOG_NOTICE, "user %s: can't setegid: %m", pw->pw_name);
1450 fatal("Can't drop privileges.");
1451 }
1452 #ifdef LOGIN_CAP
1453 if ((lc = login_getpwclass(pw)) != NULL) {
1454 #ifdef notyet
1455 char remote_ip[NI_MAXHOST];
1456
1457 if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1458 remote_ip, sizeof(remote_ip) - 1, NULL, 0,
1459 NI_NUMERICHOST))
1460 *remote_ip = 0;
1461 remote_ip[sizeof(remote_ip) - 1] = 0;
1462 if (!auth_hostok(lc, remotehost, remote_ip)) {
1463 pfilter_notify(1, "bannedhost");
1464 syslog(LOG_INFO|LOG_AUTH,
1465 "FTP LOGIN FAILED (HOST) as %s: permission denied.",
1466 pw->pw_name);
1467 reply(530, "Permission denied.");
1468 pw = NULL;
1469 return;
1470 }
1471 if (!auth_timeok(lc, time(NULL))) {
1472 reply(530, "Login not available right now.");
1473 pw = NULL;
1474 return;
1475 }
1476 #endif
1477 }
1478 setsid();
1479 setusercontext(lc, pw, 0,
1480 LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY|
1481 LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1482 #else
1483 (void) initgroups(pw->pw_name, pw->pw_gid);
1484 /* cache groups for cmds.c::matchgroup() */
1485 #endif
1486 #ifdef USE_PAM
1487 if (pamh) {
1488 if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
1489 syslog(LOG_ERR, "pam_open_session: %s",
1490 pam_strerror(pamh, e));
1491 } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED))
1492 != PAM_SUCCESS) {
1493 syslog(LOG_ERR, "pam_setcred: %s",
1494 pam_strerror(pamh, e));
1495 }
1496 }
1497 #endif
1498 gidcount = getgroups(0, NULL);
1499 if (gidlist)
1500 free(gidlist);
1501 gidlist = malloc(gidcount * sizeof *gidlist);
1502 gidcount = getgroups(gidcount, gidlist);
1503
1504 /* open utmp/wtmp before chroot */
1505 login_utmp(ttyline, pw->pw_name, remotehost, &his_addr);
1506
1507 logged_in = 1;
1508
1509 connections = 1;
1510 if (dopidfile)
1511 count_users();
1512 if (curclass.limit != -1 && connections > curclass.limit) {
1513 if (! EMPTYSTR(curclass.limitfile))
1514 (void)display_file(conffilename(curclass.limitfile),
1515 530);
1516 reply(530,
1517 "User %s access denied, connection limit of " LLF
1518 " reached.",
1519 pw->pw_name, (LLT)curclass.limit);
1520 syslog(LOG_NOTICE,
1521 "Maximum connection limit of " LLF
1522 " for class %s reached, login refused for %s",
1523 (LLT)curclass.limit, curclass.classname, pw->pw_name);
1524 goto bad;
1525 }
1526
1527 homedir[0] = '/';
1528 switch (curclass.type) {
1529 case CLASS_GUEST:
1530 /*
1531 * We MUST do a chdir() after the chroot. Otherwise
1532 * the old current directory will be accessible as "."
1533 * outside the new root!
1534 */
1535 format_path(root,
1536 curclass.chroot ? curclass.chroot :
1537 anondir ? anondir :
1538 pw->pw_dir);
1539 format_path(homedir,
1540 curclass.homedir ? curclass.homedir :
1541 "/");
1542 if (EMPTYSTR(homedir))
1543 homedir[0] = '/';
1544 if (EMPTYSTR(root) || chroot(root) < 0) {
1545 syslog(LOG_NOTICE,
1546 "GUEST user %s: can't chroot to %s: %m",
1547 pw->pw_name, root);
1548 goto bad_guest;
1549 }
1550 if (chdir(homedir) < 0) {
1551 syslog(LOG_NOTICE,
1552 "GUEST user %s: can't chdir to %s: %m",
1553 pw->pw_name, homedir);
1554 bad_guest:
1555 fatal("Can't set guest privileges.");
1556 }
1557 break;
1558 case CLASS_CHROOT:
1559 format_path(root,
1560 curclass.chroot ? curclass.chroot :
1561 pw->pw_dir);
1562 format_path(homedir,
1563 curclass.homedir ? curclass.homedir :
1564 "/");
1565 if (EMPTYSTR(homedir))
1566 homedir[0] = '/';
1567 if (EMPTYSTR(root) || chroot(root) < 0) {
1568 syslog(LOG_NOTICE,
1569 "CHROOT user %s: can't chroot to %s: %m",
1570 pw->pw_name, root);
1571 goto bad_chroot;
1572 }
1573 if (chdir(homedir) < 0) {
1574 syslog(LOG_NOTICE,
1575 "CHROOT user %s: can't chdir to %s: %m",
1576 pw->pw_name, homedir);
1577 bad_chroot:
1578 fatal("Can't change root.");
1579 }
1580 break;
1581 case CLASS_REAL:
1582 /* only chroot REAL if explicitly requested */
1583 if (! EMPTYSTR(curclass.chroot)) {
1584 format_path(root, curclass.chroot);
1585 if (EMPTYSTR(root) || chroot(root) < 0) {
1586 syslog(LOG_NOTICE,
1587 "REAL user %s: can't chroot to %s: %m",
1588 pw->pw_name, root);
1589 goto bad_chroot;
1590 }
1591 }
1592 format_path(homedir,
1593 curclass.homedir ? curclass.homedir :
1594 pw->pw_dir);
1595 if (EMPTYSTR(homedir) || chdir(homedir) < 0) {
1596 if (chdir("/") < 0) {
1597 syslog(LOG_NOTICE,
1598 "REAL user %s: can't chdir to %s: %m",
1599 pw->pw_name,
1600 !EMPTYSTR(homedir) ? homedir : "/");
1601 reply(530,
1602 "User %s: can't change directory to %s.",
1603 pw->pw_name,
1604 !EMPTYSTR(homedir) ? homedir : "/");
1605 goto bad;
1606 } else {
1607 reply(-230,
1608 "No directory! Logging in with home=/");
1609 homedir[0] = '/';
1610 }
1611 }
1612 break;
1613 }
1614 #ifndef LOGIN_CAP
1615 setsid();
1616 setlogin(pw->pw_name);
1617 #endif
1618 if (dropprivs ||
1619 (curclass.type != CLASS_REAL &&
1620 ntohs(ctrl_addr.su_port) > IPPORT_RESERVED + 1)) {
1621 dropprivs++;
1622 if (setgid((gid_t)pw->pw_gid) < 0) {
1623 syslog(LOG_NOTICE, "user %s: can't setgid: %m", pw->pw_name);
1624 fatal("Can't drop privileges.");
1625 }
1626 if (setuid((uid_t)pw->pw_uid) < 0) {
1627 syslog(LOG_NOTICE, "user %s: can't setuid: %m", pw->pw_name);
1628 fatal("Can't drop privileges.");
1629 }
1630 } else {
1631 if (seteuid((uid_t)pw->pw_uid) < 0) {
1632 syslog(LOG_NOTICE, "user %s: can't seteuid: %m", pw->pw_name);
1633 fatal("Can't drop privileges.");
1634 }
1635 }
1636 setenv("HOME", homedir, 1);
1637
1638 if (curclass.type == CLASS_GUEST && passwd[0] == '-')
1639 quietmessages = 1;
1640
1641 /*
1642 * Display a login message, if it exists.
1643 * N.B. reply(230,) must follow the message.
1644 */
1645 if (! EMPTYSTR(curclass.motd))
1646 (void)display_file(conffilename(curclass.motd), 230);
1647 show_chdir_messages(230);
1648 if (curclass.type == CLASS_GUEST) {
1649 char *p;
1650
1651 reply(230, "Guest login ok, access restrictions apply.");
1652 #if defined(HAVE_SETPROCTITLE)
1653 snprintf(proctitle, sizeof(proctitle),
1654 "%s: anonymous/%s", remotehost, passwd);
1655 setproctitle("%s", proctitle);
1656 #endif /* defined(HAVE_SETPROCTITLE) */
1657 if (logging)
1658 syslog(LOG_INFO,
1659 "ANONYMOUS FTP LOGIN FROM %s, %s (class: %s, type: %s)",
1660 remoteloghost, passwd,
1661 curclass.classname, CURCLASSTYPE);
1662 /* store guest password reply into pw_passwd */
1663 REASSIGN(pw->pw_passwd, ftpd_strdup(passwd));
1664 for (p = pw->pw_passwd; *p; p++)
1665 if (!isgraph((unsigned char)*p))
1666 *p = '_';
1667 } else {
1668 reply(230, "User %s logged in.", pw->pw_name);
1669 #if defined(HAVE_SETPROCTITLE)
1670 snprintf(proctitle, sizeof(proctitle),
1671 "%s: %s", remotehost, pw->pw_name);
1672 setproctitle("%s", proctitle);
1673 #endif /* defined(HAVE_SETPROCTITLE) */
1674 if (logging)
1675 syslog(LOG_INFO,
1676 "FTP LOGIN FROM %s as %s (class: %s, type: %s)",
1677 remoteloghost, pw->pw_name,
1678 curclass.classname, CURCLASSTYPE);
1679 }
1680 (void) umask(curclass.umask);
1681 #ifdef LOGIN_CAP
1682 login_close(lc);
1683 #endif
1684 return;
1685
1686 bad:
1687 #ifdef LOGIN_CAP
1688 login_close(lc);
1689 #endif
1690 /* Forget all about it... */
1691 end_login();
1692 }
1693
1694 void
retrieve(const char * argv[],const char * name)1695 retrieve(const char *argv[], const char *name)
1696 {
1697 FILE *fin, *dout;
1698 struct stat st;
1699 int (*closefunc)(FILE *) = NULL;
1700 int dolog, sendrv, closerv, stderrfd, isconversion, isdata, isls;
1701 struct timeval start, finish, td, *tdp;
1702 struct rusage rusage_before, rusage_after;
1703 const char *dispname;
1704 const char *error;
1705
1706 sendrv = closerv = stderrfd = -1;
1707 isconversion = isdata = isls = dolog = 0;
1708 tdp = NULL;
1709 dispname = name;
1710 fin = dout = NULL;
1711 error = NULL;
1712 if (argv == NULL) { /* if not running a command ... */
1713 dolog = 1;
1714 isdata = 1;
1715 fin = fopen(name, "r");
1716 closefunc = fclose;
1717 if (fin == NULL) /* doesn't exist?; try a conversion */
1718 argv = do_conversion(name);
1719 if (argv != NULL) {
1720 isconversion++;
1721 syslog(LOG_DEBUG, "get command: '%s' on '%s'",
1722 argv[0], name);
1723 }
1724 }
1725 if (argv != NULL) {
1726 char temp[MAXPATHLEN];
1727
1728 if (strcmp(argv[0], INTERNAL_LS) == 0) {
1729 isls = 1;
1730 stderrfd = -1;
1731 } else {
1732 (void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
1733 stderrfd = mkstemp(temp);
1734 if (stderrfd != -1)
1735 (void)unlink(temp);
1736 }
1737 dispname = argv[0];
1738 fin = ftpd_popen(argv, "r", stderrfd);
1739 closefunc = ftpd_pclose;
1740 st.st_size = -1;
1741 st.st_blksize = BUFSIZ;
1742 }
1743 if (fin == NULL) {
1744 if (errno != 0) {
1745 perror_reply(550, dispname);
1746 if (dolog)
1747 logxfer("get", -1, name, NULL, NULL,
1748 strerror(errno));
1749 }
1750 goto cleanupretrieve;
1751 }
1752 byte_count = -1;
1753 if (argv == NULL
1754 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1755 error = "Not a plain file";
1756 reply(550, "%s: %s.", dispname, error);
1757 goto done;
1758 }
1759 if (restart_point) {
1760 if (type == TYPE_A) {
1761 off_t i;
1762 int c;
1763
1764 for (i = 0; i < restart_point; i++) {
1765 if ((c=getc(fin)) == EOF) {
1766 error = strerror(errno);
1767 perror_reply(550, dispname);
1768 goto done;
1769 }
1770 if (c == '\n')
1771 i++;
1772 }
1773 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1774 error = strerror(errno);
1775 perror_reply(550, dispname);
1776 goto done;
1777 }
1778 }
1779 dout = dataconn(dispname, st.st_size, "w");
1780 if (dout == NULL)
1781 goto done;
1782
1783 (void)getrusage(RUSAGE_SELF, &rusage_before);
1784 (void)gettimeofday(&start, NULL);
1785 sendrv = send_data(fin, dout, &st, isdata);
1786 (void)gettimeofday(&finish, NULL);
1787 (void)getrusage(RUSAGE_SELF, &rusage_after);
1788 closedataconn(dout); /* close now to affect timing stats */
1789 timersub(&finish, &start, &td);
1790 tdp = &td;
1791 done:
1792 if (dolog) {
1793 logxfer("get", byte_count, name, NULL, tdp, error);
1794 if (tdp != NULL)
1795 logrusage(&rusage_before, &rusage_after);
1796 }
1797 closerv = (*closefunc)(fin);
1798 if (sendrv == 0) {
1799 FILE *errf;
1800 struct stat sb;
1801
1802 if (!isls && argv != NULL && closerv != 0) {
1803 reply(-226,
1804 "Command returned an exit status of %d",
1805 closerv);
1806 if (isconversion)
1807 syslog(LOG_WARNING,
1808 "retrieve command: '%s' returned %d",
1809 argv[0], closerv);
1810 }
1811 if (!isls && argv != NULL && stderrfd != -1 &&
1812 (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
1813 ((errf = fdopen(stderrfd, "r")) != NULL)) {
1814 char *cp, line[LINE_MAX];
1815
1816 reply(-226, "Command error messages:");
1817 rewind(errf);
1818 while (fgets(line, sizeof(line), errf) != NULL) {
1819 if ((cp = strchr(line, '\n')) != NULL)
1820 *cp = '\0';
1821 reply(0, " %s", line);
1822 }
1823 (void) fflush(stdout);
1824 (void) fclose(errf);
1825 /* a reply(226,) must follow */
1826 }
1827 reply(226, "Transfer complete.");
1828 }
1829 cleanupretrieve:
1830 if (stderrfd != -1)
1831 (void)close(stderrfd);
1832 if (isconversion)
1833 free(argv);
1834 }
1835
1836 void
store(const char * name,const char * fmode,int unique)1837 store(const char *name, const char *fmode, int unique)
1838 {
1839 FILE *fout, *din;
1840 struct stat st;
1841 int (*closefunc)(FILE *);
1842 struct timeval start, finish, td, *tdp;
1843 const char *desc, *error;
1844
1845 din = NULL;
1846 desc = (*fmode == 'w') ? "put" : "append";
1847 error = NULL;
1848 if (unique && stat(name, &st) == 0 &&
1849 (name = gunique(name)) == NULL) {
1850 logxfer(desc, -1, name, NULL, NULL,
1851 "cannot create unique file");
1852 goto cleanupstore;
1853 }
1854
1855 if (restart_point)
1856 fmode = "r+";
1857 fout = fopen(name, fmode);
1858 closefunc = fclose;
1859 tdp = NULL;
1860 if (fout == NULL) {
1861 perror_reply(553, name);
1862 logxfer(desc, -1, name, NULL, NULL, strerror(errno));
1863 goto cleanupstore;
1864 }
1865 byte_count = -1;
1866 if (restart_point) {
1867 if (type == TYPE_A) {
1868 off_t i;
1869 int c;
1870
1871 for (i = 0; i < restart_point; i++) {
1872 if ((c=getc(fout)) == EOF) {
1873 error = strerror(errno);
1874 perror_reply(550, name);
1875 goto done;
1876 }
1877 if (c == '\n')
1878 i++;
1879 }
1880 /*
1881 * We must do this seek to "current" position
1882 * because we are changing from reading to
1883 * writing.
1884 */
1885 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1886 error = strerror(errno);
1887 perror_reply(550, name);
1888 goto done;
1889 }
1890 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1891 error = strerror(errno);
1892 perror_reply(550, name);
1893 goto done;
1894 }
1895 }
1896 din = dataconn(name, (off_t)-1, "r");
1897 if (din == NULL)
1898 goto done;
1899 (void)gettimeofday(&start, NULL);
1900 if (receive_data(din, fout) == 0) {
1901 if (unique)
1902 reply(226, "Transfer complete (unique file name:%s).",
1903 name);
1904 else
1905 reply(226, "Transfer complete.");
1906 }
1907 (void)gettimeofday(&finish, NULL);
1908 closedataconn(din); /* close now to affect timing stats */
1909 timersub(&finish, &start, &td);
1910 tdp = &td;
1911 done:
1912 logxfer(desc, byte_count, name, NULL, tdp, error);
1913 (*closefunc)(fout);
1914 cleanupstore:
1915 ;
1916 }
1917
1918 static FILE *
getdatasock(const char * fmode)1919 getdatasock(const char *fmode)
1920 {
1921 int on, s, t, tries;
1922 in_port_t port;
1923
1924 on = 1;
1925 if (data >= 0)
1926 return (fdopen(data, fmode));
1927 if (! dropprivs) {
1928 if (seteuid((uid_t)0) < 0) {
1929 syslog(LOG_NOTICE, "getdatasock: can't seteuid 0: %m");
1930 fatal("Can't reset privileges.");
1931 }
1932 }
1933 s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1934 if (s < 0)
1935 goto bad;
1936 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1937 (char *) &on, sizeof(on)) < 0)
1938 goto bad;
1939 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1940 (char *) &on, sizeof(on)) < 0)
1941 goto bad;
1942 /* anchor socket to avoid multi-homing problems */
1943 data_source = ctrl_addr;
1944 /*
1945 * By default source port for PORT connctions is
1946 * ctrlport-1 (see RFC959 section 5.2).
1947 * However, if privs have been dropped and that
1948 * would be < IPPORT_RESERVED, use a random port
1949 * instead.
1950 */
1951 if (dataport)
1952 port = dataport;
1953 else
1954 port = ntohs(ctrl_addr.su_port) - 1;
1955 if (dropprivs && port < IPPORT_RESERVED)
1956 port = 0; /* use random port */
1957 data_source.su_port = htons(port);
1958
1959 for (tries = 1; ; tries++) {
1960 if (bind(s, (struct sockaddr *)&data_source.si_su,
1961 data_source.su_len) >= 0)
1962 break;
1963 if (errno != EADDRINUSE || tries > 10)
1964 goto bad;
1965 sleep(tries);
1966 }
1967 if (! dropprivs) {
1968 if (seteuid((uid_t)pw->pw_uid) < 0) {
1969 syslog(LOG_NOTICE, "user %s: can't seteuid: %m", pw->pw_name);
1970 fatal("Can't drop privileges.");
1971 }
1972 }
1973 #ifdef IP_TOS
1974 if (!mapped && ctrl_addr.su_family == AF_INET) {
1975 on = IPTOS_THROUGHPUT;
1976 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1977 sizeof(int)) < 0)
1978 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1979 }
1980 #endif
1981 return (fdopen(s, fmode));
1982 bad:
1983 /* Return the real value of errno (close may change it) */
1984 t = errno;
1985 if (! dropprivs) {
1986 if (seteuid((uid_t)pw->pw_uid) < 0) {
1987 syslog(LOG_NOTICE, "user %s: can't seteuid: %m", pw->pw_name);
1988 fatal("Can't drop privileges.");
1989 }
1990 }
1991 if (s >= 0)
1992 (void) close(s);
1993 errno = t;
1994 return (NULL);
1995 }
1996
1997 FILE *
dataconn(const char * name,off_t size,const char * fmode)1998 dataconn(const char *name, off_t size, const char *fmode)
1999 {
2000 char sizebuf[32];
2001 FILE *file;
2002 int retry, tos, keepalive, conerrno;
2003
2004 file_size = size;
2005 byte_count = 0;
2006 if (size != (off_t) -1)
2007 (void)snprintf(sizebuf, sizeof(sizebuf), " (" LLF " byte%s)",
2008 (LLT)size, PLURAL(size));
2009 else
2010 sizebuf[0] = '\0';
2011 if (pdata >= 0) {
2012 struct sockinet from;
2013 int s;
2014 socklen_t fromlen = sizeof(from.su_len);
2015
2016 (void) alarm(curclass.timeout);
2017 s = accept(pdata, (struct sockaddr *)&from.si_su, &fromlen);
2018 (void) alarm(0);
2019 if (s < 0) {
2020 reply(425, "Can't open data connection.");
2021 (void) close(pdata);
2022 pdata = -1;
2023 return (NULL);
2024 }
2025 (void) close(pdata);
2026 pdata = s;
2027 switch (from.su_family) {
2028 case AF_INET:
2029 #ifdef IP_TOS
2030 if (!mapped) {
2031 tos = IPTOS_THROUGHPUT;
2032 (void) setsockopt(s, IPPROTO_IP, IP_TOS,
2033 (char *)&tos, sizeof(int));
2034 }
2035 break;
2036 #endif
2037 }
2038 /* Set keepalives on the socket to detect dropped conns. */
2039 #ifdef SO_KEEPALIVE
2040 keepalive = 1;
2041 (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
2042 (char *)&keepalive, sizeof(int));
2043 #endif
2044 reply(150, "Opening %s mode data connection for '%s'%s.",
2045 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
2046 return (fdopen(pdata, fmode));
2047 }
2048 if (data >= 0) {
2049 reply(125, "Using existing data connection for '%s'%s.",
2050 name, sizebuf);
2051 usedefault = 1;
2052 return (fdopen(data, fmode));
2053 }
2054 if (usedefault)
2055 data_dest = his_addr;
2056 usedefault = 1;
2057 retry = conerrno = 0;
2058 do {
2059 file = getdatasock(fmode);
2060 if (file == NULL) {
2061 char hbuf[NI_MAXHOST];
2062 char pbuf[NI_MAXSERV];
2063 conerrno = errno;
2064 if (getnameinfo((struct sockaddr *)&data_source.si_su,
2065 data_source.su_len, hbuf, sizeof(hbuf), pbuf,
2066 sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV))
2067 strlcpy(hbuf, "?", sizeof(hbuf));
2068 reply(425, "Can't create data socket (%s,%s): %s.",
2069 hbuf, pbuf, strerror(conerrno));
2070 return (NULL);
2071 }
2072 data = fileno(file);
2073 conerrno = 0;
2074 if (connect(data, (struct sockaddr *)&data_dest.si_su,
2075 data_dest.su_len) == 0)
2076 break;
2077 conerrno = errno;
2078 (void) fclose(file);
2079 file = NULL;
2080 data = -1;
2081 if (conerrno == EADDRINUSE) {
2082 sleep((unsigned) swaitint);
2083 retry += swaitint;
2084 } else {
2085 break;
2086 }
2087 } while (retry <= swaitmax);
2088 if (conerrno != 0) {
2089 perror_reply(425, "Can't build data connection");
2090 return (NULL);
2091 }
2092 reply(150, "Opening %s mode data connection for '%s'%s.",
2093 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
2094 return (file);
2095 }
2096
2097 void
closedataconn(FILE * fd)2098 closedataconn(FILE *fd)
2099 {
2100
2101 if (fd == NULL)
2102 return;
2103 (void)fclose(fd);
2104 data = -1;
2105 if (pdata >= 0)
2106 (void)close(pdata);
2107 pdata = -1;
2108 }
2109
2110 int
write_data(int fd,char * buf,size_t size,off_t * bufrem,struct timeval * then,int isdata)2111 write_data(int fd, char *buf, size_t size, off_t *bufrem,
2112 struct timeval *then, int isdata)
2113 {
2114 struct timeval now, td;
2115 ssize_t c;
2116
2117 while (size > 0) {
2118 c = size;
2119 if (curclass.writesize) {
2120 if (curclass.writesize < c)
2121 c = curclass.writesize;
2122 }
2123 if (curclass.rateget) {
2124 if (*bufrem < c)
2125 c = *bufrem;
2126 }
2127 (void) alarm(curclass.timeout);
2128 c = write(fd, buf, c);
2129 if (c <= 0)
2130 return (1);
2131 buf += c;
2132 size -= c;
2133 byte_count += c;
2134 if (isdata) {
2135 total_data_out += c;
2136 total_data += c;
2137 }
2138 total_bytes_out += c;
2139 total_bytes += c;
2140 if (curclass.rateget) {
2141 *bufrem -= c;
2142 if (*bufrem == 0) {
2143 (void)gettimeofday(&now, NULL);
2144 timersub(&now, then, &td);
2145 if (td.tv_sec == 0) {
2146 usleep(1000000 - td.tv_usec);
2147 (void)gettimeofday(then, NULL);
2148 } else
2149 *then = now;
2150 *bufrem = curclass.rateget;
2151 }
2152 }
2153 }
2154 return (0);
2155 }
2156
2157 static enum send_status
send_data_with_read(int filefd,int netfd,const struct stat * st,int isdata)2158 send_data_with_read(int filefd, int netfd, const struct stat *st, int isdata)
2159 {
2160 struct timeval then;
2161 off_t bufrem;
2162 ssize_t readsize;
2163 char *buf;
2164 int c, error;
2165
2166 if (curclass.readsize > 0)
2167 readsize = curclass.readsize;
2168 else
2169 readsize = st->st_blksize;
2170 if ((buf = malloc(readsize)) == NULL) {
2171 perror_reply(451, "Local resource failure: malloc");
2172 return (SS_NO_TRANSFER);
2173 }
2174
2175 if (curclass.rateget) {
2176 bufrem = curclass.rateget;
2177 (void)gettimeofday(&then, NULL);
2178 } else
2179 bufrem = readsize;
2180 for (;;) {
2181 (void) alarm(curclass.timeout);
2182 c = read(filefd, buf, readsize);
2183 if (c == 0)
2184 error = SS_SUCCESS;
2185 else if (c < 0)
2186 error = SS_FILE_ERROR;
2187 else if (write_data(netfd, buf, c, &bufrem, &then, isdata))
2188 error = SS_DATA_ERROR;
2189 else if (urgflag && handleoobcmd())
2190 error = SS_ABORTED;
2191 else
2192 continue;
2193
2194 free(buf);
2195 return (error);
2196 }
2197 }
2198
2199 static enum send_status
send_data_with_mmap(int filefd,int netfd,const struct stat * st,int isdata)2200 send_data_with_mmap(int filefd, int netfd, const struct stat *st, int isdata)
2201 {
2202 struct timeval then;
2203 off_t bufrem, filesize, off, origoff;
2204 ssize_t mapsize, winsize;
2205 int error, sendbufsize, sendlowat;
2206 void *win;
2207
2208 bufrem = 0;
2209 if (curclass.sendbufsize) {
2210 sendbufsize = curclass.sendbufsize;
2211 if (setsockopt(netfd, SOL_SOCKET, SO_SNDBUF,
2212 &sendbufsize, sizeof(int)) == -1)
2213 syslog(LOG_WARNING, "setsockopt(SO_SNDBUF, %d): %m",
2214 sendbufsize);
2215 }
2216
2217 if (curclass.sendlowat) {
2218 sendlowat = curclass.sendlowat;
2219 if (setsockopt(netfd, SOL_SOCKET, SO_SNDLOWAT,
2220 &sendlowat, sizeof(int)) == -1)
2221 syslog(LOG_WARNING, "setsockopt(SO_SNDLOWAT, %d): %m",
2222 sendlowat);
2223 }
2224
2225 winsize = curclass.mmapsize;
2226 filesize = st->st_size;
2227 if (ftpd_debug)
2228 syslog(LOG_INFO, "mmapsize = " LLF ", writesize = " LLF,
2229 (LLT)winsize, (LLT)curclass.writesize);
2230 if (winsize <= 0)
2231 goto try_read;
2232
2233 off = lseek(filefd, (off_t)0, SEEK_CUR);
2234 if (off == -1)
2235 goto try_read;
2236
2237 origoff = off;
2238 if (curclass.rateget) {
2239 bufrem = curclass.rateget;
2240 (void)gettimeofday(&then, NULL);
2241 } else
2242 bufrem = winsize;
2243 while (1) {
2244 mapsize = MIN(filesize - off, winsize);
2245 if (mapsize == 0)
2246 break;
2247 win = mmap(NULL, mapsize, PROT_READ,
2248 MAP_FILE|MAP_SHARED, filefd, off);
2249 if (win == MAP_FAILED) {
2250 if (off == origoff)
2251 goto try_read;
2252 return (SS_FILE_ERROR);
2253 }
2254 (void) madvise(win, mapsize, MADV_SEQUENTIAL);
2255 error = write_data(netfd, win, mapsize, &bufrem, &then,
2256 isdata);
2257 (void) madvise(win, mapsize, MADV_DONTNEED);
2258 munmap(win, mapsize);
2259 if (urgflag && handleoobcmd())
2260 return (SS_ABORTED);
2261 if (error)
2262 return (SS_DATA_ERROR);
2263 off += mapsize;
2264 }
2265 return (SS_SUCCESS);
2266
2267 try_read:
2268 return (send_data_with_read(filefd, netfd, st, isdata));
2269 }
2270
2271 /*
2272 * Transfer the contents of "instr" to "outstr" peer using the appropriate
2273 * encapsulation of the data subject to Mode, Structure, and Type.
2274 *
2275 * NB: Form isn't handled.
2276 */
2277 static int
send_data(FILE * instr,FILE * outstr,const struct stat * st,int isdata)2278 send_data(FILE *instr, FILE *outstr, const struct stat *st, int isdata)
2279 {
2280 int c, filefd, netfd, rval;
2281
2282 urgflag = 0;
2283 transflag = 1;
2284 rval = -1;
2285
2286 switch (type) {
2287
2288 case TYPE_A:
2289 /* XXXLUKEM: rate limit ascii send (get) */
2290 (void) alarm(curclass.timeout);
2291 while ((c = getc(instr)) != EOF) {
2292 if (urgflag && handleoobcmd())
2293 goto cleanup_send_data;
2294 byte_count++;
2295 if (c == '\n') {
2296 if (ferror(outstr))
2297 goto data_err;
2298 (void) putc('\r', outstr);
2299 if (isdata) {
2300 total_data_out++;
2301 total_data++;
2302 }
2303 total_bytes_out++;
2304 total_bytes++;
2305 }
2306 (void) putc(c, outstr);
2307 if (isdata) {
2308 total_data_out++;
2309 total_data++;
2310 }
2311 total_bytes_out++;
2312 total_bytes++;
2313 if ((byte_count % 4096) == 0)
2314 (void) alarm(curclass.timeout);
2315 }
2316 (void) alarm(0);
2317 fflush(outstr);
2318 if (ferror(instr))
2319 goto file_err;
2320 if (ferror(outstr))
2321 goto data_err;
2322 rval = 0;
2323 goto cleanup_send_data;
2324
2325 case TYPE_I:
2326 case TYPE_L:
2327 filefd = fileno(instr);
2328 netfd = fileno(outstr);
2329 switch (send_data_with_mmap(filefd, netfd, st, isdata)) {
2330
2331 case SS_SUCCESS:
2332 break;
2333
2334 case SS_ABORTED:
2335 case SS_NO_TRANSFER:
2336 goto cleanup_send_data;
2337
2338 case SS_FILE_ERROR:
2339 goto file_err;
2340
2341 case SS_DATA_ERROR:
2342 goto data_err;
2343 }
2344 rval = 0;
2345 goto cleanup_send_data;
2346
2347 default:
2348 reply(550, "Unimplemented TYPE %d in send_data", type);
2349 goto cleanup_send_data;
2350 }
2351
2352 data_err:
2353 (void) alarm(0);
2354 perror_reply(426, "Data connection");
2355 goto cleanup_send_data;
2356
2357 file_err:
2358 (void) alarm(0);
2359 perror_reply(551, "Error on input file");
2360 goto cleanup_send_data;
2361
2362 cleanup_send_data:
2363 (void) alarm(0);
2364 transflag = 0;
2365 urgflag = 0;
2366 if (isdata) {
2367 total_files_out++;
2368 total_files++;
2369 }
2370 total_xfers_out++;
2371 total_xfers++;
2372 return (rval);
2373 }
2374
2375 /*
2376 * Transfer data from peer to "outstr" using the appropriate encapulation of
2377 * the data subject to Mode, Structure, and Type.
2378 *
2379 * N.B.: Form isn't handled.
2380 */
2381 static int
receive_data(FILE * instr,FILE * outstr)2382 receive_data(FILE *instr, FILE *outstr)
2383 {
2384 int c, netfd, filefd, rval;
2385 int volatile bare_lfs;
2386 off_t byteswritten;
2387 char *buf;
2388 ssize_t readsize;
2389 struct sigaction sa, sa_saved;
2390 struct stat st;
2391
2392 memset(&sa, 0, sizeof(sa));
2393 sigfillset(&sa.sa_mask);
2394 sa.sa_flags = SA_RESTART;
2395 sa.sa_handler = lostconn;
2396 (void) sigaction(SIGALRM, &sa, &sa_saved);
2397
2398 bare_lfs = 0;
2399 urgflag = 0;
2400 transflag = 1;
2401 rval = -1;
2402 byteswritten = 0;
2403 buf = NULL;
2404
2405 #define FILESIZECHECK(x) \
2406 do { \
2407 if (curclass.maxfilesize != -1 && \
2408 (x) > curclass.maxfilesize) { \
2409 errno = EFBIG; \
2410 goto file_err; \
2411 } \
2412 } while (0)
2413
2414 switch (type) {
2415
2416 case TYPE_I:
2417 case TYPE_L:
2418 netfd = fileno(instr);
2419 filefd = fileno(outstr);
2420 (void) alarm(curclass.timeout);
2421 if (curclass.readsize)
2422 readsize = curclass.readsize;
2423 else if (fstat(filefd, &st) != -1)
2424 readsize = (ssize_t)st.st_blksize;
2425 else
2426 readsize = BUFSIZ;
2427 if ((buf = malloc(readsize)) == NULL) {
2428 perror_reply(451, "Local resource failure: malloc");
2429 goto cleanup_recv_data;
2430 }
2431 if (curclass.rateput) {
2432 while (1) {
2433 int d;
2434 struct timeval then, now, td;
2435 off_t bufrem;
2436
2437 (void)gettimeofday(&then, NULL);
2438 errno = c = d = 0;
2439 for (bufrem = curclass.rateput; bufrem > 0; ) {
2440 if ((c = read(netfd, buf,
2441 MIN(readsize, bufrem))) <= 0)
2442 goto recvdone;
2443 if (urgflag && handleoobcmd())
2444 goto cleanup_recv_data;
2445 FILESIZECHECK(byte_count + c);
2446 if ((d = write(filefd, buf, c)) != c)
2447 goto file_err;
2448 (void) alarm(curclass.timeout);
2449 bufrem -= c;
2450 byte_count += c;
2451 total_data_in += c;
2452 total_data += c;
2453 total_bytes_in += c;
2454 total_bytes += c;
2455 }
2456 (void)gettimeofday(&now, NULL);
2457 timersub(&now, &then, &td);
2458 if (td.tv_sec == 0)
2459 usleep(1000000 - td.tv_usec);
2460 }
2461 } else {
2462 while ((c = read(netfd, buf, readsize)) > 0) {
2463 if (urgflag && handleoobcmd())
2464 goto cleanup_recv_data;
2465 FILESIZECHECK(byte_count + c);
2466 if (write(filefd, buf, c) != c)
2467 goto file_err;
2468 (void) alarm(curclass.timeout);
2469 byte_count += c;
2470 total_data_in += c;
2471 total_data += c;
2472 total_bytes_in += c;
2473 total_bytes += c;
2474 }
2475 }
2476 recvdone:
2477 if (c < 0)
2478 goto data_err;
2479 rval = 0;
2480 goto cleanup_recv_data;
2481
2482 case TYPE_E:
2483 reply(553, "TYPE E not implemented.");
2484 goto cleanup_recv_data;
2485
2486 case TYPE_A:
2487 (void) alarm(curclass.timeout);
2488 /* XXXLUKEM: rate limit ascii receive (put) */
2489 while ((c = getc(instr)) != EOF) {
2490 if (urgflag && handleoobcmd())
2491 goto cleanup_recv_data;
2492 byte_count++;
2493 total_data_in++;
2494 total_data++;
2495 total_bytes_in++;
2496 total_bytes++;
2497 if ((byte_count % 4096) == 0)
2498 (void) alarm(curclass.timeout);
2499 if (c == '\n')
2500 bare_lfs++;
2501 while (c == '\r') {
2502 if (ferror(outstr))
2503 goto data_err;
2504 if ((c = getc(instr)) != '\n') {
2505 byte_count++;
2506 total_data_in++;
2507 total_data++;
2508 total_bytes_in++;
2509 total_bytes++;
2510 if ((byte_count % 4096) == 0)
2511 (void) alarm(curclass.timeout);
2512 byteswritten++;
2513 FILESIZECHECK(byteswritten);
2514 (void) putc ('\r', outstr);
2515 if (c == '\0' || c == EOF)
2516 goto contin2;
2517 }
2518 }
2519 byteswritten++;
2520 FILESIZECHECK(byteswritten);
2521 (void) putc(c, outstr);
2522 contin2: ;
2523 }
2524 (void) alarm(0);
2525 fflush(outstr);
2526 if (ferror(instr))
2527 goto data_err;
2528 if (ferror(outstr))
2529 goto file_err;
2530 if (bare_lfs) {
2531 reply(-226,
2532 "WARNING! %d bare linefeeds received in ASCII mode",
2533 bare_lfs);
2534 reply(0, "File may not have transferred correctly.");
2535 }
2536 rval = 0;
2537 goto cleanup_recv_data;
2538
2539 default:
2540 reply(550, "Unimplemented TYPE %d in receive_data", type);
2541 goto cleanup_recv_data;
2542 }
2543 #undef FILESIZECHECK
2544
2545 data_err:
2546 (void) alarm(0);
2547 perror_reply(426, "Data Connection");
2548 goto cleanup_recv_data;
2549
2550 file_err:
2551 (void) alarm(0);
2552 perror_reply(452, "Error writing file");
2553 goto cleanup_recv_data;
2554
2555 cleanup_recv_data:
2556 (void) alarm(0);
2557 (void) sigaction(SIGALRM, &sa_saved, NULL);
2558 if (buf)
2559 free(buf);
2560 transflag = 0;
2561 urgflag = 0;
2562 total_files_in++;
2563 total_files++;
2564 total_xfers_in++;
2565 total_xfers++;
2566 return (rval);
2567 }
2568
2569 void
statcmd(void)2570 statcmd(void)
2571 {
2572 struct sockinet *su = NULL;
2573 static char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
2574 unsigned char *a, *p;
2575 int ispassive, af;
2576 off_t otbi, otbo, otb;
2577
2578 a = p = NULL;
2579
2580 reply(-211, "%s FTP server status:", hostname);
2581 reply(0, "Version: %s", EMPTYSTR(version) ? "<suppressed>" : version);
2582 hbuf[0] = '\0';
2583 if (!getnameinfo((struct sockaddr *)&his_addr.si_su, his_addr.su_len,
2584 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)
2585 && strcmp(remotehost, hbuf) != 0)
2586 reply(0, "Connected to %s (%s)", remotehost, hbuf);
2587 else
2588 reply(0, "Connected to %s", remotehost);
2589
2590 if (logged_in) {
2591 if (curclass.type == CLASS_GUEST)
2592 reply(0, "Logged in anonymously");
2593 else
2594 reply(0, "Logged in as %s%s", pw->pw_name,
2595 curclass.type == CLASS_CHROOT ? " (chroot)" : "");
2596 } else if (askpasswd)
2597 reply(0, "Waiting for password");
2598 else
2599 reply(0, "Waiting for user name");
2600 cprintf(stdout, " TYPE: %s", typenames[type]);
2601 if (type == TYPE_A || type == TYPE_E)
2602 cprintf(stdout, ", FORM: %s", formnames[form]);
2603 if (type == TYPE_L) {
2604 #if NBBY == 8
2605 cprintf(stdout, " %d", NBBY);
2606 #else
2607 /* XXX: `bytesize' needs to be defined in this case */
2608 cprintf(stdout, " %d", bytesize);
2609 #endif
2610 }
2611 cprintf(stdout, "; STRUcture: %s; transfer MODE: %s\r\n",
2612 strunames[stru], modenames[mode]);
2613 ispassive = 0;
2614 if (data != -1) {
2615 reply(0, "Data connection open");
2616 su = NULL;
2617 } else if (pdata != -1) {
2618 reply(0, "in Passive mode");
2619 if (curclass.advertise.su_len != 0)
2620 su = &curclass.advertise;
2621 else
2622 su = &pasv_addr;
2623 ispassive = 1;
2624 goto printaddr;
2625 } else if (usedefault == 0) {
2626 su = (struct sockinet *)&data_dest;
2627
2628 if (epsvall) {
2629 reply(0, "EPSV only mode (EPSV ALL)");
2630 goto epsvonly;
2631 }
2632 printaddr:
2633 /* PASV/PORT */
2634 if (su->su_family == AF_INET) {
2635 a = (unsigned char *) &su->su_addr;
2636 p = (unsigned char *) &su->su_port;
2637 #define UC(b) (((int) b) & 0xff)
2638 reply(0, "%s (%d,%d,%d,%d,%d,%d)",
2639 ispassive ? "PASV" : "PORT" ,
2640 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2641 UC(p[0]), UC(p[1]));
2642 }
2643
2644 /* LPSV/LPRT */
2645 {
2646 int alen, i;
2647
2648 alen = 0;
2649 switch (su->su_family) {
2650 case AF_INET:
2651 a = (unsigned char *) &su->su_addr;
2652 p = (unsigned char *) &su->su_port;
2653 alen = sizeof(su->su_addr);
2654 af = 4;
2655 break;
2656 #ifdef INET6
2657 case AF_INET6:
2658 a = (unsigned char *) &su->su_6addr;
2659 p = (unsigned char *) &su->su_port;
2660 alen = sizeof(su->su_6addr);
2661 af = 6;
2662 break;
2663 #endif
2664 default:
2665 af = 0;
2666 break;
2667 }
2668 if (af) {
2669 cprintf(stdout, " %s (%d,%d",
2670 ispassive ? "LPSV" : "LPRT", af, alen);
2671 for (i = 0; i < alen; i++)
2672 cprintf(stdout, ",%d", UC(a[i]));
2673 cprintf(stdout, ",%d,%d,%d)\r\n",
2674 2, UC(p[0]), UC(p[1]));
2675 #undef UC
2676 }
2677 }
2678
2679 /* EPRT/EPSV */
2680 epsvonly:
2681 af = af2epsvproto(su->su_family);
2682 hbuf[0] = '\0';
2683 if (af > 0) {
2684 struct sockinet tmp;
2685
2686 tmp = *su;
2687 #ifdef INET6
2688 if (tmp.su_family == AF_INET6)
2689 tmp.su_scope_id = 0;
2690 #endif
2691 if (getnameinfo((struct sockaddr *)&tmp.si_su,
2692 tmp.su_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
2693 NI_NUMERICHOST | NI_NUMERICSERV) == 0)
2694 reply(0, "%s (|%d|%s|%s|)",
2695 ispassive ? "EPSV" : "EPRT",
2696 af, hbuf, sbuf);
2697 }
2698 } else
2699 reply(0, "No data connection");
2700
2701 if (logged_in) {
2702 reply(0,
2703 "Data sent: " LLF " byte%s in " LLF " file%s",
2704 (LLT)total_data_out, PLURAL(total_data_out),
2705 (LLT)total_files_out, PLURAL(total_files_out));
2706 reply(0,
2707 "Data received: " LLF " byte%s in " LLF " file%s",
2708 (LLT)total_data_in, PLURAL(total_data_in),
2709 (LLT)total_files_in, PLURAL(total_files_in));
2710 reply(0,
2711 "Total data: " LLF " byte%s in " LLF " file%s",
2712 (LLT)total_data, PLURAL(total_data),
2713 (LLT)total_files, PLURAL(total_files));
2714 }
2715 otbi = total_bytes_in;
2716 otbo = total_bytes_out;
2717 otb = total_bytes;
2718 reply(0, "Traffic sent: " LLF " byte%s in " LLF " transfer%s",
2719 (LLT)otbo, PLURAL(otbo),
2720 (LLT)total_xfers_out, PLURAL(total_xfers_out));
2721 reply(0, "Traffic received: " LLF " byte%s in " LLF " transfer%s",
2722 (LLT)otbi, PLURAL(otbi),
2723 (LLT)total_xfers_in, PLURAL(total_xfers_in));
2724 reply(0, "Total traffic: " LLF " byte%s in " LLF " transfer%s",
2725 (LLT)otb, PLURAL(otb),
2726 (LLT)total_xfers, PLURAL(total_xfers));
2727
2728 if (logged_in && !CURCLASS_FLAGS_ISSET(private)) {
2729 struct ftpconv *cp;
2730
2731 reply(0, "%s", "");
2732 reply(0, "Class: %s, type: %s",
2733 curclass.classname, CURCLASSTYPE);
2734 reply(0, "Check PORT/LPRT commands: %sabled",
2735 CURCLASS_FLAGS_ISSET(checkportcmd) ? "en" : "dis");
2736 if (! EMPTYSTR(curclass.display))
2737 reply(0, "Display file: %s", curclass.display);
2738 if (! EMPTYSTR(curclass.notify))
2739 reply(0, "Notify fileglob: %s", curclass.notify);
2740 reply(0, "Idle timeout: " LLF ", maximum timeout: " LLF,
2741 (LLT)curclass.timeout, (LLT)curclass.maxtimeout);
2742 reply(0, "Current connections: %d", connections);
2743 if (curclass.limit == -1)
2744 reply(0, "Maximum connections: unlimited");
2745 else
2746 reply(0, "Maximum connections: " LLF,
2747 (LLT)curclass.limit);
2748 if (curclass.limitfile)
2749 reply(0, "Connection limit exceeded message file: %s",
2750 conffilename(curclass.limitfile));
2751 if (! EMPTYSTR(curclass.chroot))
2752 reply(0, "Chroot format: %s", curclass.chroot);
2753 reply(0, "Deny bad ftpusers(5) quickly: %sabled",
2754 CURCLASS_FLAGS_ISSET(denyquick) ? "en" : "dis");
2755 if (! EMPTYSTR(curclass.homedir))
2756 reply(0, "Homedir format: %s", curclass.homedir);
2757 if (curclass.maxfilesize == -1)
2758 reply(0, "Maximum file size: unlimited");
2759 else
2760 reply(0, "Maximum file size: " LLF,
2761 (LLT)curclass.maxfilesize);
2762 if (! EMPTYSTR(curclass.motd))
2763 reply(0, "MotD file: %s", conffilename(curclass.motd));
2764 reply(0,
2765 "Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled",
2766 CURCLASS_FLAGS_ISSET(modify) ? "en" : "dis");
2767 reply(0, "Upload commands (APPE, STOR, STOU): %sabled",
2768 CURCLASS_FLAGS_ISSET(upload) ? "en" : "dis");
2769 reply(0, "Sanitize file names: %sabled",
2770 CURCLASS_FLAGS_ISSET(sanenames) ? "en" : "dis");
2771 reply(0, "PASV/LPSV/EPSV connections: %sabled",
2772 CURCLASS_FLAGS_ISSET(passive) ? "en" : "dis");
2773 if (curclass.advertise.su_len != 0) {
2774 char buf[50]; /* big enough for IPv6 address */
2775 const char *bp;
2776
2777 bp = inet_ntop(curclass.advertise.su_family,
2778 (void *)&curclass.advertise.su_addr,
2779 buf, sizeof(buf));
2780 if (bp != NULL)
2781 reply(0, "PASV advertise address: %s", bp);
2782 }
2783 if (curclass.portmin && curclass.portmax)
2784 reply(0, "PASV port range: " LLF " - " LLF,
2785 (LLT)curclass.portmin, (LLT)curclass.portmax);
2786 if (curclass.rateget)
2787 reply(0, "Rate get limit: " LLF " bytes/sec",
2788 (LLT)curclass.rateget);
2789 else
2790 reply(0, "Rate get limit: disabled");
2791 if (curclass.rateput)
2792 reply(0, "Rate put limit: " LLF " bytes/sec",
2793 (LLT)curclass.rateput);
2794 else
2795 reply(0, "Rate put limit: disabled");
2796 if (curclass.mmapsize)
2797 reply(0, "Mmap size: " LLF, (LLT)curclass.mmapsize);
2798 else
2799 reply(0, "Mmap size: disabled");
2800 if (curclass.readsize)
2801 reply(0, "Read size: " LLF, (LLT)curclass.readsize);
2802 else
2803 reply(0, "Read size: default");
2804 if (curclass.writesize)
2805 reply(0, "Write size: " LLF, (LLT)curclass.writesize);
2806 else
2807 reply(0, "Write size: default");
2808 if (curclass.recvbufsize)
2809 reply(0, "Receive buffer size: " LLF,
2810 (LLT)curclass.recvbufsize);
2811 else
2812 reply(0, "Receive buffer size: default");
2813 if (curclass.sendbufsize)
2814 reply(0, "Send buffer size: " LLF,
2815 (LLT)curclass.sendbufsize);
2816 else
2817 reply(0, "Send buffer size: default");
2818 if (curclass.sendlowat)
2819 reply(0, "Send low water mark: " LLF,
2820 (LLT)curclass.sendlowat);
2821 else
2822 reply(0, "Send low water mark: default");
2823 reply(0, "Umask: %.04o", curclass.umask);
2824 for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
2825 if (cp->suffix == NULL || cp->types == NULL ||
2826 cp->command == NULL)
2827 continue;
2828 reply(0, "Conversion: %s [%s] disable: %s, command: %s",
2829 cp->suffix, cp->types, cp->disable, cp->command);
2830 }
2831 }
2832
2833 reply(211, "End of status");
2834 }
2835
2836 void
fatal(const char * s)2837 fatal(const char *s)
2838 {
2839
2840 reply(451, "Error in server: %s\n", s);
2841 reply(221, "Closing connection due to server error.");
2842 dologout(0);
2843 /* NOTREACHED */
2844 }
2845
2846 /*
2847 * reply() --
2848 * depending on the value of n, display fmt with a trailing CRLF and
2849 * prefix of:
2850 * n < -1 prefix the message with abs(n) + "-" (initial line)
2851 * n == 0 prefix the message with 4 spaces (middle lines)
2852 * n > 0 prefix the message with n + " " (final line)
2853 */
2854 void
reply(int n,const char * fmt,...)2855 reply(int n, const char *fmt, ...)
2856 {
2857 char msg[MAXPATHLEN * 2 + 100];
2858 size_t b;
2859 va_list ap;
2860
2861 if (n == 0)
2862 b = snprintf(msg, sizeof(msg), " ");
2863 else if (n < 0)
2864 b = snprintf(msg, sizeof(msg), "%d-", -n);
2865 else
2866 b = snprintf(msg, sizeof(msg), "%d ", n);
2867 va_start(ap, fmt);
2868 vsnprintf(msg + b, sizeof(msg) - b, fmt, ap);
2869 va_end(ap);
2870 cprintf(stdout, "%s\r\n", msg);
2871 (void)fflush(stdout);
2872 if (ftpd_debug)
2873 syslog(LOG_DEBUG, "<--- %s", msg);
2874 }
2875
2876 static void
logremotehost(struct sockinet * who)2877 logremotehost(struct sockinet *who)
2878 {
2879
2880 #if defined(HAVE_SOCKADDR_SNPRINTF)
2881 char abuf[MAXHOSTNAMELEN];
2882 #endif
2883
2884 struct sockaddr *sa = (struct sockaddr *)&who->si_su;
2885 if (getnameinfo(sa, who->su_len, remotehost, sizeof(remotehost), NULL,
2886 0, getnameopts))
2887 strlcpy(remotehost, "?", sizeof(remotehost));
2888 #if defined(HAVE_SOCKADDR_SNPRINTF)
2889 sockaddr_snprintf(abuf, sizeof(abuf), "%a", sa);
2890 snprintf(remoteloghost, sizeof(remoteloghost), "%s(%s)", remotehost,
2891 abuf);
2892 #else
2893 strlcpy(remoteloghost, remotehost, sizeof(remoteloghost));
2894 #endif
2895
2896 #if defined(HAVE_SETPROCTITLE)
2897 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2898 setproctitle("%s", proctitle);
2899 #endif /* defined(HAVE_SETPROCTITLE) */
2900 if (logging)
2901 syslog(LOG_INFO, "connection from %s to %s",
2902 remoteloghost, hostname);
2903 }
2904
2905 /*
2906 * Record logout in wtmp file and exit with supplied status.
2907 * NOTE: because this is called from signal handlers it cannot
2908 * use stdio (or call other functions that use stdio).
2909 */
2910 void
dologout(int status)2911 dologout(int status)
2912 {
2913 /*
2914 * Prevent reception of SIGURG from resulting in a resumption
2915 * back to the main program loop.
2916 */
2917 transflag = 0;
2918 logout_utmp();
2919 if (logged_in) {
2920 #ifdef KERBEROS
2921 if (!notickets && krbtkfile_env)
2922 unlink(krbtkfile_env);
2923 #endif
2924 }
2925 /* beware of flushing buffers after a SIGPIPE */
2926 if (xferlogfd != -1)
2927 close(xferlogfd);
2928 _exit(status);
2929 }
2930
2931 void
abor(void)2932 abor(void)
2933 {
2934
2935 if (!transflag)
2936 return;
2937 tmpline[0] = '\0';
2938 is_oob = 0;
2939 reply(426, "Transfer aborted. Data connection closed.");
2940 reply(226, "Abort successful");
2941 transflag = 0; /* flag that the transfer has aborted */
2942 }
2943
2944 void
statxfer(void)2945 statxfer(void)
2946 {
2947
2948 if (!transflag)
2949 return;
2950 tmpline[0] = '\0';
2951 is_oob = 0;
2952 if (file_size != (off_t) -1)
2953 reply(213,
2954 "Status: " LLF " of " LLF " byte%s transferred",
2955 (LLT)byte_count, (LLT)file_size,
2956 PLURAL(byte_count));
2957 else
2958 reply(213, "Status: " LLF " byte%s transferred",
2959 (LLT)byte_count, PLURAL(byte_count));
2960 }
2961
2962 /*
2963 * Call when urgflag != 0 to handle Out Of Band commands.
2964 * Returns non zero if the OOB command aborted the transfer
2965 * by setting transflag to 0. (c.f., "ABOR").
2966 */
2967 static int
handleoobcmd(void)2968 handleoobcmd(void)
2969 {
2970 char *cp;
2971 int ret;
2972
2973 if (!urgflag)
2974 return (0);
2975 urgflag = 0;
2976 /* only process if transfer occurring */
2977 if (!transflag)
2978 return (0);
2979 cp = tmpline;
2980 ret = get_line(cp, sizeof(tmpline)-1, stdin);
2981 if (ret == -1) {
2982 reply(221, "You could at least say goodbye.");
2983 dologout(0);
2984 } else if (ret == -2) {
2985 /* Ignore truncated command */
2986 /* XXX: abort xfer with "500 command too long", & return 1 ? */
2987 return 0;
2988 }
2989 /*
2990 * Manually parse OOB commands, because we can't
2991 * recursively call the yacc parser...
2992 */
2993 if (strcasecmp(cp, "ABOR\r\n") == 0) {
2994 abor();
2995 } else if (strcasecmp(cp, "STAT\r\n") == 0) {
2996 statxfer();
2997 } else {
2998 /* XXX: error with "500 unknown command" ? */
2999 }
3000 return (transflag == 0);
3001 }
3002
3003 static int
bind_pasv_addr(void)3004 bind_pasv_addr(void)
3005 {
3006 static int passiveport;
3007 int port, len;
3008
3009 len = pasv_addr.su_len;
3010 if (curclass.portmin == 0 && curclass.portmax == 0) {
3011 pasv_addr.su_port = 0;
3012 return (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len));
3013 }
3014
3015 if (passiveport == 0) {
3016 srand(getpid());
3017 passiveport = rand() % (curclass.portmax - curclass.portmin)
3018 + curclass.portmin;
3019 }
3020
3021 port = passiveport;
3022 while (1) {
3023 port++;
3024 if (port > curclass.portmax)
3025 port = curclass.portmin;
3026 else if (port == passiveport) {
3027 errno = EAGAIN;
3028 return (-1);
3029 }
3030 pasv_addr.su_port = htons(port);
3031 if (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len) == 0)
3032 break;
3033 if (errno != EADDRINUSE)
3034 return (-1);
3035 }
3036 passiveport = port;
3037 return (0);
3038 }
3039
3040 /*
3041 * Note: a response of 425 is not mentioned as a possible response to
3042 * the PASV command in RFC959. However, it has been blessed as
3043 * a legitimate response by Jon Postel in a telephone conversation
3044 * with Rick Adams on 25 Jan 89.
3045 */
3046 void
passive(void)3047 passive(void)
3048 {
3049 socklen_t len;
3050 int recvbufsize;
3051 char *p, *a;
3052
3053 if (pdata >= 0)
3054 close(pdata);
3055 pdata = socket(AF_INET, SOCK_STREAM, 0);
3056 if (pdata < 0 || !logged_in) {
3057 perror_reply(425, "Can't open passive connection");
3058 return;
3059 }
3060 pasv_addr = ctrl_addr;
3061
3062 if (bind_pasv_addr() < 0)
3063 goto pasv_error;
3064 len = pasv_addr.su_len;
3065 if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
3066 goto pasv_error;
3067 pasv_addr.su_len = len;
3068 if (curclass.recvbufsize) {
3069 recvbufsize = curclass.recvbufsize;
3070 if (setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, &recvbufsize,
3071 sizeof(int)) == -1)
3072 syslog(LOG_WARNING, "setsockopt(SO_RCVBUF, %d): %m",
3073 recvbufsize);
3074 }
3075 if (listen(pdata, 1) < 0)
3076 goto pasv_error;
3077 if (curclass.advertise.su_len != 0)
3078 a = (char *) &curclass.advertise.su_addr;
3079 else
3080 a = (char *) &pasv_addr.su_addr;
3081 p = (char *) &pasv_addr.su_port;
3082
3083 #define UC(b) (((int) b) & 0xff)
3084
3085 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
3086 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
3087 return;
3088
3089 pasv_error:
3090 (void) close(pdata);
3091 pdata = -1;
3092 perror_reply(425, "Can't open passive connection");
3093 return;
3094 }
3095
3096 /*
3097 * convert protocol identifier to/from AF
3098 */
3099 int
lpsvproto2af(int proto)3100 lpsvproto2af(int proto)
3101 {
3102
3103 switch (proto) {
3104 case 4:
3105 return AF_INET;
3106 #ifdef INET6
3107 case 6:
3108 return AF_INET6;
3109 #endif
3110 default:
3111 return -1;
3112 }
3113 }
3114
3115 int
af2lpsvproto(int af)3116 af2lpsvproto(int af)
3117 {
3118
3119 switch (af) {
3120 case AF_INET:
3121 return 4;
3122 #ifdef INET6
3123 case AF_INET6:
3124 return 6;
3125 #endif
3126 default:
3127 return -1;
3128 }
3129 }
3130
3131 int
epsvproto2af(int proto)3132 epsvproto2af(int proto)
3133 {
3134
3135 switch (proto) {
3136 case 1:
3137 return AF_INET;
3138 #ifdef INET6
3139 case 2:
3140 return AF_INET6;
3141 #endif
3142 default:
3143 return -1;
3144 }
3145 }
3146
3147 int
af2epsvproto(int af)3148 af2epsvproto(int af)
3149 {
3150
3151 switch (af) {
3152 case AF_INET:
3153 return 1;
3154 #ifdef INET6
3155 case AF_INET6:
3156 return 2;
3157 #endif
3158 default:
3159 return -1;
3160 }
3161 }
3162
3163 /*
3164 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
3165 * 229 Entering Extended Passive Mode (|||port|)
3166 */
3167 void
long_passive(const char * cmd,int pf)3168 long_passive(const char *cmd, int pf)
3169 {
3170 socklen_t len;
3171 char *p, *a;
3172
3173 if (!logged_in) {
3174 syslog(LOG_NOTICE, "long passive but not logged in");
3175 reply(503, "Login with USER first.");
3176 return;
3177 }
3178
3179 if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
3180 /*
3181 * XXX: only EPRT/EPSV ready clients will understand this
3182 */
3183 if (strcmp(cmd, "EPSV") != 0)
3184 reply(501, "Network protocol mismatch"); /*XXX*/
3185 else
3186 epsv_protounsupp("Network protocol mismatch");
3187
3188 return;
3189 }
3190
3191 if (pdata >= 0)
3192 close(pdata);
3193 pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
3194 if (pdata < 0) {
3195 perror_reply(425, "Can't open passive connection");
3196 return;
3197 }
3198 pasv_addr = ctrl_addr;
3199 if (bind_pasv_addr() < 0)
3200 goto pasv_error;
3201 len = pasv_addr.su_len;
3202 if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
3203 goto pasv_error;
3204 pasv_addr.su_len = len;
3205 if (listen(pdata, 1) < 0)
3206 goto pasv_error;
3207 p = (char *) &pasv_addr.su_port;
3208
3209 #define UC(b) (((int) b) & 0xff)
3210
3211 if (strcmp(cmd, "LPSV") == 0) {
3212 struct sockinet *advert;
3213
3214 if (curclass.advertise.su_len != 0)
3215 advert = &curclass.advertise;
3216 else
3217 advert = &pasv_addr;
3218 switch (advert->su_family) {
3219 case AF_INET:
3220 a = (char *) &advert->su_addr;
3221 reply(228,
3222 "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
3223 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
3224 2, UC(p[0]), UC(p[1]));
3225 return;
3226 #ifdef INET6
3227 case AF_INET6:
3228 a = (char *) &advert->su_6addr;
3229 reply(228,
3230 "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
3231 6, 16,
3232 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
3233 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
3234 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
3235 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
3236 2, UC(p[0]), UC(p[1]));
3237 return;
3238 #endif
3239 }
3240 #undef UC
3241 } else if (strcmp(cmd, "EPSV") == 0) {
3242 switch (pasv_addr.su_family) {
3243 case AF_INET:
3244 #ifdef INET6
3245 case AF_INET6:
3246 #endif
3247 reply(229, "Entering Extended Passive Mode (|||%d|)",
3248 ntohs(pasv_addr.su_port));
3249 return;
3250 }
3251 } else {
3252 /* more proper error code? */
3253 }
3254
3255 pasv_error:
3256 (void) close(pdata);
3257 pdata = -1;
3258 perror_reply(425, "Can't open passive connection");
3259 return;
3260 }
3261
3262 int
extended_port(const char * arg)3263 extended_port(const char *arg)
3264 {
3265 char *tmp = NULL;
3266 char *result[3];
3267 char *p, *q;
3268 char delim;
3269 struct addrinfo hints;
3270 struct addrinfo *res = NULL;
3271 int i;
3272 unsigned long proto;
3273
3274 tmp = ftpd_strdup(arg);
3275 p = tmp;
3276 delim = p[0];
3277 p++;
3278 memset(result, 0, sizeof(result));
3279 for (i = 0; i < 3; i++) {
3280 q = strchr(p, delim);
3281 if (!q || *q != delim)
3282 goto parsefail;
3283 *q++ = '\0';
3284 result[i] = p;
3285 p = q;
3286 }
3287
3288 /* some more sanity checks */
3289 errno = 0;
3290 p = NULL;
3291 (void)strtoul(result[2], &p, 10);
3292 if (errno || !*result[2] || *p)
3293 goto parsefail;
3294 errno = 0;
3295 p = NULL;
3296 proto = strtoul(result[0], &p, 10);
3297 if (errno || !*result[0] || *p)
3298 goto protounsupp;
3299
3300 memset(&hints, 0, sizeof(hints));
3301 hints.ai_family = epsvproto2af((int)proto);
3302 if (hints.ai_family < 0)
3303 goto protounsupp;
3304 hints.ai_socktype = SOCK_STREAM;
3305 hints.ai_flags = AI_NUMERICHOST;
3306 if (getaddrinfo(result[1], result[2], &hints, &res))
3307 goto parsefail;
3308 if (res->ai_next)
3309 goto parsefail;
3310 if (sizeof(data_dest) < res->ai_addrlen)
3311 goto parsefail;
3312 memcpy(&data_dest.si_su, res->ai_addr, res->ai_addrlen);
3313 data_dest.su_len = res->ai_addrlen;
3314 #ifdef INET6
3315 if (his_addr.su_family == AF_INET6 &&
3316 data_dest.su_family == AF_INET6) {
3317 /* XXX: more sanity checks! */
3318 data_dest.su_scope_id = his_addr.su_scope_id;
3319 }
3320 #endif
3321
3322 if (tmp != NULL)
3323 free(tmp);
3324 if (res)
3325 freeaddrinfo(res);
3326 return 0;
3327
3328 parsefail:
3329 reply(500, "Invalid argument, rejected.");
3330 usedefault = 1;
3331 if (tmp != NULL)
3332 free(tmp);
3333 if (res)
3334 freeaddrinfo(res);
3335 return -1;
3336
3337 protounsupp:
3338 epsv_protounsupp("Protocol not supported");
3339 usedefault = 1;
3340 if (tmp != NULL)
3341 free(tmp);
3342 return -1;
3343 }
3344
3345 /*
3346 * 522 Protocol not supported (proto,...)
3347 * as we assume address family for control and data connections are the same,
3348 * we do not return the list of address families we support - instead, we
3349 * return the address family of the control connection.
3350 */
3351 void
epsv_protounsupp(const char * message)3352 epsv_protounsupp(const char *message)
3353 {
3354 int proto;
3355
3356 proto = af2epsvproto(ctrl_addr.su_family);
3357 if (proto < 0)
3358 reply(501, "%s", message); /* XXX */
3359 else
3360 reply(522, "%s, use (%d)", message, proto);
3361 }
3362
3363 /*
3364 * Generate unique name for file with basename "local".
3365 * The file named "local" is already known to exist.
3366 * Generates failure reply on error.
3367 *
3368 * XXX: this function should under go changes similar to
3369 * the mktemp(3)/mkstemp(3) changes.
3370 */
3371 static char *
gunique(const char * local)3372 gunique(const char *local)
3373 {
3374 static char new[MAXPATHLEN];
3375 struct stat st;
3376 char *cp;
3377 int count;
3378
3379 cp = strrchr(local, '/');
3380 if (cp)
3381 *cp = '\0';
3382 if (stat(cp ? local : ".", &st) < 0) {
3383 perror_reply(553, cp ? local : ".");
3384 return (NULL);
3385 }
3386 if (cp)
3387 *cp = '/';
3388 for (count = 1; count < 100; count++) {
3389 (void)snprintf(new, sizeof(new) - 1, "%s.%d", local, count);
3390 if (stat(new, &st) < 0)
3391 return (new);
3392 }
3393 reply(452, "Unique file name cannot be created.");
3394 return (NULL);
3395 }
3396
3397 /*
3398 * Format and send reply containing system error number.
3399 */
3400 void
perror_reply(int code,const char * string)3401 perror_reply(int code, const char *string)
3402 {
3403 int save_errno;
3404
3405 save_errno = errno;
3406 reply(code, "%s: %s.", string, strerror(errno));
3407 errno = save_errno;
3408 }
3409
3410 static char *onefile[] = {
3411 NULL,
3412 0
3413 };
3414
3415 void
send_file_list(const char * whichf)3416 send_file_list(const char *whichf)
3417 {
3418 struct stat st;
3419 DIR *dirp;
3420 struct dirent *dir;
3421 FILE *volatile dout;
3422 char **volatile dirlist;
3423 char *dirname, *p;
3424 char *notglob;
3425 int volatile simple;
3426 int volatile freeglob;
3427 glob_t gl;
3428
3429 dirp = NULL;
3430 dout = NULL;
3431 notglob = NULL;
3432 simple = 0;
3433 freeglob = 0;
3434 urgflag = 0;
3435
3436 p = NULL;
3437 if (strpbrk(whichf, "~{[*?") != NULL) {
3438 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
3439
3440 memset(&gl, 0, sizeof(gl));
3441 freeglob = 1;
3442 if (glob(whichf, flags, 0, &gl)) {
3443 reply(450, "Not found");
3444 goto cleanup_send_file_list;
3445 } else if (gl.gl_pathc == 0) {
3446 errno = ENOENT;
3447 perror_reply(450, whichf);
3448 goto cleanup_send_file_list;
3449 }
3450 dirlist = gl.gl_pathv;
3451 } else {
3452 notglob = ftpd_strdup(whichf);
3453 onefile[0] = notglob;
3454 dirlist = onefile;
3455 simple = 1;
3456 }
3457 /* XXX: } for vi sm */
3458
3459 while ((dirname = *dirlist++) != NULL) {
3460 int trailingslash = 0;
3461
3462 if (stat(dirname, &st) < 0) {
3463 /*
3464 * If user typed "ls -l", etc, and the client
3465 * used NLST, do what the user meant.
3466 */
3467 /* XXX: nuke this support? */
3468 if (dirname[0] == '-' && *dirlist == NULL &&
3469 transflag == 0) {
3470 const char *argv[] = { INTERNAL_LS, "", NULL };
3471
3472 argv[1] = dirname;
3473 retrieve(argv, dirname);
3474 goto cleanup_send_file_list;
3475 }
3476 perror_reply(450, whichf);
3477 goto cleanup_send_file_list;
3478 }
3479
3480 if (S_ISREG(st.st_mode)) {
3481 /*
3482 * XXXRFC:
3483 * should we follow RFC959 and not work
3484 * for non directories?
3485 */
3486 if (dout == NULL) {
3487 dout = dataconn("file list", (off_t)-1, "w");
3488 if (dout == NULL)
3489 goto cleanup_send_file_list;
3490 transflag = 1;
3491 }
3492 cprintf(dout, "%s%s\n", dirname,
3493 type == TYPE_A ? "\r" : "");
3494 continue;
3495 } else if (!S_ISDIR(st.st_mode))
3496 continue;
3497
3498 if (dirname[strlen(dirname) - 1] == '/')
3499 trailingslash++;
3500
3501 if ((dirp = opendir(dirname)) == NULL)
3502 continue;
3503
3504 while ((dir = readdir(dirp)) != NULL) {
3505 char nbuf[MAXPATHLEN];
3506
3507 if (urgflag && handleoobcmd()) {
3508 (void) closedir(dirp);
3509 goto cleanup_send_file_list;
3510 }
3511
3512 if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name))
3513 continue;
3514
3515 (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
3516 trailingslash ? "" : "/", dir->d_name);
3517
3518 /*
3519 * We have to do a stat to ensure it's
3520 * not a directory or special file.
3521 */
3522 /*
3523 * XXXRFC:
3524 * should we follow RFC959 and filter out
3525 * non files ? lukem - NO!, or not until
3526 * our ftp client uses MLS{T,D} for completion.
3527 */
3528 if (simple || (stat(nbuf, &st) == 0 &&
3529 S_ISREG(st.st_mode))) {
3530 if (dout == NULL) {
3531 dout = dataconn("file list", (off_t)-1,
3532 "w");
3533 if (dout == NULL) {
3534 (void) closedir(dirp);
3535 goto cleanup_send_file_list;
3536 }
3537 transflag = 1;
3538 }
3539 p = nbuf;
3540 if (nbuf[0] == '.' && nbuf[1] == '/')
3541 p = &nbuf[2];
3542 cprintf(dout, "%s%s\n", p,
3543 type == TYPE_A ? "\r" : "");
3544 }
3545 }
3546 (void) closedir(dirp);
3547 }
3548
3549 if (dout == NULL)
3550 reply(450, "No files found.");
3551 else if (ferror(dout) != 0)
3552 perror_reply(451, "Data connection");
3553 else
3554 reply(226, "Transfer complete.");
3555
3556 cleanup_send_file_list:
3557 closedataconn(dout);
3558 transflag = 0;
3559 urgflag = 0;
3560 total_xfers++;
3561 total_xfers_out++;
3562 if (notglob)
3563 free(notglob);
3564 if (freeglob)
3565 globfree(&gl);
3566 }
3567
3568 char *
conffilename(const char * s)3569 conffilename(const char *s)
3570 {
3571 static char filename[MAXPATHLEN];
3572
3573 if (*s == '/')
3574 strlcpy(filename, s, sizeof(filename));
3575 else
3576 (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
3577 return (filename);
3578 }
3579
3580 /*
3581 * logxfer --
3582 * if logging > 1, then based on the arguments, syslog a message:
3583 * if bytes != -1 "<command> <file1> = <bytes> bytes"
3584 * else if file2 != NULL "<command> <file1> <file2>"
3585 * else "<command> <file1>"
3586 * if elapsed != NULL, append "in xxx.yyy seconds"
3587 * if error != NULL, append ": " + error
3588 *
3589 * if doxferlog != 0, bytes != -1, and command is "get", "put",
3590 * or "append", syslog and/or write a wu-ftpd style xferlog entry
3591 */
3592 void
logxfer(const char * command,off_t bytes,const char * file1,const char * file2,const struct timeval * elapsed,const char * error)3593 logxfer(const char *command, off_t bytes, const char *file1, const char *file2,
3594 const struct timeval *elapsed, const char *error)
3595 {
3596 char buf[MAXPATHLEN * 2 + 100];
3597 char realfile1[MAXPATHLEN], realfile2[MAXPATHLEN];
3598 const char *r1, *r2;
3599 char direction;
3600 size_t len;
3601 time_t now;
3602
3603 if (logging <=1 && !doxferlog)
3604 return;
3605
3606 r1 = r2 = NULL;
3607 if ((r1 = realpath(file1, realfile1)) == NULL)
3608 r1 = file1;
3609 if (file2 != NULL)
3610 if ((r2 = realpath(file2, realfile2)) == NULL)
3611 r2 = file2;
3612
3613 /*
3614 * syslog command
3615 */
3616 if (logging > 1) {
3617 len = snprintf(buf, sizeof(buf), "%s %s", command, r1);
3618 if (bytes != (off_t)-1)
3619 len += snprintf(buf + len, sizeof(buf) - len,
3620 " = " LLF " byte%s", (LLT) bytes, PLURAL(bytes));
3621 else if (r2 != NULL)
3622 len += snprintf(buf + len, sizeof(buf) - len,
3623 " %s", r2);
3624 if (elapsed != NULL)
3625 len += snprintf(buf + len, sizeof(buf) - len,
3626 " in " LLF ".%.03ld seconds",
3627 (LLT)elapsed->tv_sec,
3628 (long)(elapsed->tv_usec / 1000));
3629 if (error != NULL)
3630 len += snprintf(buf + len, sizeof(buf) - len,
3631 ": %s", error);
3632 syslog(LOG_INFO, "%s", buf);
3633 }
3634
3635 /*
3636 * syslog wu-ftpd style log entry, prefixed with "xferlog: "
3637 */
3638 if (!doxferlog || bytes == -1)
3639 return;
3640
3641 if (strcmp(command, "get") == 0)
3642 direction = 'o';
3643 else if (strcmp(command, "put") == 0 || strcmp(command, "append") == 0)
3644 direction = 'i';
3645 else
3646 return;
3647
3648 time(&now);
3649 len = snprintf(buf, sizeof(buf),
3650 "%.24s " LLF " %s " LLF " %s %c %s %c %c %s FTP 0 * %c\n",
3651
3652 /*
3653 * XXX: wu-ftpd puts ' (send)' or ' (recv)' in the syslog message, and removes
3654 * the full date. This may be problematic for accurate log parsing,
3655 * given that syslog messages don't contain the full date.
3656 */
3657 ctime(&now),
3658 (LLT)
3659 (elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0)),
3660 remotehost,
3661 (LLT) bytes,
3662 r1,
3663 type == TYPE_A ? 'a' : 'b',
3664 "_", /* XXX: take conversions into account? */
3665 direction,
3666
3667 curclass.type == CLASS_GUEST ? 'a' :
3668 curclass.type == CLASS_CHROOT ? 'g' :
3669 curclass.type == CLASS_REAL ? 'r' : '?',
3670
3671 curclass.type == CLASS_GUEST ? pw->pw_passwd : pw->pw_name,
3672 error != NULL ? 'i' : 'c'
3673 );
3674
3675 if ((doxferlog & 2) && xferlogfd != -1)
3676 write(xferlogfd, buf, len);
3677 if ((doxferlog & 1)) {
3678 buf[len-1] = '\n'; /* strip \n from syslog message */
3679 syslog(LOG_INFO, "xferlog: %s", buf);
3680 }
3681 }
3682
3683 /*
3684 * Log the resource usage.
3685 *
3686 * XXX: more resource usage to logging?
3687 */
3688 void
logrusage(const struct rusage * rusage_before,const struct rusage * rusage_after)3689 logrusage(const struct rusage *rusage_before,
3690 const struct rusage *rusage_after)
3691 {
3692 struct timeval usrtime, systime;
3693
3694 if (logging <= 1)
3695 return;
3696
3697 timersub(&rusage_after->ru_utime, &rusage_before->ru_utime, &usrtime);
3698 timersub(&rusage_after->ru_stime, &rusage_before->ru_stime, &systime);
3699 syslog(LOG_INFO, LLF ".%.03ldu " LLF ".%.03lds %ld+%ldio %ldpf+%ldw",
3700 (LLT)usrtime.tv_sec, (long)(usrtime.tv_usec / 1000),
3701 (LLT)systime.tv_sec, (long)(systime.tv_usec / 1000),
3702 rusage_after->ru_inblock - rusage_before->ru_inblock,
3703 rusage_after->ru_oublock - rusage_before->ru_oublock,
3704 rusage_after->ru_majflt - rusage_before->ru_majflt,
3705 rusage_after->ru_nswap - rusage_before->ru_nswap);
3706 }
3707
3708 /*
3709 * Determine if `password' is valid for user given in `pw'.
3710 * Returns 2 if password expired, 1 if otherwise failed, 0 if ok
3711 */
3712 int
checkpassword(const struct passwd * pwent,const char * password)3713 checkpassword(const struct passwd *pwent, const char *password)
3714 {
3715 const char *orig;
3716 char *new;
3717 time_t change, expire, now;
3718
3719 change = expire = 0;
3720 if (pwent == NULL)
3721 return 1;
3722
3723 time(&now);
3724 orig = pwent->pw_passwd; /* save existing password */
3725 expire = pwent->pw_expire;
3726 change = pwent->pw_change;
3727 if (change == _PASSWORD_CHGNOW)
3728 change = now;
3729
3730 if (orig[0] == '\0') /* don't allow empty passwords */
3731 return 1;
3732
3733 new = crypt(password, orig); /* encrypt given password */
3734 if (strcmp(new, orig) != 0) /* compare */
3735 return 1;
3736
3737 if ((expire && now >= expire) || (change && now >= change))
3738 return 2; /* check if expired */
3739
3740 return 0; /* OK! */
3741 }
3742
3743 char *
ftpd_strdup(const char * s)3744 ftpd_strdup(const char *s)
3745 {
3746 char *new = strdup(s);
3747
3748 if (new == NULL)
3749 fatal("Local resource failure: malloc");
3750 /* NOTREACHED */
3751 return (new);
3752 }
3753
3754 /*
3755 * As per fprintf(), but increment total_bytes and total_bytes_out,
3756 * by the appropriate amount.
3757 */
3758 void
cprintf(FILE * fd,const char * fmt,...)3759 cprintf(FILE *fd, const char *fmt, ...)
3760 {
3761 off_t b;
3762 va_list ap;
3763
3764 va_start(ap, fmt);
3765 b = vfprintf(fd, fmt, ap);
3766 va_end(ap);
3767 total_bytes += b;
3768 total_bytes_out += b;
3769 }
3770
3771 #ifdef USE_PAM
3772 /*
3773 * the following code is stolen from imap-uw PAM authentication module and
3774 * login.c
3775 */
3776 typedef struct {
3777 const char *uname; /* user name */
3778 int triedonce; /* if non-zero, tried before */
3779 } ftpd_cred_t;
3780
3781 static int
auth_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata)3782 auth_conv(int num_msg, const struct pam_message **msg,
3783 struct pam_response **resp, void *appdata)
3784 {
3785 int i, ret;
3786 size_t n;
3787 ftpd_cred_t *cred = (ftpd_cred_t *) appdata;
3788 struct pam_response *myreply;
3789 char pbuf[FTP_BUFLEN];
3790
3791 if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
3792 return (PAM_CONV_ERR);
3793 myreply = calloc(num_msg, sizeof *myreply);
3794 if (myreply == NULL)
3795 return PAM_BUF_ERR;
3796
3797 for (i = 0; i < num_msg; i++) {
3798 myreply[i].resp_retcode = 0;
3799 myreply[i].resp = NULL;
3800 switch (msg[i]->msg_style) {
3801 case PAM_PROMPT_ECHO_ON: /* user */
3802 myreply[i].resp = ftpd_strdup(cred->uname);
3803 /* PAM frees resp. */
3804 break;
3805 case PAM_PROMPT_ECHO_OFF: /* authtok (password) */
3806 /*
3807 * Only send a single 331 reply and
3808 * then expect a PASS.
3809 */
3810 if (cred->triedonce) {
3811 syslog(LOG_ERR,
3812 "auth_conv: already performed PAM_PROMPT_ECHO_OFF");
3813 goto fail;
3814 }
3815 cred->triedonce++;
3816 if (msg[i]->msg[0] == '\0') {
3817 (void)strlcpy(pbuf, "password", sizeof(pbuf));
3818 } else {
3819 /* Uncapitalize msg */
3820 (void)strlcpy(pbuf, msg[i]->msg, sizeof(pbuf));
3821 if (isupper((unsigned char)pbuf[0]))
3822 pbuf[0] = tolower(
3823 (unsigned char)pbuf[0]);
3824 /* Remove trailing ':' and whitespace */
3825 n = strlen(pbuf);
3826 while (n-- > 0) {
3827 if (isspace((unsigned char)pbuf[n]) ||
3828 pbuf[n] == ':')
3829 pbuf[n] = '\0';
3830 else
3831 break;
3832 }
3833 }
3834 /* Send reply, wait for a response. */
3835 reply(331, "User %s accepted, provide %s.",
3836 cred->uname, pbuf);
3837 (void) alarm(curclass.timeout);
3838 ret = get_line(pbuf, sizeof(pbuf)-1, stdin);
3839 (void) alarm(0);
3840 if (ret == -1) {
3841 reply(221, "You could at least say goodbye.");
3842 dologout(0);
3843 } else if (ret == -2) {
3844 /* XXX: should we do this reply(-530, ..) ? */
3845 reply(-530, "Command too long.");
3846 goto fail;
3847 }
3848 /* Ensure it is PASS */
3849 if (strncasecmp(pbuf, "PASS ", 5) != 0) {
3850 syslog(LOG_ERR,
3851 "auth_conv: unexpected reply '%.4s'", pbuf);
3852 /* XXX: should we do this reply(-530, ..) ? */
3853 reply(-530, "Unexpected reply '%.4s'.", pbuf);
3854 goto fail;
3855 }
3856 /* Strip CRLF from "PASS" reply */
3857 n = strlen(pbuf);
3858 while (--n >= 5 &&
3859 (pbuf[n] == '\r' || pbuf[n] == '\n'))
3860 pbuf[n] = '\0';
3861 /* Copy password into reply */
3862 myreply[i].resp = ftpd_strdup(pbuf+5);
3863 /* PAM frees resp. */
3864 break;
3865 case PAM_TEXT_INFO:
3866 case PAM_ERROR_MSG:
3867 break;
3868 default: /* unknown message style */
3869 goto fail;
3870 }
3871 }
3872
3873 *resp = myreply;
3874 return PAM_SUCCESS;
3875
3876 fail:
3877 free(myreply);
3878 *resp = NULL;
3879 return PAM_CONV_ERR;
3880 }
3881
3882 /*
3883 * Attempt to authenticate the user using PAM. Returns 0 if the user is
3884 * authenticated, or 1 if not authenticated. If some sort of PAM system
3885 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
3886 * function returns -1. This can be used as an indication that we should
3887 * fall back to a different authentication mechanism.
3888 * pw maybe be updated to a new user if PAM_USER changes from curname.
3889 */
3890 static int
auth_pam(void)3891 auth_pam(void)
3892 {
3893 const char *tmpl_user;
3894 const void *item;
3895 int rval;
3896 int e;
3897 ftpd_cred_t auth_cred = { curname, 0 };
3898 struct pam_conv conv = { &auth_conv, &auth_cred };
3899 struct sockaddr_storage ss;
3900
3901 e = pam_start("ftpd", curname, &conv, &pamh);
3902 if (e != PAM_SUCCESS) {
3903 /*
3904 * In OpenPAM, it's OK to pass NULL to pam_strerror()
3905 * if context creation has failed in the first place.
3906 */
3907 syslog(LOG_ERR, "pam_start: %s", pam_strerror(NULL, e));
3908 return -1;
3909 }
3910
3911 e = pam_set_item(pamh, PAM_RHOST, remotehost);
3912 if (e != PAM_SUCCESS) {
3913 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
3914 pam_strerror(pamh, e));
3915 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3916 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3917 }
3918 pamh = NULL;
3919 return -1;
3920 }
3921
3922 memset(&ss, 0, sizeof(ss));
3923 memcpy(&ss, &his_addr.si_su, his_addr.su_len);
3924 e = pam_set_item(pamh, PAM_SOCKADDR, &ss);
3925 if (e != PAM_SUCCESS) {
3926 syslog(LOG_ERR, "pam_set_item(PAM_SOCKADDR): %s",
3927 pam_strerror(pamh, e));
3928 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3929 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3930 }
3931 pamh = NULL;
3932 return -1;
3933 }
3934
3935 e = pam_authenticate(pamh, 0);
3936 if (ftpd_debug)
3937 syslog(LOG_DEBUG, "pam_authenticate: user '%s' returned %d",
3938 curname, e);
3939 switch (e) {
3940 case PAM_SUCCESS:
3941 /*
3942 * With PAM we support the concept of a "template"
3943 * user. The user enters a login name which is
3944 * authenticated by PAM, usually via a remote service
3945 * such as RADIUS or TACACS+. If authentication
3946 * succeeds, a different but related "template" name
3947 * is used for setting the credentials, shell, and
3948 * home directory. The name the user enters need only
3949 * exist on the remote authentication server, but the
3950 * template name must be present in the local password
3951 * database.
3952 *
3953 * This is supported by two various mechanisms in the
3954 * individual modules. However, from the application's
3955 * point of view, the template user is always passed
3956 * back as a changed value of the PAM_USER item.
3957 */
3958 if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
3959 PAM_SUCCESS) {
3960 tmpl_user = (const char *) item;
3961 if (pw == NULL
3962 || strcmp(pw->pw_name, tmpl_user) != 0) {
3963 pw = sgetpwnam(tmpl_user);
3964 if (ftpd_debug)
3965 syslog(LOG_DEBUG,
3966 "auth_pam: PAM changed "
3967 "user from '%s' to '%s'",
3968 curname, pw->pw_name);
3969 (void)strlcpy(curname, pw->pw_name,
3970 curname_len);
3971 }
3972 } else
3973 syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
3974 pam_strerror(pamh, e));
3975 rval = 0;
3976 break;
3977
3978 case PAM_AUTH_ERR:
3979 case PAM_USER_UNKNOWN:
3980 case PAM_MAXTRIES:
3981 rval = 1;
3982 break;
3983
3984 default:
3985 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
3986 rval = -1;
3987 break;
3988 }
3989
3990 if (rval == 0) {
3991 e = pam_acct_mgmt(pamh, 0);
3992 if (e != PAM_SUCCESS) {
3993 syslog(LOG_ERR, "pam_acct_mgmt: %s",
3994 pam_strerror(pamh, e));
3995 rval = 1;
3996 }
3997 }
3998
3999 if (rval != 0) {
4000 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
4001 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
4002 }
4003 pamh = NULL;
4004 }
4005 return rval;
4006 }
4007
4008 #endif /* USE_PAM */
4009