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