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