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