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