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