ftpd.c revision 1.204.4.1 1 /* $NetBSD: ftpd.c,v 1.204.4.1 2023/10/02 17:09:41 martin Exp $ */
2
3 /*
4 * Copyright (c) 1997-2009 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.204.4.1 2023/10/02 17:09:41 martin 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
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
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
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
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
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 *
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
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
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
1210 checkaccess(const char *name)
1211 {
1212
1213 return (checkuser(_NAME_FTPUSERS, name, 1, 0, NULL));
1214 }
1215
1216 static void
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
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
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 (void) seteuid((uid_t)0);
1304 #ifdef LOGIN_CAP
1305 setusercontext(NULL, getpwuid(0), 0,
1306 LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1307 #endif
1308 #ifdef USE_PAM
1309 if (pamh) {
1310 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS)
1311 syslog(LOG_ERR, "pam_setcred: %s",
1312 pam_strerror(pamh, e));
1313 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS)
1314 syslog(LOG_ERR, "pam_close_session: %s",
1315 pam_strerror(pamh, e));
1316 if ((e = pam_end(pamh, e)) != PAM_SUCCESS)
1317 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
1318 pamh = NULL;
1319 }
1320 #endif
1321 }
1322
1323 void
1324 pass(const char *passwd)
1325 {
1326 do_pass(0, 0, passwd);
1327 }
1328
1329 /*
1330 * Perform the passwd confirmation and login.
1331 *
1332 * If pass_checked is zero, confirm passwd is correct, & ignore pass_rval.
1333 * This is the traditional PASS implementation.
1334 *
1335 * If pass_checked is non-zero, use pass_rval and ignore passwd.
1336 * This is used by auth_pam() which has already parsed PASS.
1337 * This only applies to curclass.type != CLASS_GUEST.
1338 */
1339 static void
1340 do_pass(int pass_checked, int pass_rval, const char *passwd)
1341 {
1342 int rval;
1343 char root[MAXPATHLEN];
1344 #ifdef LOGIN_CAP
1345 login_cap_t *lc = NULL;
1346 #endif
1347 #ifdef USE_PAM
1348 int e;
1349 #endif
1350
1351 rval = 1;
1352
1353 if (logged_in || askpasswd == 0) {
1354 reply(503, "Login with USER first.");
1355 return;
1356 }
1357 askpasswd = 0;
1358 if (curclass.type != CLASS_GUEST) {
1359 /* "ftp" is the only account allowed with no password */
1360 if (pw == NULL) {
1361 rval = 1; /* failure below */
1362 goto skip;
1363 }
1364 if (pass_checked) { /* password validated in user() */
1365 rval = pass_rval;
1366 goto skip;
1367 }
1368 #ifdef USE_PAM
1369 syslog(LOG_ERR, "do_pass: USE_PAM shouldn't get here");
1370 rval = 1;
1371 goto skip;
1372 #endif
1373 #if defined(KERBEROS)
1374 if (klogin(pw, "", hostname, (char *)passwd) == 0) {
1375 rval = 0;
1376 goto skip;
1377 }
1378 #endif
1379 #if defined(KERBEROS5)
1380 if (k5login(pw, "", hostname, (char *)passwd) == 0) {
1381 rval = 0;
1382 goto skip;
1383 }
1384 #endif
1385 #ifdef SKEY
1386 if (skey_haskey(pw->pw_name) == 0) {
1387 char *p;
1388 int r;
1389
1390 p = ftpd_strdup(passwd);
1391 r = skey_passcheck(pw->pw_name, p);
1392 free(p);
1393 if (r != -1) {
1394 rval = 0;
1395 goto skip;
1396 }
1397 }
1398 #endif
1399 if (!sflag)
1400 rval = checkpassword(pw, passwd);
1401 else
1402 rval = 1;
1403
1404 skip:
1405
1406 /*
1407 * If rval > 0, the user failed the authentication check
1408 * above. If rval == 0, either Kerberos or local
1409 * authentication succeeded.
1410 */
1411 if (rval) {
1412 reply(530, "%s", rval == 2 ? "Password expired." :
1413 "Login incorrect.");
1414 pfilter_notify(1, rval == 2 ? "exppass" : "badpass");
1415 if (logging) {
1416 syslog(LOG_NOTICE,
1417 "FTP LOGIN FAILED FROM %s", remoteloghost);
1418 syslog(LOG_AUTHPRIV | LOG_NOTICE,
1419 "FTP LOGIN FAILED FROM %s, %s",
1420 remoteloghost, curname);
1421 }
1422 pw = NULL;
1423 if (login_attempts++ >= 5) {
1424 syslog(LOG_NOTICE,
1425 "repeated login failures from %s",
1426 remoteloghost);
1427 exit(0);
1428 }
1429 return;
1430 }
1431 }
1432
1433 /* password ok; check if anything else prevents login */
1434 if (! permitted) {
1435 reply(530, "User %s may not use FTP.", pw->pw_name);
1436 if (logging)
1437 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
1438 remoteloghost, pw->pw_name);
1439 goto bad;
1440 }
1441
1442 login_attempts = 0; /* this time successful */
1443 if (setegid((gid_t)pw->pw_gid) < 0) {
1444 reply(550, "Can't set gid.");
1445 goto bad;
1446 }
1447 #ifdef LOGIN_CAP
1448 if ((lc = login_getpwclass(pw)) != NULL) {
1449 #ifdef notyet
1450 char remote_ip[NI_MAXHOST];
1451
1452 if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1453 remote_ip, sizeof(remote_ip) - 1, NULL, 0,
1454 NI_NUMERICHOST))
1455 *remote_ip = 0;
1456 remote_ip[sizeof(remote_ip) - 1] = 0;
1457 if (!auth_hostok(lc, remotehost, remote_ip)) {
1458 pfilter_notify(1, "bannedhost");
1459 syslog(LOG_INFO|LOG_AUTH,
1460 "FTP LOGIN FAILED (HOST) as %s: permission denied.",
1461 pw->pw_name);
1462 reply(530, "Permission denied.");
1463 pw = NULL;
1464 return;
1465 }
1466 if (!auth_timeok(lc, time(NULL))) {
1467 reply(530, "Login not available right now.");
1468 pw = NULL;
1469 return;
1470 }
1471 #endif
1472 }
1473 setsid();
1474 setusercontext(lc, pw, 0,
1475 LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY|
1476 LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1477 #else
1478 (void) initgroups(pw->pw_name, pw->pw_gid);
1479 /* cache groups for cmds.c::matchgroup() */
1480 #endif
1481 #ifdef USE_PAM
1482 if (pamh) {
1483 if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
1484 syslog(LOG_ERR, "pam_open_session: %s",
1485 pam_strerror(pamh, e));
1486 } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED))
1487 != PAM_SUCCESS) {
1488 syslog(LOG_ERR, "pam_setcred: %s",
1489 pam_strerror(pamh, e));
1490 }
1491 }
1492 #endif
1493 gidcount = getgroups(0, NULL);
1494 if (gidlist)
1495 free(gidlist);
1496 gidlist = malloc(gidcount * sizeof *gidlist);
1497 gidcount = getgroups(gidcount, gidlist);
1498
1499 /* open utmp/wtmp before chroot */
1500 login_utmp(ttyline, pw->pw_name, remotehost, &his_addr);
1501
1502 logged_in = 1;
1503
1504 connections = 1;
1505 if (dopidfile)
1506 count_users();
1507 if (curclass.limit != -1 && connections > curclass.limit) {
1508 if (! EMPTYSTR(curclass.limitfile))
1509 (void)display_file(conffilename(curclass.limitfile),
1510 530);
1511 reply(530,
1512 "User %s access denied, connection limit of " LLF
1513 " reached.",
1514 pw->pw_name, (LLT)curclass.limit);
1515 syslog(LOG_NOTICE,
1516 "Maximum connection limit of " LLF
1517 " for class %s reached, login refused for %s",
1518 (LLT)curclass.limit, curclass.classname, pw->pw_name);
1519 goto bad;
1520 }
1521
1522 homedir[0] = '/';
1523 switch (curclass.type) {
1524 case CLASS_GUEST:
1525 /*
1526 * We MUST do a chdir() after the chroot. Otherwise
1527 * the old current directory will be accessible as "."
1528 * outside the new root!
1529 */
1530 format_path(root,
1531 curclass.chroot ? curclass.chroot :
1532 anondir ? anondir :
1533 pw->pw_dir);
1534 format_path(homedir,
1535 curclass.homedir ? curclass.homedir :
1536 "/");
1537 if (EMPTYSTR(homedir))
1538 homedir[0] = '/';
1539 if (EMPTYSTR(root) || chroot(root) < 0) {
1540 syslog(LOG_NOTICE,
1541 "GUEST user %s: can't chroot to %s: %m",
1542 pw->pw_name, root);
1543 goto bad_guest;
1544 }
1545 if (chdir(homedir) < 0) {
1546 syslog(LOG_NOTICE,
1547 "GUEST user %s: can't chdir to %s: %m",
1548 pw->pw_name, homedir);
1549 bad_guest:
1550 reply(550, "Can't set guest privileges.");
1551 goto bad;
1552 }
1553 break;
1554 case CLASS_CHROOT:
1555 format_path(root,
1556 curclass.chroot ? curclass.chroot :
1557 pw->pw_dir);
1558 format_path(homedir,
1559 curclass.homedir ? curclass.homedir :
1560 "/");
1561 if (EMPTYSTR(homedir))
1562 homedir[0] = '/';
1563 if (EMPTYSTR(root) || chroot(root) < 0) {
1564 syslog(LOG_NOTICE,
1565 "CHROOT user %s: can't chroot to %s: %m",
1566 pw->pw_name, root);
1567 goto bad_chroot;
1568 }
1569 if (chdir(homedir) < 0) {
1570 syslog(LOG_NOTICE,
1571 "CHROOT user %s: can't chdir to %s: %m",
1572 pw->pw_name, homedir);
1573 bad_chroot:
1574 reply(550, "Can't change root.");
1575 goto bad;
1576 }
1577 break;
1578 case CLASS_REAL:
1579 /* only chroot REAL if explicitly requested */
1580 if (! EMPTYSTR(curclass.chroot)) {
1581 format_path(root, curclass.chroot);
1582 if (EMPTYSTR(root) || chroot(root) < 0) {
1583 syslog(LOG_NOTICE,
1584 "REAL user %s: can't chroot to %s: %m",
1585 pw->pw_name, root);
1586 goto bad_chroot;
1587 }
1588 }
1589 format_path(homedir,
1590 curclass.homedir ? curclass.homedir :
1591 pw->pw_dir);
1592 if (EMPTYSTR(homedir) || chdir(homedir) < 0) {
1593 if (chdir("/") < 0) {
1594 syslog(LOG_NOTICE,
1595 "REAL user %s: can't chdir to %s: %m",
1596 pw->pw_name,
1597 !EMPTYSTR(homedir) ? homedir : "/");
1598 reply(530,
1599 "User %s: can't change directory to %s.",
1600 pw->pw_name,
1601 !EMPTYSTR(homedir) ? homedir : "/");
1602 goto bad;
1603 } else {
1604 reply(-230,
1605 "No directory! Logging in with home=/");
1606 homedir[0] = '/';
1607 }
1608 }
1609 break;
1610 }
1611 #ifndef LOGIN_CAP
1612 setsid();
1613 setlogin(pw->pw_name);
1614 #endif
1615 if (dropprivs ||
1616 (curclass.type != CLASS_REAL &&
1617 ntohs(ctrl_addr.su_port) > IPPORT_RESERVED + 1)) {
1618 dropprivs++;
1619 if (setgid((gid_t)pw->pw_gid) < 0) {
1620 reply(550, "Can't set gid.");
1621 goto bad;
1622 }
1623 if (setuid((uid_t)pw->pw_uid) < 0) {
1624 reply(550, "Can't set uid.");
1625 goto bad;
1626 }
1627 } else {
1628 if (seteuid((uid_t)pw->pw_uid) < 0) {
1629 reply(550, "Can't set uid.");
1630 goto bad;
1631 }
1632 }
1633 setenv("HOME", homedir, 1);
1634
1635 if (curclass.type == CLASS_GUEST && passwd[0] == '-')
1636 quietmessages = 1;
1637
1638 /*
1639 * Display a login message, if it exists.
1640 * N.B. reply(230,) must follow the message.
1641 */
1642 if (! EMPTYSTR(curclass.motd))
1643 (void)display_file(conffilename(curclass.motd), 230);
1644 show_chdir_messages(230);
1645 if (curclass.type == CLASS_GUEST) {
1646 char *p;
1647
1648 reply(230, "Guest login ok, access restrictions apply.");
1649 #if defined(HAVE_SETPROCTITLE)
1650 snprintf(proctitle, sizeof(proctitle),
1651 "%s: anonymous/%s", remotehost, passwd);
1652 setproctitle("%s", proctitle);
1653 #endif /* defined(HAVE_SETPROCTITLE) */
1654 if (logging)
1655 syslog(LOG_INFO,
1656 "ANONYMOUS FTP LOGIN FROM %s, %s (class: %s, type: %s)",
1657 remoteloghost, passwd,
1658 curclass.classname, CURCLASSTYPE);
1659 /* store guest password reply into pw_passwd */
1660 REASSIGN(pw->pw_passwd, ftpd_strdup(passwd));
1661 for (p = pw->pw_passwd; *p; p++)
1662 if (!isgraph((unsigned char)*p))
1663 *p = '_';
1664 } else {
1665 reply(230, "User %s logged in.", pw->pw_name);
1666 #if defined(HAVE_SETPROCTITLE)
1667 snprintf(proctitle, sizeof(proctitle),
1668 "%s: %s", remotehost, pw->pw_name);
1669 setproctitle("%s", proctitle);
1670 #endif /* defined(HAVE_SETPROCTITLE) */
1671 if (logging)
1672 syslog(LOG_INFO,
1673 "FTP LOGIN FROM %s as %s (class: %s, type: %s)",
1674 remoteloghost, pw->pw_name,
1675 curclass.classname, CURCLASSTYPE);
1676 }
1677 (void) umask(curclass.umask);
1678 #ifdef LOGIN_CAP
1679 login_close(lc);
1680 #endif
1681 return;
1682
1683 bad:
1684 #ifdef LOGIN_CAP
1685 login_close(lc);
1686 #endif
1687 /* Forget all about it... */
1688 end_login();
1689 }
1690
1691 void
1692 retrieve(const char *argv[], const char *name)
1693 {
1694 FILE *fin, *dout;
1695 struct stat st;
1696 int (*closefunc)(FILE *) = NULL;
1697 int dolog, sendrv, closerv, stderrfd, isconversion, isdata, isls;
1698 struct timeval start, finish, td, *tdp;
1699 struct rusage rusage_before, rusage_after;
1700 const char *dispname;
1701 const char *error;
1702
1703 sendrv = closerv = stderrfd = -1;
1704 isconversion = isdata = isls = dolog = 0;
1705 tdp = NULL;
1706 dispname = name;
1707 fin = dout = NULL;
1708 error = NULL;
1709 if (argv == NULL) { /* if not running a command ... */
1710 dolog = 1;
1711 isdata = 1;
1712 fin = fopen(name, "r");
1713 closefunc = fclose;
1714 if (fin == NULL) /* doesn't exist?; try a conversion */
1715 argv = do_conversion(name);
1716 if (argv != NULL) {
1717 isconversion++;
1718 syslog(LOG_DEBUG, "get command: '%s' on '%s'",
1719 argv[0], name);
1720 }
1721 }
1722 if (argv != NULL) {
1723 char temp[MAXPATHLEN];
1724
1725 if (strcmp(argv[0], INTERNAL_LS) == 0) {
1726 isls = 1;
1727 stderrfd = -1;
1728 } else {
1729 (void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
1730 stderrfd = mkstemp(temp);
1731 if (stderrfd != -1)
1732 (void)unlink(temp);
1733 }
1734 dispname = argv[0];
1735 fin = ftpd_popen(argv, "r", stderrfd);
1736 closefunc = ftpd_pclose;
1737 st.st_size = -1;
1738 st.st_blksize = BUFSIZ;
1739 }
1740 if (fin == NULL) {
1741 if (errno != 0) {
1742 perror_reply(550, dispname);
1743 if (dolog)
1744 logxfer("get", -1, name, NULL, NULL,
1745 strerror(errno));
1746 }
1747 goto cleanupretrieve;
1748 }
1749 byte_count = -1;
1750 if (argv == NULL
1751 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1752 error = "Not a plain file";
1753 reply(550, "%s: %s.", dispname, error);
1754 goto done;
1755 }
1756 if (restart_point) {
1757 if (type == TYPE_A) {
1758 off_t i;
1759 int c;
1760
1761 for (i = 0; i < restart_point; i++) {
1762 if ((c=getc(fin)) == EOF) {
1763 error = strerror(errno);
1764 perror_reply(550, dispname);
1765 goto done;
1766 }
1767 if (c == '\n')
1768 i++;
1769 }
1770 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1771 error = strerror(errno);
1772 perror_reply(550, dispname);
1773 goto done;
1774 }
1775 }
1776 dout = dataconn(dispname, st.st_size, "w");
1777 if (dout == NULL)
1778 goto done;
1779
1780 (void)getrusage(RUSAGE_SELF, &rusage_before);
1781 (void)gettimeofday(&start, NULL);
1782 sendrv = send_data(fin, dout, &st, isdata);
1783 (void)gettimeofday(&finish, NULL);
1784 (void)getrusage(RUSAGE_SELF, &rusage_after);
1785 closedataconn(dout); /* close now to affect timing stats */
1786 timersub(&finish, &start, &td);
1787 tdp = &td;
1788 done:
1789 if (dolog) {
1790 logxfer("get", byte_count, name, NULL, tdp, error);
1791 if (tdp != NULL)
1792 logrusage(&rusage_before, &rusage_after);
1793 }
1794 closerv = (*closefunc)(fin);
1795 if (sendrv == 0) {
1796 FILE *errf;
1797 struct stat sb;
1798
1799 if (!isls && argv != NULL && closerv != 0) {
1800 reply(-226,
1801 "Command returned an exit status of %d",
1802 closerv);
1803 if (isconversion)
1804 syslog(LOG_WARNING,
1805 "retrieve command: '%s' returned %d",
1806 argv[0], closerv);
1807 }
1808 if (!isls && argv != NULL && stderrfd != -1 &&
1809 (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
1810 ((errf = fdopen(stderrfd, "r")) != NULL)) {
1811 char *cp, line[LINE_MAX];
1812
1813 reply(-226, "Command error messages:");
1814 rewind(errf);
1815 while (fgets(line, sizeof(line), errf) != NULL) {
1816 if ((cp = strchr(line, '\n')) != NULL)
1817 *cp = '\0';
1818 reply(0, " %s", line);
1819 }
1820 (void) fflush(stdout);
1821 (void) fclose(errf);
1822 /* a reply(226,) must follow */
1823 }
1824 reply(226, "Transfer complete.");
1825 }
1826 cleanupretrieve:
1827 if (stderrfd != -1)
1828 (void)close(stderrfd);
1829 if (isconversion)
1830 free(argv);
1831 }
1832
1833 void
1834 store(const char *name, const char *fmode, int unique)
1835 {
1836 FILE *fout, *din;
1837 struct stat st;
1838 int (*closefunc)(FILE *);
1839 struct timeval start, finish, td, *tdp;
1840 const char *desc, *error;
1841
1842 din = NULL;
1843 desc = (*fmode == 'w') ? "put" : "append";
1844 error = NULL;
1845 if (unique && stat(name, &st) == 0 &&
1846 (name = gunique(name)) == NULL) {
1847 logxfer(desc, -1, name, NULL, NULL,
1848 "cannot create unique file");
1849 goto cleanupstore;
1850 }
1851
1852 if (restart_point)
1853 fmode = "r+";
1854 fout = fopen(name, fmode);
1855 closefunc = fclose;
1856 tdp = NULL;
1857 if (fout == NULL) {
1858 perror_reply(553, name);
1859 logxfer(desc, -1, name, NULL, NULL, strerror(errno));
1860 goto cleanupstore;
1861 }
1862 byte_count = -1;
1863 if (restart_point) {
1864 if (type == TYPE_A) {
1865 off_t i;
1866 int c;
1867
1868 for (i = 0; i < restart_point; i++) {
1869 if ((c=getc(fout)) == EOF) {
1870 error = strerror(errno);
1871 perror_reply(550, name);
1872 goto done;
1873 }
1874 if (c == '\n')
1875 i++;
1876 }
1877 /*
1878 * We must do this seek to "current" position
1879 * because we are changing from reading to
1880 * writing.
1881 */
1882 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1883 error = strerror(errno);
1884 perror_reply(550, name);
1885 goto done;
1886 }
1887 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1888 error = strerror(errno);
1889 perror_reply(550, name);
1890 goto done;
1891 }
1892 }
1893 din = dataconn(name, (off_t)-1, "r");
1894 if (din == NULL)
1895 goto done;
1896 (void)gettimeofday(&start, NULL);
1897 if (receive_data(din, fout) == 0) {
1898 if (unique)
1899 reply(226, "Transfer complete (unique file name:%s).",
1900 name);
1901 else
1902 reply(226, "Transfer complete.");
1903 }
1904 (void)gettimeofday(&finish, NULL);
1905 closedataconn(din); /* close now to affect timing stats */
1906 timersub(&finish, &start, &td);
1907 tdp = &td;
1908 done:
1909 logxfer(desc, byte_count, name, NULL, tdp, error);
1910 (*closefunc)(fout);
1911 cleanupstore:
1912 ;
1913 }
1914
1915 static FILE *
1916 getdatasock(const char *fmode)
1917 {
1918 int on, s, t, tries;
1919 in_port_t port;
1920
1921 on = 1;
1922 if (data >= 0)
1923 return (fdopen(data, fmode));
1924 if (! dropprivs)
1925 (void) seteuid((uid_t)0);
1926 s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1927 if (s < 0)
1928 goto bad;
1929 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1930 (char *) &on, sizeof(on)) < 0)
1931 goto bad;
1932 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1933 (char *) &on, sizeof(on)) < 0)
1934 goto bad;
1935 /* anchor socket to avoid multi-homing problems */
1936 data_source = ctrl_addr;
1937 /*
1938 * By default source port for PORT connctions is
1939 * ctrlport-1 (see RFC959 section 5.2).
1940 * However, if privs have been dropped and that
1941 * would be < IPPORT_RESERVED, use a random port
1942 * instead.
1943 */
1944 if (dataport)
1945 port = dataport;
1946 else
1947 port = ntohs(ctrl_addr.su_port) - 1;
1948 if (dropprivs && port < IPPORT_RESERVED)
1949 port = 0; /* use random port */
1950 data_source.su_port = htons(port);
1951
1952 for (tries = 1; ; tries++) {
1953 if (bind(s, (struct sockaddr *)&data_source.si_su,
1954 data_source.su_len) >= 0)
1955 break;
1956 if (errno != EADDRINUSE || tries > 10)
1957 goto bad;
1958 sleep(tries);
1959 }
1960 if (! dropprivs)
1961 (void) seteuid((uid_t)pw->pw_uid);
1962 #ifdef IP_TOS
1963 if (!mapped && ctrl_addr.su_family == AF_INET) {
1964 on = IPTOS_THROUGHPUT;
1965 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1966 sizeof(int)) < 0)
1967 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1968 }
1969 #endif
1970 return (fdopen(s, fmode));
1971 bad:
1972 /* Return the real value of errno (close may change it) */
1973 t = errno;
1974 if (! dropprivs)
1975 (void) seteuid((uid_t)pw->pw_uid);
1976 if (s >= 0)
1977 (void) close(s);
1978 errno = t;
1979 return (NULL);
1980 }
1981
1982 FILE *
1983 dataconn(const char *name, off_t size, const char *fmode)
1984 {
1985 char sizebuf[32];
1986 FILE *file;
1987 int retry, tos, keepalive, conerrno;
1988
1989 file_size = size;
1990 byte_count = 0;
1991 if (size != (off_t) -1)
1992 (void)snprintf(sizebuf, sizeof(sizebuf), " (" LLF " byte%s)",
1993 (LLT)size, PLURAL(size));
1994 else
1995 sizebuf[0] = '\0';
1996 if (pdata >= 0) {
1997 struct sockinet from;
1998 int s;
1999 socklen_t fromlen = sizeof(from.su_len);
2000
2001 (void) alarm(curclass.timeout);
2002 s = accept(pdata, (struct sockaddr *)&from.si_su, &fromlen);
2003 (void) alarm(0);
2004 if (s < 0) {
2005 reply(425, "Can't open data connection.");
2006 (void) close(pdata);
2007 pdata = -1;
2008 return (NULL);
2009 }
2010 (void) close(pdata);
2011 pdata = s;
2012 switch (from.su_family) {
2013 case AF_INET:
2014 #ifdef IP_TOS
2015 if (!mapped) {
2016 tos = IPTOS_THROUGHPUT;
2017 (void) setsockopt(s, IPPROTO_IP, IP_TOS,
2018 (char *)&tos, sizeof(int));
2019 }
2020 break;
2021 #endif
2022 }
2023 /* Set keepalives on the socket to detect dropped conns. */
2024 #ifdef SO_KEEPALIVE
2025 keepalive = 1;
2026 (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
2027 (char *)&keepalive, sizeof(int));
2028 #endif
2029 reply(150, "Opening %s mode data connection for '%s'%s.",
2030 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
2031 return (fdopen(pdata, fmode));
2032 }
2033 if (data >= 0) {
2034 reply(125, "Using existing data connection for '%s'%s.",
2035 name, sizebuf);
2036 usedefault = 1;
2037 return (fdopen(data, fmode));
2038 }
2039 if (usedefault)
2040 data_dest = his_addr;
2041 usedefault = 1;
2042 retry = conerrno = 0;
2043 do {
2044 file = getdatasock(fmode);
2045 if (file == NULL) {
2046 char hbuf[NI_MAXHOST];
2047 char pbuf[NI_MAXSERV];
2048
2049 if (getnameinfo((struct sockaddr *)&data_source.si_su,
2050 data_source.su_len, hbuf, sizeof(hbuf), pbuf,
2051 sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV))
2052 strlcpy(hbuf, "?", sizeof(hbuf));
2053 reply(425, "Can't create data socket (%s,%s): %s.",
2054 hbuf, pbuf, strerror(errno));
2055 return (NULL);
2056 }
2057 data = fileno(file);
2058 conerrno = 0;
2059 if (connect(data, (struct sockaddr *)&data_dest.si_su,
2060 data_dest.su_len) == 0)
2061 break;
2062 conerrno = errno;
2063 (void) fclose(file);
2064 file = NULL;
2065 data = -1;
2066 if (conerrno == EADDRINUSE) {
2067 sleep((unsigned) swaitint);
2068 retry += swaitint;
2069 } else {
2070 break;
2071 }
2072 } while (retry <= swaitmax);
2073 if (conerrno != 0) {
2074 perror_reply(425, "Can't build data connection");
2075 return (NULL);
2076 }
2077 reply(150, "Opening %s mode data connection for '%s'%s.",
2078 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
2079 return (file);
2080 }
2081
2082 void
2083 closedataconn(FILE *fd)
2084 {
2085
2086 if (fd == NULL)
2087 return;
2088 (void)fclose(fd);
2089 data = -1;
2090 if (pdata >= 0)
2091 (void)close(pdata);
2092 pdata = -1;
2093 }
2094
2095 int
2096 write_data(int fd, char *buf, size_t size, off_t *bufrem,
2097 struct timeval *then, int isdata)
2098 {
2099 struct timeval now, td;
2100 ssize_t c;
2101
2102 while (size > 0) {
2103 c = size;
2104 if (curclass.writesize) {
2105 if (curclass.writesize < c)
2106 c = curclass.writesize;
2107 }
2108 if (curclass.rateget) {
2109 if (*bufrem < c)
2110 c = *bufrem;
2111 }
2112 (void) alarm(curclass.timeout);
2113 c = write(fd, buf, c);
2114 if (c <= 0)
2115 return (1);
2116 buf += c;
2117 size -= c;
2118 byte_count += c;
2119 if (isdata) {
2120 total_data_out += c;
2121 total_data += c;
2122 }
2123 total_bytes_out += c;
2124 total_bytes += c;
2125 if (curclass.rateget) {
2126 *bufrem -= c;
2127 if (*bufrem == 0) {
2128 (void)gettimeofday(&now, NULL);
2129 timersub(&now, then, &td);
2130 if (td.tv_sec == 0) {
2131 usleep(1000000 - td.tv_usec);
2132 (void)gettimeofday(then, NULL);
2133 } else
2134 *then = now;
2135 *bufrem = curclass.rateget;
2136 }
2137 }
2138 }
2139 return (0);
2140 }
2141
2142 static enum send_status
2143 send_data_with_read(int filefd, int netfd, const struct stat *st, int isdata)
2144 {
2145 struct timeval then;
2146 off_t bufrem;
2147 ssize_t readsize;
2148 char *buf;
2149 int c, error;
2150
2151 if (curclass.readsize > 0)
2152 readsize = curclass.readsize;
2153 else
2154 readsize = st->st_blksize;
2155 if ((buf = malloc(readsize)) == NULL) {
2156 perror_reply(451, "Local resource failure: malloc");
2157 return (SS_NO_TRANSFER);
2158 }
2159
2160 if (curclass.rateget) {
2161 bufrem = curclass.rateget;
2162 (void)gettimeofday(&then, NULL);
2163 } else
2164 bufrem = readsize;
2165 for (;;) {
2166 (void) alarm(curclass.timeout);
2167 c = read(filefd, buf, readsize);
2168 if (c == 0)
2169 error = SS_SUCCESS;
2170 else if (c < 0)
2171 error = SS_FILE_ERROR;
2172 else if (write_data(netfd, buf, c, &bufrem, &then, isdata))
2173 error = SS_DATA_ERROR;
2174 else if (urgflag && handleoobcmd())
2175 error = SS_ABORTED;
2176 else
2177 continue;
2178
2179 free(buf);
2180 return (error);
2181 }
2182 }
2183
2184 static enum send_status
2185 send_data_with_mmap(int filefd, int netfd, const struct stat *st, int isdata)
2186 {
2187 struct timeval then;
2188 off_t bufrem, filesize, off, origoff;
2189 ssize_t mapsize, winsize;
2190 int error, sendbufsize, sendlowat;
2191 void *win;
2192
2193 bufrem = 0;
2194 if (curclass.sendbufsize) {
2195 sendbufsize = curclass.sendbufsize;
2196 if (setsockopt(netfd, SOL_SOCKET, SO_SNDBUF,
2197 &sendbufsize, sizeof(int)) == -1)
2198 syslog(LOG_WARNING, "setsockopt(SO_SNDBUF, %d): %m",
2199 sendbufsize);
2200 }
2201
2202 if (curclass.sendlowat) {
2203 sendlowat = curclass.sendlowat;
2204 if (setsockopt(netfd, SOL_SOCKET, SO_SNDLOWAT,
2205 &sendlowat, sizeof(int)) == -1)
2206 syslog(LOG_WARNING, "setsockopt(SO_SNDLOWAT, %d): %m",
2207 sendlowat);
2208 }
2209
2210 winsize = curclass.mmapsize;
2211 filesize = st->st_size;
2212 if (ftpd_debug)
2213 syslog(LOG_INFO, "mmapsize = " LLF ", writesize = " LLF,
2214 (LLT)winsize, (LLT)curclass.writesize);
2215 if (winsize <= 0)
2216 goto try_read;
2217
2218 off = lseek(filefd, (off_t)0, SEEK_CUR);
2219 if (off == -1)
2220 goto try_read;
2221
2222 origoff = off;
2223 if (curclass.rateget) {
2224 bufrem = curclass.rateget;
2225 (void)gettimeofday(&then, NULL);
2226 } else
2227 bufrem = winsize;
2228 while (1) {
2229 mapsize = MIN(filesize - off, winsize);
2230 if (mapsize == 0)
2231 break;
2232 win = mmap(NULL, mapsize, PROT_READ,
2233 MAP_FILE|MAP_SHARED, filefd, off);
2234 if (win == MAP_FAILED) {
2235 if (off == origoff)
2236 goto try_read;
2237 return (SS_FILE_ERROR);
2238 }
2239 (void) madvise(win, mapsize, MADV_SEQUENTIAL);
2240 error = write_data(netfd, win, mapsize, &bufrem, &then,
2241 isdata);
2242 (void) madvise(win, mapsize, MADV_DONTNEED);
2243 munmap(win, mapsize);
2244 if (urgflag && handleoobcmd())
2245 return (SS_ABORTED);
2246 if (error)
2247 return (SS_DATA_ERROR);
2248 off += mapsize;
2249 }
2250 return (SS_SUCCESS);
2251
2252 try_read:
2253 return (send_data_with_read(filefd, netfd, st, isdata));
2254 }
2255
2256 /*
2257 * Transfer the contents of "instr" to "outstr" peer using the appropriate
2258 * encapsulation of the data subject to Mode, Structure, and Type.
2259 *
2260 * NB: Form isn't handled.
2261 */
2262 static int
2263 send_data(FILE *instr, FILE *outstr, const struct stat *st, int isdata)
2264 {
2265 int c, filefd, netfd, rval;
2266
2267 urgflag = 0;
2268 transflag = 1;
2269 rval = -1;
2270
2271 switch (type) {
2272
2273 case TYPE_A:
2274 /* XXXLUKEM: rate limit ascii send (get) */
2275 (void) alarm(curclass.timeout);
2276 while ((c = getc(instr)) != EOF) {
2277 if (urgflag && handleoobcmd())
2278 goto cleanup_send_data;
2279 byte_count++;
2280 if (c == '\n') {
2281 if (ferror(outstr))
2282 goto data_err;
2283 (void) putc('\r', outstr);
2284 if (isdata) {
2285 total_data_out++;
2286 total_data++;
2287 }
2288 total_bytes_out++;
2289 total_bytes++;
2290 }
2291 (void) putc(c, outstr);
2292 if (isdata) {
2293 total_data_out++;
2294 total_data++;
2295 }
2296 total_bytes_out++;
2297 total_bytes++;
2298 if ((byte_count % 4096) == 0)
2299 (void) alarm(curclass.timeout);
2300 }
2301 (void) alarm(0);
2302 fflush(outstr);
2303 if (ferror(instr))
2304 goto file_err;
2305 if (ferror(outstr))
2306 goto data_err;
2307 rval = 0;
2308 goto cleanup_send_data;
2309
2310 case TYPE_I:
2311 case TYPE_L:
2312 filefd = fileno(instr);
2313 netfd = fileno(outstr);
2314 switch (send_data_with_mmap(filefd, netfd, st, isdata)) {
2315
2316 case SS_SUCCESS:
2317 break;
2318
2319 case SS_ABORTED:
2320 case SS_NO_TRANSFER:
2321 goto cleanup_send_data;
2322
2323 case SS_FILE_ERROR:
2324 goto file_err;
2325
2326 case SS_DATA_ERROR:
2327 goto data_err;
2328 }
2329 rval = 0;
2330 goto cleanup_send_data;
2331
2332 default:
2333 reply(550, "Unimplemented TYPE %d in send_data", type);
2334 goto cleanup_send_data;
2335 }
2336
2337 data_err:
2338 (void) alarm(0);
2339 perror_reply(426, "Data connection");
2340 goto cleanup_send_data;
2341
2342 file_err:
2343 (void) alarm(0);
2344 perror_reply(551, "Error on input file");
2345 goto cleanup_send_data;
2346
2347 cleanup_send_data:
2348 (void) alarm(0);
2349 transflag = 0;
2350 urgflag = 0;
2351 if (isdata) {
2352 total_files_out++;
2353 total_files++;
2354 }
2355 total_xfers_out++;
2356 total_xfers++;
2357 return (rval);
2358 }
2359
2360 /*
2361 * Transfer data from peer to "outstr" using the appropriate encapulation of
2362 * the data subject to Mode, Structure, and Type.
2363 *
2364 * N.B.: Form isn't handled.
2365 */
2366 static int
2367 receive_data(FILE *instr, FILE *outstr)
2368 {
2369 int c, netfd, filefd, rval;
2370 int volatile bare_lfs;
2371 off_t byteswritten;
2372 char *buf;
2373 ssize_t readsize;
2374 struct sigaction sa, sa_saved;
2375 struct stat st;
2376
2377 memset(&sa, 0, sizeof(sa));
2378 sigfillset(&sa.sa_mask);
2379 sa.sa_flags = SA_RESTART;
2380 sa.sa_handler = lostconn;
2381 (void) sigaction(SIGALRM, &sa, &sa_saved);
2382
2383 bare_lfs = 0;
2384 urgflag = 0;
2385 transflag = 1;
2386 rval = -1;
2387 byteswritten = 0;
2388 buf = NULL;
2389
2390 #define FILESIZECHECK(x) \
2391 do { \
2392 if (curclass.maxfilesize != -1 && \
2393 (x) > curclass.maxfilesize) { \
2394 errno = EFBIG; \
2395 goto file_err; \
2396 } \
2397 } while (0)
2398
2399 switch (type) {
2400
2401 case TYPE_I:
2402 case TYPE_L:
2403 netfd = fileno(instr);
2404 filefd = fileno(outstr);
2405 (void) alarm(curclass.timeout);
2406 if (curclass.readsize)
2407 readsize = curclass.readsize;
2408 else if (fstat(filefd, &st) != -1)
2409 readsize = (ssize_t)st.st_blksize;
2410 else
2411 readsize = BUFSIZ;
2412 if ((buf = malloc(readsize)) == NULL) {
2413 perror_reply(451, "Local resource failure: malloc");
2414 goto cleanup_recv_data;
2415 }
2416 if (curclass.rateput) {
2417 while (1) {
2418 int d;
2419 struct timeval then, now, td;
2420 off_t bufrem;
2421
2422 (void)gettimeofday(&then, NULL);
2423 errno = c = d = 0;
2424 for (bufrem = curclass.rateput; bufrem > 0; ) {
2425 if ((c = read(netfd, buf,
2426 MIN(readsize, bufrem))) <= 0)
2427 goto recvdone;
2428 if (urgflag && handleoobcmd())
2429 goto cleanup_recv_data;
2430 FILESIZECHECK(byte_count + c);
2431 if ((d = write(filefd, buf, c)) != c)
2432 goto file_err;
2433 (void) alarm(curclass.timeout);
2434 bufrem -= c;
2435 byte_count += c;
2436 total_data_in += c;
2437 total_data += c;
2438 total_bytes_in += c;
2439 total_bytes += c;
2440 }
2441 (void)gettimeofday(&now, NULL);
2442 timersub(&now, &then, &td);
2443 if (td.tv_sec == 0)
2444 usleep(1000000 - td.tv_usec);
2445 }
2446 } else {
2447 while ((c = read(netfd, buf, readsize)) > 0) {
2448 if (urgflag && handleoobcmd())
2449 goto cleanup_recv_data;
2450 FILESIZECHECK(byte_count + c);
2451 if (write(filefd, buf, c) != c)
2452 goto file_err;
2453 (void) alarm(curclass.timeout);
2454 byte_count += c;
2455 total_data_in += c;
2456 total_data += c;
2457 total_bytes_in += c;
2458 total_bytes += c;
2459 }
2460 }
2461 recvdone:
2462 if (c < 0)
2463 goto data_err;
2464 rval = 0;
2465 goto cleanup_recv_data;
2466
2467 case TYPE_E:
2468 reply(553, "TYPE E not implemented.");
2469 goto cleanup_recv_data;
2470
2471 case TYPE_A:
2472 (void) alarm(curclass.timeout);
2473 /* XXXLUKEM: rate limit ascii receive (put) */
2474 while ((c = getc(instr)) != EOF) {
2475 if (urgflag && handleoobcmd())
2476 goto cleanup_recv_data;
2477 byte_count++;
2478 total_data_in++;
2479 total_data++;
2480 total_bytes_in++;
2481 total_bytes++;
2482 if ((byte_count % 4096) == 0)
2483 (void) alarm(curclass.timeout);
2484 if (c == '\n')
2485 bare_lfs++;
2486 while (c == '\r') {
2487 if (ferror(outstr))
2488 goto data_err;
2489 if ((c = getc(instr)) != '\n') {
2490 byte_count++;
2491 total_data_in++;
2492 total_data++;
2493 total_bytes_in++;
2494 total_bytes++;
2495 if ((byte_count % 4096) == 0)
2496 (void) alarm(curclass.timeout);
2497 byteswritten++;
2498 FILESIZECHECK(byteswritten);
2499 (void) putc ('\r', outstr);
2500 if (c == '\0' || c == EOF)
2501 goto contin2;
2502 }
2503 }
2504 byteswritten++;
2505 FILESIZECHECK(byteswritten);
2506 (void) putc(c, outstr);
2507 contin2: ;
2508 }
2509 (void) alarm(0);
2510 fflush(outstr);
2511 if (ferror(instr))
2512 goto data_err;
2513 if (ferror(outstr))
2514 goto file_err;
2515 if (bare_lfs) {
2516 reply(-226,
2517 "WARNING! %d bare linefeeds received in ASCII mode",
2518 bare_lfs);
2519 reply(0, "File may not have transferred correctly.");
2520 }
2521 rval = 0;
2522 goto cleanup_recv_data;
2523
2524 default:
2525 reply(550, "Unimplemented TYPE %d in receive_data", type);
2526 goto cleanup_recv_data;
2527 }
2528 #undef FILESIZECHECK
2529
2530 data_err:
2531 (void) alarm(0);
2532 perror_reply(426, "Data Connection");
2533 goto cleanup_recv_data;
2534
2535 file_err:
2536 (void) alarm(0);
2537 perror_reply(452, "Error writing file");
2538 goto cleanup_recv_data;
2539
2540 cleanup_recv_data:
2541 (void) alarm(0);
2542 (void) sigaction(SIGALRM, &sa_saved, NULL);
2543 if (buf)
2544 free(buf);
2545 transflag = 0;
2546 urgflag = 0;
2547 total_files_in++;
2548 total_files++;
2549 total_xfers_in++;
2550 total_xfers++;
2551 return (rval);
2552 }
2553
2554 void
2555 statcmd(void)
2556 {
2557 struct sockinet *su = NULL;
2558 static char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
2559 unsigned char *a, *p;
2560 int ispassive, af;
2561 off_t otbi, otbo, otb;
2562
2563 a = p = NULL;
2564
2565 reply(-211, "%s FTP server status:", hostname);
2566 reply(0, "Version: %s", EMPTYSTR(version) ? "<suppressed>" : version);
2567 hbuf[0] = '\0';
2568 if (!getnameinfo((struct sockaddr *)&his_addr.si_su, his_addr.su_len,
2569 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)
2570 && strcmp(remotehost, hbuf) != 0)
2571 reply(0, "Connected to %s (%s)", remotehost, hbuf);
2572 else
2573 reply(0, "Connected to %s", remotehost);
2574
2575 if (logged_in) {
2576 if (curclass.type == CLASS_GUEST)
2577 reply(0, "Logged in anonymously");
2578 else
2579 reply(0, "Logged in as %s%s", pw->pw_name,
2580 curclass.type == CLASS_CHROOT ? " (chroot)" : "");
2581 } else if (askpasswd)
2582 reply(0, "Waiting for password");
2583 else
2584 reply(0, "Waiting for user name");
2585 cprintf(stdout, " TYPE: %s", typenames[type]);
2586 if (type == TYPE_A || type == TYPE_E)
2587 cprintf(stdout, ", FORM: %s", formnames[form]);
2588 if (type == TYPE_L) {
2589 #if NBBY == 8
2590 cprintf(stdout, " %d", NBBY);
2591 #else
2592 /* XXX: `bytesize' needs to be defined in this case */
2593 cprintf(stdout, " %d", bytesize);
2594 #endif
2595 }
2596 cprintf(stdout, "; STRUcture: %s; transfer MODE: %s\r\n",
2597 strunames[stru], modenames[mode]);
2598 ispassive = 0;
2599 if (data != -1) {
2600 reply(0, "Data connection open");
2601 su = NULL;
2602 } else if (pdata != -1) {
2603 reply(0, "in Passive mode");
2604 if (curclass.advertise.su_len != 0)
2605 su = &curclass.advertise;
2606 else
2607 su = &pasv_addr;
2608 ispassive = 1;
2609 goto printaddr;
2610 } else if (usedefault == 0) {
2611 su = (struct sockinet *)&data_dest;
2612
2613 if (epsvall) {
2614 reply(0, "EPSV only mode (EPSV ALL)");
2615 goto epsvonly;
2616 }
2617 printaddr:
2618 /* PASV/PORT */
2619 if (su->su_family == AF_INET) {
2620 a = (unsigned char *) &su->su_addr;
2621 p = (unsigned char *) &su->su_port;
2622 #define UC(b) (((int) b) & 0xff)
2623 reply(0, "%s (%d,%d,%d,%d,%d,%d)",
2624 ispassive ? "PASV" : "PORT" ,
2625 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2626 UC(p[0]), UC(p[1]));
2627 }
2628
2629 /* LPSV/LPRT */
2630 {
2631 int alen, i;
2632
2633 alen = 0;
2634 switch (su->su_family) {
2635 case AF_INET:
2636 a = (unsigned char *) &su->su_addr;
2637 p = (unsigned char *) &su->su_port;
2638 alen = sizeof(su->su_addr);
2639 af = 4;
2640 break;
2641 #ifdef INET6
2642 case AF_INET6:
2643 a = (unsigned char *) &su->su_6addr;
2644 p = (unsigned char *) &su->su_port;
2645 alen = sizeof(su->su_6addr);
2646 af = 6;
2647 break;
2648 #endif
2649 default:
2650 af = 0;
2651 break;
2652 }
2653 if (af) {
2654 cprintf(stdout, " %s (%d,%d",
2655 ispassive ? "LPSV" : "LPRT", af, alen);
2656 for (i = 0; i < alen; i++)
2657 cprintf(stdout, ",%d", UC(a[i]));
2658 cprintf(stdout, ",%d,%d,%d)\r\n",
2659 2, UC(p[0]), UC(p[1]));
2660 #undef UC
2661 }
2662 }
2663
2664 /* EPRT/EPSV */
2665 epsvonly:
2666 af = af2epsvproto(su->su_family);
2667 hbuf[0] = '\0';
2668 if (af > 0) {
2669 struct sockinet tmp;
2670
2671 tmp = *su;
2672 #ifdef INET6
2673 if (tmp.su_family == AF_INET6)
2674 tmp.su_scope_id = 0;
2675 #endif
2676 if (getnameinfo((struct sockaddr *)&tmp.si_su,
2677 tmp.su_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
2678 NI_NUMERICHOST | NI_NUMERICSERV) == 0)
2679 reply(0, "%s (|%d|%s|%s|)",
2680 ispassive ? "EPSV" : "EPRT",
2681 af, hbuf, sbuf);
2682 }
2683 } else
2684 reply(0, "No data connection");
2685
2686 if (logged_in) {
2687 reply(0,
2688 "Data sent: " LLF " byte%s in " LLF " file%s",
2689 (LLT)total_data_out, PLURAL(total_data_out),
2690 (LLT)total_files_out, PLURAL(total_files_out));
2691 reply(0,
2692 "Data received: " LLF " byte%s in " LLF " file%s",
2693 (LLT)total_data_in, PLURAL(total_data_in),
2694 (LLT)total_files_in, PLURAL(total_files_in));
2695 reply(0,
2696 "Total data: " LLF " byte%s in " LLF " file%s",
2697 (LLT)total_data, PLURAL(total_data),
2698 (LLT)total_files, PLURAL(total_files));
2699 }
2700 otbi = total_bytes_in;
2701 otbo = total_bytes_out;
2702 otb = total_bytes;
2703 reply(0, "Traffic sent: " LLF " byte%s in " LLF " transfer%s",
2704 (LLT)otbo, PLURAL(otbo),
2705 (LLT)total_xfers_out, PLURAL(total_xfers_out));
2706 reply(0, "Traffic received: " LLF " byte%s in " LLF " transfer%s",
2707 (LLT)otbi, PLURAL(otbi),
2708 (LLT)total_xfers_in, PLURAL(total_xfers_in));
2709 reply(0, "Total traffic: " LLF " byte%s in " LLF " transfer%s",
2710 (LLT)otb, PLURAL(otb),
2711 (LLT)total_xfers, PLURAL(total_xfers));
2712
2713 if (logged_in && !CURCLASS_FLAGS_ISSET(private)) {
2714 struct ftpconv *cp;
2715
2716 reply(0, "%s", "");
2717 reply(0, "Class: %s, type: %s",
2718 curclass.classname, CURCLASSTYPE);
2719 reply(0, "Check PORT/LPRT commands: %sabled",
2720 CURCLASS_FLAGS_ISSET(checkportcmd) ? "en" : "dis");
2721 if (! EMPTYSTR(curclass.display))
2722 reply(0, "Display file: %s", curclass.display);
2723 if (! EMPTYSTR(curclass.notify))
2724 reply(0, "Notify fileglob: %s", curclass.notify);
2725 reply(0, "Idle timeout: " LLF ", maximum timeout: " LLF,
2726 (LLT)curclass.timeout, (LLT)curclass.maxtimeout);
2727 reply(0, "Current connections: %d", connections);
2728 if (curclass.limit == -1)
2729 reply(0, "Maximum connections: unlimited");
2730 else
2731 reply(0, "Maximum connections: " LLF,
2732 (LLT)curclass.limit);
2733 if (curclass.limitfile)
2734 reply(0, "Connection limit exceeded message file: %s",
2735 conffilename(curclass.limitfile));
2736 if (! EMPTYSTR(curclass.chroot))
2737 reply(0, "Chroot format: %s", curclass.chroot);
2738 reply(0, "Deny bad ftpusers(5) quickly: %sabled",
2739 CURCLASS_FLAGS_ISSET(denyquick) ? "en" : "dis");
2740 if (! EMPTYSTR(curclass.homedir))
2741 reply(0, "Homedir format: %s", curclass.homedir);
2742 if (curclass.maxfilesize == -1)
2743 reply(0, "Maximum file size: unlimited");
2744 else
2745 reply(0, "Maximum file size: " LLF,
2746 (LLT)curclass.maxfilesize);
2747 if (! EMPTYSTR(curclass.motd))
2748 reply(0, "MotD file: %s", conffilename(curclass.motd));
2749 reply(0,
2750 "Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled",
2751 CURCLASS_FLAGS_ISSET(modify) ? "en" : "dis");
2752 reply(0, "Upload commands (APPE, STOR, STOU): %sabled",
2753 CURCLASS_FLAGS_ISSET(upload) ? "en" : "dis");
2754 reply(0, "Sanitize file names: %sabled",
2755 CURCLASS_FLAGS_ISSET(sanenames) ? "en" : "dis");
2756 reply(0, "PASV/LPSV/EPSV connections: %sabled",
2757 CURCLASS_FLAGS_ISSET(passive) ? "en" : "dis");
2758 if (curclass.advertise.su_len != 0) {
2759 char buf[50]; /* big enough for IPv6 address */
2760 const char *bp;
2761
2762 bp = inet_ntop(curclass.advertise.su_family,
2763 (void *)&curclass.advertise.su_addr,
2764 buf, sizeof(buf));
2765 if (bp != NULL)
2766 reply(0, "PASV advertise address: %s", bp);
2767 }
2768 if (curclass.portmin && curclass.portmax)
2769 reply(0, "PASV port range: " LLF " - " LLF,
2770 (LLT)curclass.portmin, (LLT)curclass.portmax);
2771 if (curclass.rateget)
2772 reply(0, "Rate get limit: " LLF " bytes/sec",
2773 (LLT)curclass.rateget);
2774 else
2775 reply(0, "Rate get limit: disabled");
2776 if (curclass.rateput)
2777 reply(0, "Rate put limit: " LLF " bytes/sec",
2778 (LLT)curclass.rateput);
2779 else
2780 reply(0, "Rate put limit: disabled");
2781 if (curclass.mmapsize)
2782 reply(0, "Mmap size: " LLF, (LLT)curclass.mmapsize);
2783 else
2784 reply(0, "Mmap size: disabled");
2785 if (curclass.readsize)
2786 reply(0, "Read size: " LLF, (LLT)curclass.readsize);
2787 else
2788 reply(0, "Read size: default");
2789 if (curclass.writesize)
2790 reply(0, "Write size: " LLF, (LLT)curclass.writesize);
2791 else
2792 reply(0, "Write size: default");
2793 if (curclass.recvbufsize)
2794 reply(0, "Receive buffer size: " LLF,
2795 (LLT)curclass.recvbufsize);
2796 else
2797 reply(0, "Receive buffer size: default");
2798 if (curclass.sendbufsize)
2799 reply(0, "Send buffer size: " LLF,
2800 (LLT)curclass.sendbufsize);
2801 else
2802 reply(0, "Send buffer size: default");
2803 if (curclass.sendlowat)
2804 reply(0, "Send low water mark: " LLF,
2805 (LLT)curclass.sendlowat);
2806 else
2807 reply(0, "Send low water mark: default");
2808 reply(0, "Umask: %.04o", curclass.umask);
2809 for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
2810 if (cp->suffix == NULL || cp->types == NULL ||
2811 cp->command == NULL)
2812 continue;
2813 reply(0, "Conversion: %s [%s] disable: %s, command: %s",
2814 cp->suffix, cp->types, cp->disable, cp->command);
2815 }
2816 }
2817
2818 reply(211, "End of status");
2819 }
2820
2821 void
2822 fatal(const char *s)
2823 {
2824
2825 reply(451, "Error in server: %s\n", s);
2826 reply(221, "Closing connection due to server error.");
2827 dologout(0);
2828 /* NOTREACHED */
2829 }
2830
2831 /*
2832 * reply() --
2833 * depending on the value of n, display fmt with a trailing CRLF and
2834 * prefix of:
2835 * n < -1 prefix the message with abs(n) + "-" (initial line)
2836 * n == 0 prefix the message with 4 spaces (middle lines)
2837 * n > 0 prefix the message with n + " " (final line)
2838 */
2839 void
2840 reply(int n, const char *fmt, ...)
2841 {
2842 char msg[MAXPATHLEN * 2 + 100];
2843 size_t b;
2844 va_list ap;
2845
2846 if (n == 0)
2847 b = snprintf(msg, sizeof(msg), " ");
2848 else if (n < 0)
2849 b = snprintf(msg, sizeof(msg), "%d-", -n);
2850 else
2851 b = snprintf(msg, sizeof(msg), "%d ", n);
2852 va_start(ap, fmt);
2853 vsnprintf(msg + b, sizeof(msg) - b, fmt, ap);
2854 va_end(ap);
2855 cprintf(stdout, "%s\r\n", msg);
2856 (void)fflush(stdout);
2857 if (ftpd_debug)
2858 syslog(LOG_DEBUG, "<--- %s", msg);
2859 }
2860
2861 static void
2862 logremotehost(struct sockinet *who)
2863 {
2864
2865 #if defined(HAVE_SOCKADDR_SNPRINTF)
2866 char abuf[MAXHOSTNAMELEN];
2867 #endif
2868
2869 struct sockaddr *sa = (struct sockaddr *)&who->si_su;
2870 if (getnameinfo(sa, who->su_len, remotehost, sizeof(remotehost), NULL,
2871 0, getnameopts))
2872 strlcpy(remotehost, "?", sizeof(remotehost));
2873 #if defined(HAVE_SOCKADDR_SNPRINTF)
2874 sockaddr_snprintf(abuf, sizeof(abuf), "%a", sa);
2875 snprintf(remoteloghost, sizeof(remoteloghost), "%s(%s)", remotehost,
2876 abuf);
2877 #else
2878 strlcpy(remoteloghost, remotehost, sizeof(remoteloghost));
2879 #endif
2880
2881 #if defined(HAVE_SETPROCTITLE)
2882 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2883 setproctitle("%s", proctitle);
2884 #endif /* defined(HAVE_SETPROCTITLE) */
2885 if (logging)
2886 syslog(LOG_INFO, "connection from %s to %s",
2887 remoteloghost, hostname);
2888 }
2889
2890 /*
2891 * Record logout in wtmp file and exit with supplied status.
2892 * NOTE: because this is called from signal handlers it cannot
2893 * use stdio (or call other functions that use stdio).
2894 */
2895 void
2896 dologout(int status)
2897 {
2898 /*
2899 * Prevent reception of SIGURG from resulting in a resumption
2900 * back to the main program loop.
2901 */
2902 transflag = 0;
2903 logout_utmp();
2904 if (logged_in) {
2905 #ifdef KERBEROS
2906 if (!notickets && krbtkfile_env)
2907 unlink(krbtkfile_env);
2908 #endif
2909 }
2910 /* beware of flushing buffers after a SIGPIPE */
2911 if (xferlogfd != -1)
2912 close(xferlogfd);
2913 _exit(status);
2914 }
2915
2916 void
2917 abor(void)
2918 {
2919
2920 if (!transflag)
2921 return;
2922 tmpline[0] = '\0';
2923 is_oob = 0;
2924 reply(426, "Transfer aborted. Data connection closed.");
2925 reply(226, "Abort successful");
2926 transflag = 0; /* flag that the transfer has aborted */
2927 }
2928
2929 void
2930 statxfer(void)
2931 {
2932
2933 if (!transflag)
2934 return;
2935 tmpline[0] = '\0';
2936 is_oob = 0;
2937 if (file_size != (off_t) -1)
2938 reply(213,
2939 "Status: " LLF " of " LLF " byte%s transferred",
2940 (LLT)byte_count, (LLT)file_size,
2941 PLURAL(byte_count));
2942 else
2943 reply(213, "Status: " LLF " byte%s transferred",
2944 (LLT)byte_count, PLURAL(byte_count));
2945 }
2946
2947 /*
2948 * Call when urgflag != 0 to handle Out Of Band commands.
2949 * Returns non zero if the OOB command aborted the transfer
2950 * by setting transflag to 0. (c.f., "ABOR").
2951 */
2952 static int
2953 handleoobcmd(void)
2954 {
2955 char *cp;
2956 int ret;
2957
2958 if (!urgflag)
2959 return (0);
2960 urgflag = 0;
2961 /* only process if transfer occurring */
2962 if (!transflag)
2963 return (0);
2964 cp = tmpline;
2965 ret = get_line(cp, sizeof(tmpline)-1, stdin);
2966 if (ret == -1) {
2967 reply(221, "You could at least say goodbye.");
2968 dologout(0);
2969 } else if (ret == -2) {
2970 /* Ignore truncated command */
2971 /* XXX: abort xfer with "500 command too long", & return 1 ? */
2972 return 0;
2973 }
2974 /*
2975 * Manually parse OOB commands, because we can't
2976 * recursively call the yacc parser...
2977 */
2978 if (strcasecmp(cp, "ABOR\r\n") == 0) {
2979 abor();
2980 } else if (strcasecmp(cp, "STAT\r\n") == 0) {
2981 statxfer();
2982 } else {
2983 /* XXX: error with "500 unknown command" ? */
2984 }
2985 return (transflag == 0);
2986 }
2987
2988 static int
2989 bind_pasv_addr(void)
2990 {
2991 static int passiveport;
2992 int port, len;
2993
2994 len = pasv_addr.su_len;
2995 if (curclass.portmin == 0 && curclass.portmax == 0) {
2996 pasv_addr.su_port = 0;
2997 return (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len));
2998 }
2999
3000 if (passiveport == 0) {
3001 srand(getpid());
3002 passiveport = rand() % (curclass.portmax - curclass.portmin)
3003 + curclass.portmin;
3004 }
3005
3006 port = passiveport;
3007 while (1) {
3008 port++;
3009 if (port > curclass.portmax)
3010 port = curclass.portmin;
3011 else if (port == passiveport) {
3012 errno = EAGAIN;
3013 return (-1);
3014 }
3015 pasv_addr.su_port = htons(port);
3016 if (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len) == 0)
3017 break;
3018 if (errno != EADDRINUSE)
3019 return (-1);
3020 }
3021 passiveport = port;
3022 return (0);
3023 }
3024
3025 /*
3026 * Note: a response of 425 is not mentioned as a possible response to
3027 * the PASV command in RFC959. However, it has been blessed as
3028 * a legitimate response by Jon Postel in a telephone conversation
3029 * with Rick Adams on 25 Jan 89.
3030 */
3031 void
3032 passive(void)
3033 {
3034 socklen_t len;
3035 int recvbufsize;
3036 char *p, *a;
3037
3038 if (pdata >= 0)
3039 close(pdata);
3040 pdata = socket(AF_INET, SOCK_STREAM, 0);
3041 if (pdata < 0 || !logged_in) {
3042 perror_reply(425, "Can't open passive connection");
3043 return;
3044 }
3045 pasv_addr = ctrl_addr;
3046
3047 if (bind_pasv_addr() < 0)
3048 goto pasv_error;
3049 len = pasv_addr.su_len;
3050 if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
3051 goto pasv_error;
3052 pasv_addr.su_len = len;
3053 if (curclass.recvbufsize) {
3054 recvbufsize = curclass.recvbufsize;
3055 if (setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, &recvbufsize,
3056 sizeof(int)) == -1)
3057 syslog(LOG_WARNING, "setsockopt(SO_RCVBUF, %d): %m",
3058 recvbufsize);
3059 }
3060 if (listen(pdata, 1) < 0)
3061 goto pasv_error;
3062 if (curclass.advertise.su_len != 0)
3063 a = (char *) &curclass.advertise.su_addr;
3064 else
3065 a = (char *) &pasv_addr.su_addr;
3066 p = (char *) &pasv_addr.su_port;
3067
3068 #define UC(b) (((int) b) & 0xff)
3069
3070 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
3071 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
3072 return;
3073
3074 pasv_error:
3075 (void) close(pdata);
3076 pdata = -1;
3077 perror_reply(425, "Can't open passive connection");
3078 return;
3079 }
3080
3081 /*
3082 * convert protocol identifier to/from AF
3083 */
3084 int
3085 lpsvproto2af(int proto)
3086 {
3087
3088 switch (proto) {
3089 case 4:
3090 return AF_INET;
3091 #ifdef INET6
3092 case 6:
3093 return AF_INET6;
3094 #endif
3095 default:
3096 return -1;
3097 }
3098 }
3099
3100 int
3101 af2lpsvproto(int af)
3102 {
3103
3104 switch (af) {
3105 case AF_INET:
3106 return 4;
3107 #ifdef INET6
3108 case AF_INET6:
3109 return 6;
3110 #endif
3111 default:
3112 return -1;
3113 }
3114 }
3115
3116 int
3117 epsvproto2af(int proto)
3118 {
3119
3120 switch (proto) {
3121 case 1:
3122 return AF_INET;
3123 #ifdef INET6
3124 case 2:
3125 return AF_INET6;
3126 #endif
3127 default:
3128 return -1;
3129 }
3130 }
3131
3132 int
3133 af2epsvproto(int af)
3134 {
3135
3136 switch (af) {
3137 case AF_INET:
3138 return 1;
3139 #ifdef INET6
3140 case AF_INET6:
3141 return 2;
3142 #endif
3143 default:
3144 return -1;
3145 }
3146 }
3147
3148 /*
3149 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
3150 * 229 Entering Extended Passive Mode (|||port|)
3151 */
3152 void
3153 long_passive(const char *cmd, int pf)
3154 {
3155 socklen_t len;
3156 char *p, *a;
3157
3158 if (!logged_in) {
3159 syslog(LOG_NOTICE, "long passive but not logged in");
3160 reply(503, "Login with USER first.");
3161 return;
3162 }
3163
3164 if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
3165 /*
3166 * XXX: only EPRT/EPSV ready clients will understand this
3167 */
3168 if (strcmp(cmd, "EPSV") != 0)
3169 reply(501, "Network protocol mismatch"); /*XXX*/
3170 else
3171 epsv_protounsupp("Network protocol mismatch");
3172
3173 return;
3174 }
3175
3176 if (pdata >= 0)
3177 close(pdata);
3178 pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
3179 if (pdata < 0) {
3180 perror_reply(425, "Can't open passive connection");
3181 return;
3182 }
3183 pasv_addr = ctrl_addr;
3184 if (bind_pasv_addr() < 0)
3185 goto pasv_error;
3186 len = pasv_addr.su_len;
3187 if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
3188 goto pasv_error;
3189 pasv_addr.su_len = len;
3190 if (listen(pdata, 1) < 0)
3191 goto pasv_error;
3192 p = (char *) &pasv_addr.su_port;
3193
3194 #define UC(b) (((int) b) & 0xff)
3195
3196 if (strcmp(cmd, "LPSV") == 0) {
3197 struct sockinet *advert;
3198
3199 if (curclass.advertise.su_len != 0)
3200 advert = &curclass.advertise;
3201 else
3202 advert = &pasv_addr;
3203 switch (advert->su_family) {
3204 case AF_INET:
3205 a = (char *) &advert->su_addr;
3206 reply(228,
3207 "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
3208 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
3209 2, UC(p[0]), UC(p[1]));
3210 return;
3211 #ifdef INET6
3212 case AF_INET6:
3213 a = (char *) &advert->su_6addr;
3214 reply(228,
3215 "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)",
3216 6, 16,
3217 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
3218 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
3219 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
3220 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
3221 2, UC(p[0]), UC(p[1]));
3222 return;
3223 #endif
3224 }
3225 #undef UC
3226 } else if (strcmp(cmd, "EPSV") == 0) {
3227 switch (pasv_addr.su_family) {
3228 case AF_INET:
3229 #ifdef INET6
3230 case AF_INET6:
3231 #endif
3232 reply(229, "Entering Extended Passive Mode (|||%d|)",
3233 ntohs(pasv_addr.su_port));
3234 return;
3235 }
3236 } else {
3237 /* more proper error code? */
3238 }
3239
3240 pasv_error:
3241 (void) close(pdata);
3242 pdata = -1;
3243 perror_reply(425, "Can't open passive connection");
3244 return;
3245 }
3246
3247 int
3248 extended_port(const char *arg)
3249 {
3250 char *tmp = NULL;
3251 char *result[3];
3252 char *p, *q;
3253 char delim;
3254 struct addrinfo hints;
3255 struct addrinfo *res = NULL;
3256 int i;
3257 unsigned long proto;
3258
3259 tmp = ftpd_strdup(arg);
3260 p = tmp;
3261 delim = p[0];
3262 p++;
3263 memset(result, 0, sizeof(result));
3264 for (i = 0; i < 3; i++) {
3265 q = strchr(p, delim);
3266 if (!q || *q != delim)
3267 goto parsefail;
3268 *q++ = '\0';
3269 result[i] = p;
3270 p = q;
3271 }
3272
3273 /* some more sanity checks */
3274 errno = 0;
3275 p = NULL;
3276 (void)strtoul(result[2], &p, 10);
3277 if (errno || !*result[2] || *p)
3278 goto parsefail;
3279 errno = 0;
3280 p = NULL;
3281 proto = strtoul(result[0], &p, 10);
3282 if (errno || !*result[0] || *p)
3283 goto protounsupp;
3284
3285 memset(&hints, 0, sizeof(hints));
3286 hints.ai_family = epsvproto2af((int)proto);
3287 if (hints.ai_family < 0)
3288 goto protounsupp;
3289 hints.ai_socktype = SOCK_STREAM;
3290 hints.ai_flags = AI_NUMERICHOST;
3291 if (getaddrinfo(result[1], result[2], &hints, &res))
3292 goto parsefail;
3293 if (res->ai_next)
3294 goto parsefail;
3295 if (sizeof(data_dest) < res->ai_addrlen)
3296 goto parsefail;
3297 memcpy(&data_dest.si_su, res->ai_addr, res->ai_addrlen);
3298 data_dest.su_len = res->ai_addrlen;
3299 #ifdef INET6
3300 if (his_addr.su_family == AF_INET6 &&
3301 data_dest.su_family == AF_INET6) {
3302 /* XXX: more sanity checks! */
3303 data_dest.su_scope_id = his_addr.su_scope_id;
3304 }
3305 #endif
3306
3307 if (tmp != NULL)
3308 free(tmp);
3309 if (res)
3310 freeaddrinfo(res);
3311 return 0;
3312
3313 parsefail:
3314 reply(500, "Invalid argument, rejected.");
3315 usedefault = 1;
3316 if (tmp != NULL)
3317 free(tmp);
3318 if (res)
3319 freeaddrinfo(res);
3320 return -1;
3321
3322 protounsupp:
3323 epsv_protounsupp("Protocol not supported");
3324 usedefault = 1;
3325 if (tmp != NULL)
3326 free(tmp);
3327 return -1;
3328 }
3329
3330 /*
3331 * 522 Protocol not supported (proto,...)
3332 * as we assume address family for control and data connections are the same,
3333 * we do not return the list of address families we support - instead, we
3334 * return the address family of the control connection.
3335 */
3336 void
3337 epsv_protounsupp(const char *message)
3338 {
3339 int proto;
3340
3341 proto = af2epsvproto(ctrl_addr.su_family);
3342 if (proto < 0)
3343 reply(501, "%s", message); /* XXX */
3344 else
3345 reply(522, "%s, use (%d)", message, proto);
3346 }
3347
3348 /*
3349 * Generate unique name for file with basename "local".
3350 * The file named "local" is already known to exist.
3351 * Generates failure reply on error.
3352 *
3353 * XXX: this function should under go changes similar to
3354 * the mktemp(3)/mkstemp(3) changes.
3355 */
3356 static char *
3357 gunique(const char *local)
3358 {
3359 static char new[MAXPATHLEN];
3360 struct stat st;
3361 char *cp;
3362 int count;
3363
3364 cp = strrchr(local, '/');
3365 if (cp)
3366 *cp = '\0';
3367 if (stat(cp ? local : ".", &st) < 0) {
3368 perror_reply(553, cp ? local : ".");
3369 return (NULL);
3370 }
3371 if (cp)
3372 *cp = '/';
3373 for (count = 1; count < 100; count++) {
3374 (void)snprintf(new, sizeof(new) - 1, "%s.%d", local, count);
3375 if (stat(new, &st) < 0)
3376 return (new);
3377 }
3378 reply(452, "Unique file name cannot be created.");
3379 return (NULL);
3380 }
3381
3382 /*
3383 * Format and send reply containing system error number.
3384 */
3385 void
3386 perror_reply(int code, const char *string)
3387 {
3388 int save_errno;
3389
3390 save_errno = errno;
3391 reply(code, "%s: %s.", string, strerror(errno));
3392 errno = save_errno;
3393 }
3394
3395 static char *onefile[] = {
3396 NULL,
3397 0
3398 };
3399
3400 void
3401 send_file_list(const char *whichf)
3402 {
3403 struct stat st;
3404 DIR *dirp;
3405 struct dirent *dir;
3406 FILE *volatile dout;
3407 char **volatile dirlist;
3408 char *dirname, *p;
3409 char *notglob;
3410 int volatile simple;
3411 int volatile freeglob;
3412 glob_t gl;
3413
3414 dirp = NULL;
3415 dout = NULL;
3416 notglob = NULL;
3417 simple = 0;
3418 freeglob = 0;
3419 urgflag = 0;
3420
3421 p = NULL;
3422 if (strpbrk(whichf, "~{[*?") != NULL) {
3423 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
3424
3425 memset(&gl, 0, sizeof(gl));
3426 freeglob = 1;
3427 if (glob(whichf, flags, 0, &gl)) {
3428 reply(450, "Not found");
3429 goto cleanup_send_file_list;
3430 } else if (gl.gl_pathc == 0) {
3431 errno = ENOENT;
3432 perror_reply(450, whichf);
3433 goto cleanup_send_file_list;
3434 }
3435 dirlist = gl.gl_pathv;
3436 } else {
3437 notglob = ftpd_strdup(whichf);
3438 onefile[0] = notglob;
3439 dirlist = onefile;
3440 simple = 1;
3441 }
3442 /* XXX: } for vi sm */
3443
3444 while ((dirname = *dirlist++) != NULL) {
3445 int trailingslash = 0;
3446
3447 if (stat(dirname, &st) < 0) {
3448 /*
3449 * If user typed "ls -l", etc, and the client
3450 * used NLST, do what the user meant.
3451 */
3452 /* XXX: nuke this support? */
3453 if (dirname[0] == '-' && *dirlist == NULL &&
3454 transflag == 0) {
3455 const char *argv[] = { INTERNAL_LS, "", NULL };
3456
3457 argv[1] = dirname;
3458 retrieve(argv, dirname);
3459 goto cleanup_send_file_list;
3460 }
3461 perror_reply(450, whichf);
3462 goto cleanup_send_file_list;
3463 }
3464
3465 if (S_ISREG(st.st_mode)) {
3466 /*
3467 * XXXRFC:
3468 * should we follow RFC959 and not work
3469 * for non directories?
3470 */
3471 if (dout == NULL) {
3472 dout = dataconn("file list", (off_t)-1, "w");
3473 if (dout == NULL)
3474 goto cleanup_send_file_list;
3475 transflag = 1;
3476 }
3477 cprintf(dout, "%s%s\n", dirname,
3478 type == TYPE_A ? "\r" : "");
3479 continue;
3480 } else if (!S_ISDIR(st.st_mode))
3481 continue;
3482
3483 if (dirname[strlen(dirname) - 1] == '/')
3484 trailingslash++;
3485
3486 if ((dirp = opendir(dirname)) == NULL)
3487 continue;
3488
3489 while ((dir = readdir(dirp)) != NULL) {
3490 char nbuf[MAXPATHLEN];
3491
3492 if (urgflag && handleoobcmd()) {
3493 (void) closedir(dirp);
3494 goto cleanup_send_file_list;
3495 }
3496
3497 if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name))
3498 continue;
3499
3500 (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
3501 trailingslash ? "" : "/", dir->d_name);
3502
3503 /*
3504 * We have to do a stat to ensure it's
3505 * not a directory or special file.
3506 */
3507 /*
3508 * XXXRFC:
3509 * should we follow RFC959 and filter out
3510 * non files ? lukem - NO!, or not until
3511 * our ftp client uses MLS{T,D} for completion.
3512 */
3513 if (simple || (stat(nbuf, &st) == 0 &&
3514 S_ISREG(st.st_mode))) {
3515 if (dout == NULL) {
3516 dout = dataconn("file list", (off_t)-1,
3517 "w");
3518 if (dout == NULL) {
3519 (void) closedir(dirp);
3520 goto cleanup_send_file_list;
3521 }
3522 transflag = 1;
3523 }
3524 p = nbuf;
3525 if (nbuf[0] == '.' && nbuf[1] == '/')
3526 p = &nbuf[2];
3527 cprintf(dout, "%s%s\n", p,
3528 type == TYPE_A ? "\r" : "");
3529 }
3530 }
3531 (void) closedir(dirp);
3532 }
3533
3534 if (dout == NULL)
3535 reply(450, "No files found.");
3536 else if (ferror(dout) != 0)
3537 perror_reply(451, "Data connection");
3538 else
3539 reply(226, "Transfer complete.");
3540
3541 cleanup_send_file_list:
3542 closedataconn(dout);
3543 transflag = 0;
3544 urgflag = 0;
3545 total_xfers++;
3546 total_xfers_out++;
3547 if (notglob)
3548 free(notglob);
3549 if (freeglob)
3550 globfree(&gl);
3551 }
3552
3553 char *
3554 conffilename(const char *s)
3555 {
3556 static char filename[MAXPATHLEN];
3557
3558 if (*s == '/')
3559 strlcpy(filename, s, sizeof(filename));
3560 else
3561 (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
3562 return (filename);
3563 }
3564
3565 /*
3566 * logxfer --
3567 * if logging > 1, then based on the arguments, syslog a message:
3568 * if bytes != -1 "<command> <file1> = <bytes> bytes"
3569 * else if file2 != NULL "<command> <file1> <file2>"
3570 * else "<command> <file1>"
3571 * if elapsed != NULL, append "in xxx.yyy seconds"
3572 * if error != NULL, append ": " + error
3573 *
3574 * if doxferlog != 0, bytes != -1, and command is "get", "put",
3575 * or "append", syslog and/or write a wu-ftpd style xferlog entry
3576 */
3577 void
3578 logxfer(const char *command, off_t bytes, const char *file1, const char *file2,
3579 const struct timeval *elapsed, const char *error)
3580 {
3581 char buf[MAXPATHLEN * 2 + 100];
3582 char realfile1[MAXPATHLEN], realfile2[MAXPATHLEN];
3583 const char *r1, *r2;
3584 char direction;
3585 size_t len;
3586 time_t now;
3587
3588 if (logging <=1 && !doxferlog)
3589 return;
3590
3591 r1 = r2 = NULL;
3592 if ((r1 = realpath(file1, realfile1)) == NULL)
3593 r1 = file1;
3594 if (file2 != NULL)
3595 if ((r2 = realpath(file2, realfile2)) == NULL)
3596 r2 = file2;
3597
3598 /*
3599 * syslog command
3600 */
3601 if (logging > 1) {
3602 len = snprintf(buf, sizeof(buf), "%s %s", command, r1);
3603 if (bytes != (off_t)-1)
3604 len += snprintf(buf + len, sizeof(buf) - len,
3605 " = " LLF " byte%s", (LLT) bytes, PLURAL(bytes));
3606 else if (r2 != NULL)
3607 len += snprintf(buf + len, sizeof(buf) - len,
3608 " %s", r2);
3609 if (elapsed != NULL)
3610 len += snprintf(buf + len, sizeof(buf) - len,
3611 " in " LLF ".%.03ld seconds",
3612 (LLT)elapsed->tv_sec,
3613 (long)(elapsed->tv_usec / 1000));
3614 if (error != NULL)
3615 len += snprintf(buf + len, sizeof(buf) - len,
3616 ": %s", error);
3617 syslog(LOG_INFO, "%s", buf);
3618 }
3619
3620 /*
3621 * syslog wu-ftpd style log entry, prefixed with "xferlog: "
3622 */
3623 if (!doxferlog || bytes == -1)
3624 return;
3625
3626 if (strcmp(command, "get") == 0)
3627 direction = 'o';
3628 else if (strcmp(command, "put") == 0 || strcmp(command, "append") == 0)
3629 direction = 'i';
3630 else
3631 return;
3632
3633 time(&now);
3634 len = snprintf(buf, sizeof(buf),
3635 "%.24s " LLF " %s " LLF " %s %c %s %c %c %s FTP 0 * %c\n",
3636
3637 /*
3638 * XXX: wu-ftpd puts ' (send)' or ' (recv)' in the syslog message, and removes
3639 * the full date. This may be problematic for accurate log parsing,
3640 * given that syslog messages don't contain the full date.
3641 */
3642 ctime(&now),
3643 (LLT)
3644 (elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0)),
3645 remotehost,
3646 (LLT) bytes,
3647 r1,
3648 type == TYPE_A ? 'a' : 'b',
3649 "_", /* XXX: take conversions into account? */
3650 direction,
3651
3652 curclass.type == CLASS_GUEST ? 'a' :
3653 curclass.type == CLASS_CHROOT ? 'g' :
3654 curclass.type == CLASS_REAL ? 'r' : '?',
3655
3656 curclass.type == CLASS_GUEST ? pw->pw_passwd : pw->pw_name,
3657 error != NULL ? 'i' : 'c'
3658 );
3659
3660 if ((doxferlog & 2) && xferlogfd != -1)
3661 write(xferlogfd, buf, len);
3662 if ((doxferlog & 1)) {
3663 buf[len-1] = '\n'; /* strip \n from syslog message */
3664 syslog(LOG_INFO, "xferlog: %s", buf);
3665 }
3666 }
3667
3668 /*
3669 * Log the resource usage.
3670 *
3671 * XXX: more resource usage to logging?
3672 */
3673 void
3674 logrusage(const struct rusage *rusage_before,
3675 const struct rusage *rusage_after)
3676 {
3677 struct timeval usrtime, systime;
3678
3679 if (logging <= 1)
3680 return;
3681
3682 timersub(&rusage_after->ru_utime, &rusage_before->ru_utime, &usrtime);
3683 timersub(&rusage_after->ru_stime, &rusage_before->ru_stime, &systime);
3684 syslog(LOG_INFO, LLF ".%.03ldu " LLF ".%.03lds %ld+%ldio %ldpf+%ldw",
3685 (LLT)usrtime.tv_sec, (long)(usrtime.tv_usec / 1000),
3686 (LLT)systime.tv_sec, (long)(systime.tv_usec / 1000),
3687 rusage_after->ru_inblock - rusage_before->ru_inblock,
3688 rusage_after->ru_oublock - rusage_before->ru_oublock,
3689 rusage_after->ru_majflt - rusage_before->ru_majflt,
3690 rusage_after->ru_nswap - rusage_before->ru_nswap);
3691 }
3692
3693 /*
3694 * Determine if `password' is valid for user given in `pw'.
3695 * Returns 2 if password expired, 1 if otherwise failed, 0 if ok
3696 */
3697 int
3698 checkpassword(const struct passwd *pwent, const char *password)
3699 {
3700 const char *orig;
3701 char *new;
3702 time_t change, expire, now;
3703
3704 change = expire = 0;
3705 if (pwent == NULL)
3706 return 1;
3707
3708 time(&now);
3709 orig = pwent->pw_passwd; /* save existing password */
3710 expire = pwent->pw_expire;
3711 change = pwent->pw_change;
3712 if (change == _PASSWORD_CHGNOW)
3713 change = now;
3714
3715 if (orig[0] == '\0') /* don't allow empty passwords */
3716 return 1;
3717
3718 new = crypt(password, orig); /* encrypt given password */
3719 if (strcmp(new, orig) != 0) /* compare */
3720 return 1;
3721
3722 if ((expire && now >= expire) || (change && now >= change))
3723 return 2; /* check if expired */
3724
3725 return 0; /* OK! */
3726 }
3727
3728 char *
3729 ftpd_strdup(const char *s)
3730 {
3731 char *new = strdup(s);
3732
3733 if (new == NULL)
3734 fatal("Local resource failure: malloc");
3735 /* NOTREACHED */
3736 return (new);
3737 }
3738
3739 /*
3740 * As per fprintf(), but increment total_bytes and total_bytes_out,
3741 * by the appropriate amount.
3742 */
3743 void
3744 cprintf(FILE *fd, const char *fmt, ...)
3745 {
3746 off_t b;
3747 va_list ap;
3748
3749 va_start(ap, fmt);
3750 b = vfprintf(fd, fmt, ap);
3751 va_end(ap);
3752 total_bytes += b;
3753 total_bytes_out += b;
3754 }
3755
3756 #ifdef USE_PAM
3757 /*
3758 * the following code is stolen from imap-uw PAM authentication module and
3759 * login.c
3760 */
3761 typedef struct {
3762 const char *uname; /* user name */
3763 int triedonce; /* if non-zero, tried before */
3764 } ftpd_cred_t;
3765
3766 static int
3767 auth_conv(int num_msg, const struct pam_message **msg,
3768 struct pam_response **resp, void *appdata)
3769 {
3770 int i, ret;
3771 size_t n;
3772 ftpd_cred_t *cred = (ftpd_cred_t *) appdata;
3773 struct pam_response *myreply;
3774 char pbuf[FTP_BUFLEN];
3775
3776 if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
3777 return (PAM_CONV_ERR);
3778 myreply = calloc(num_msg, sizeof *myreply);
3779 if (myreply == NULL)
3780 return PAM_BUF_ERR;
3781
3782 for (i = 0; i < num_msg; i++) {
3783 myreply[i].resp_retcode = 0;
3784 myreply[i].resp = NULL;
3785 switch (msg[i]->msg_style) {
3786 case PAM_PROMPT_ECHO_ON: /* user */
3787 myreply[i].resp = ftpd_strdup(cred->uname);
3788 /* PAM frees resp. */
3789 break;
3790 case PAM_PROMPT_ECHO_OFF: /* authtok (password) */
3791 /*
3792 * Only send a single 331 reply and
3793 * then expect a PASS.
3794 */
3795 if (cred->triedonce) {
3796 syslog(LOG_ERR,
3797 "auth_conv: already performed PAM_PROMPT_ECHO_OFF");
3798 goto fail;
3799 }
3800 cred->triedonce++;
3801 if (msg[i]->msg[0] == '\0') {
3802 (void)strlcpy(pbuf, "password", sizeof(pbuf));
3803 } else {
3804 /* Uncapitalize msg */
3805 (void)strlcpy(pbuf, msg[i]->msg, sizeof(pbuf));
3806 if (isupper((unsigned char)pbuf[0]))
3807 pbuf[0] = tolower(
3808 (unsigned char)pbuf[0]);
3809 /* Remove trailing ':' and whitespace */
3810 n = strlen(pbuf);
3811 while (n-- > 0) {
3812 if (isspace((unsigned char)pbuf[n]) ||
3813 pbuf[n] == ':')
3814 pbuf[n] = '\0';
3815 else
3816 break;
3817 }
3818 }
3819 /* Send reply, wait for a response. */
3820 reply(331, "User %s accepted, provide %s.",
3821 cred->uname, pbuf);
3822 (void) alarm(curclass.timeout);
3823 ret = get_line(pbuf, sizeof(pbuf)-1, stdin);
3824 (void) alarm(0);
3825 if (ret == -1) {
3826 reply(221, "You could at least say goodbye.");
3827 dologout(0);
3828 } else if (ret == -2) {
3829 /* XXX: should we do this reply(-530, ..) ? */
3830 reply(-530, "Command too long.");
3831 goto fail;
3832 }
3833 /* Ensure it is PASS */
3834 if (strncasecmp(pbuf, "PASS ", 5) != 0) {
3835 syslog(LOG_ERR,
3836 "auth_conv: unexpected reply '%.4s'", pbuf);
3837 /* XXX: should we do this reply(-530, ..) ? */
3838 reply(-530, "Unexpected reply '%.4s'.", pbuf);
3839 goto fail;
3840 }
3841 /* Strip CRLF from "PASS" reply */
3842 n = strlen(pbuf);
3843 while (--n >= 5 &&
3844 (pbuf[n] == '\r' || pbuf[n] == '\n'))
3845 pbuf[n] = '\0';
3846 /* Copy password into reply */
3847 myreply[i].resp = ftpd_strdup(pbuf+5);
3848 /* PAM frees resp. */
3849 break;
3850 case PAM_TEXT_INFO:
3851 case PAM_ERROR_MSG:
3852 break;
3853 default: /* unknown message style */
3854 goto fail;
3855 }
3856 }
3857
3858 *resp = myreply;
3859 return PAM_SUCCESS;
3860
3861 fail:
3862 free(myreply);
3863 *resp = NULL;
3864 return PAM_CONV_ERR;
3865 }
3866
3867 /*
3868 * Attempt to authenticate the user using PAM. Returns 0 if the user is
3869 * authenticated, or 1 if not authenticated. If some sort of PAM system
3870 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
3871 * function returns -1. This can be used as an indication that we should
3872 * fall back to a different authentication mechanism.
3873 * pw maybe be updated to a new user if PAM_USER changes from curname.
3874 */
3875 static int
3876 auth_pam(void)
3877 {
3878 const char *tmpl_user;
3879 const void *item;
3880 int rval;
3881 int e;
3882 ftpd_cred_t auth_cred = { curname, 0 };
3883 struct pam_conv conv = { &auth_conv, &auth_cred };
3884
3885 e = pam_start("ftpd", curname, &conv, &pamh);
3886 if (e != PAM_SUCCESS) {
3887 /*
3888 * In OpenPAM, it's OK to pass NULL to pam_strerror()
3889 * if context creation has failed in the first place.
3890 */
3891 syslog(LOG_ERR, "pam_start: %s", pam_strerror(NULL, e));
3892 return -1;
3893 }
3894
3895 e = pam_set_item(pamh, PAM_RHOST, remotehost);
3896 if (e != PAM_SUCCESS) {
3897 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
3898 pam_strerror(pamh, e));
3899 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3900 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3901 }
3902 pamh = NULL;
3903 return -1;
3904 }
3905
3906 e = pam_set_item(pamh, PAM_SOCKADDR, &his_addr);
3907 if (e != PAM_SUCCESS) {
3908 syslog(LOG_ERR, "pam_set_item(PAM_SOCKADDR): %s",
3909 pam_strerror(pamh, e));
3910 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3911 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3912 }
3913 pamh = NULL;
3914 return -1;
3915 }
3916
3917 e = pam_authenticate(pamh, 0);
3918 if (ftpd_debug)
3919 syslog(LOG_DEBUG, "pam_authenticate: user '%s' returned %d",
3920 curname, e);
3921 switch (e) {
3922 case PAM_SUCCESS:
3923 /*
3924 * With PAM we support the concept of a "template"
3925 * user. The user enters a login name which is
3926 * authenticated by PAM, usually via a remote service
3927 * such as RADIUS or TACACS+. If authentication
3928 * succeeds, a different but related "template" name
3929 * is used for setting the credentials, shell, and
3930 * home directory. The name the user enters need only
3931 * exist on the remote authentication server, but the
3932 * template name must be present in the local password
3933 * database.
3934 *
3935 * This is supported by two various mechanisms in the
3936 * individual modules. However, from the application's
3937 * point of view, the template user is always passed
3938 * back as a changed value of the PAM_USER item.
3939 */
3940 if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
3941 PAM_SUCCESS) {
3942 tmpl_user = (const char *) item;
3943 if (pw == NULL
3944 || strcmp(pw->pw_name, tmpl_user) != 0) {
3945 pw = sgetpwnam(tmpl_user);
3946 if (ftpd_debug)
3947 syslog(LOG_DEBUG,
3948 "auth_pam: PAM changed "
3949 "user from '%s' to '%s'",
3950 curname, pw->pw_name);
3951 (void)strlcpy(curname, pw->pw_name,
3952 curname_len);
3953 }
3954 } else
3955 syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
3956 pam_strerror(pamh, e));
3957 rval = 0;
3958 break;
3959
3960 case PAM_AUTH_ERR:
3961 case PAM_USER_UNKNOWN:
3962 case PAM_MAXTRIES:
3963 rval = 1;
3964 break;
3965
3966 default:
3967 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
3968 rval = -1;
3969 break;
3970 }
3971
3972 if (rval == 0) {
3973 e = pam_acct_mgmt(pamh, 0);
3974 if (e != PAM_SUCCESS) {
3975 syslog(LOG_ERR, "pam_acct_mgmt: %s",
3976 pam_strerror(pamh, e));
3977 rval = 1;
3978 }
3979 }
3980
3981 if (rval != 0) {
3982 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3983 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3984 }
3985 pamh = NULL;
3986 }
3987 return rval;
3988 }
3989
3990 #endif /* USE_PAM */
3991