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