ftpd.c revision 1.66 1 /* $NetBSD: ftpd.c,v 1.66 1999/06/05 13:49:53 briggs Exp $ */
2
3 /*
4 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 /*
37 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
38 * All rights reserved.
39 *
40 * This code is derived from software contributed to The NetBSD Foundation
41 * by Luke Mewburn.
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 NetBSD
54 * Foundation, Inc. and its contributors.
55 * 4. Neither the name of The NetBSD Foundation nor the names of its
56 * contributors may be used to endorse or promote products derived
57 * from this software without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 * POSSIBILITY OF SUCH DAMAGE.
70 */
71
72 #include <sys/cdefs.h>
73 #ifndef lint
74 __COPYRIGHT(
75 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
76 The Regents of the University of California. All rights reserved.\n");
77 #endif /* not lint */
78
79 #ifndef lint
80 #if 0
81 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
82 #else
83 __RCSID("$NetBSD: ftpd.c,v 1.66 1999/06/05 13:49:53 briggs Exp $");
84 #endif
85 #endif /* not lint */
86
87 /*
88 * FTP server.
89 */
90 #include <sys/param.h>
91 #include <sys/stat.h>
92 #include <sys/ioctl.h>
93 #include <sys/socket.h>
94 #include <sys/wait.h>
95
96 #include <netinet/in.h>
97 #include <netinet/in_systm.h>
98 #include <netinet/ip.h>
99
100 #define FTP_NAMES
101 #include <arpa/ftp.h>
102 #include <arpa/inet.h>
103 #include <arpa/telnet.h>
104
105 #include <ctype.h>
106 #include <dirent.h>
107 #include <err.h>
108 #include <errno.h>
109 #include <fcntl.h>
110 #include <fnmatch.h>
111 #include <glob.h>
112 #include <limits.h>
113 #include <netdb.h>
114 #include <pwd.h>
115 #include <setjmp.h>
116 #include <signal.h>
117 #include <stdio.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <syslog.h>
121 #include <time.h>
122 #include <unistd.h>
123 #ifdef SKEY
124 #include <skey.h>
125 #endif
126 #ifdef KERBEROS5
127 #include <krb5.h>
128 #endif
129
130 #include "extern.h"
131 #include "pathnames.h"
132
133 #if __STDC__
134 #include <stdarg.h>
135 #else
136 #include <varargs.h>
137 #endif
138
139 #ifndef TRUE
140 #define TRUE 1
141 #define FALSE 0
142 #endif
143
144 const char version[] = "Version: 7.2.0";
145
146 struct sockaddr_in ctrl_addr;
147 struct sockaddr_in data_source;
148 struct sockaddr_in data_dest;
149 struct sockaddr_in his_addr;
150 struct sockaddr_in pasv_addr;
151
152 int data;
153 jmp_buf errcatch, urgcatch;
154 int logged_in;
155 struct passwd *pw;
156 int debug;
157 int sflag;
158 int logging;
159 int guest;
160 int dochroot;
161 int type;
162 int form;
163 int stru; /* avoid C keyword */
164 int mode;
165 int usedefault = 1; /* for data transfers */
166 int pdata = -1; /* for passive mode */
167 sig_atomic_t transflag;
168 off_t file_size;
169 off_t byte_count;
170 char tmpline[7];
171 char hostname[MAXHOSTNAMELEN+1];
172 char remotehost[MAXHOSTNAMELEN+1];
173 static char ttyline[20];
174 char *tty = ttyline; /* for klogin */
175
176 off_t total_data_in; /* total file data bytes received */
177 off_t total_data_out; /* total file data bytes sent data */
178 off_t total_data; /* total file data bytes transferred data */
179 off_t total_files_in; /* total number of data files received */
180 off_t total_files_out; /* total number of data files sent */
181 off_t total_files; /* total number of data files transferred */
182 off_t total_bytes_in; /* total bytes received */
183 off_t total_bytes_out; /* total bytes sent */
184 off_t total_bytes; /* total bytes transferred */
185 off_t total_xfers_in; /* total number of xfers incoming */
186 off_t total_xfers_out; /* total number of xfers outgoing */
187 off_t total_xfers; /* total number of xfers */
188
189 static char *anondir = NULL;
190 static char confdir[MAXPATHLEN];
191
192 #if defined(KERBEROS) || defined(KERBEROS5)
193 int notickets = 1;
194 char *krbtkfile_env = NULL;
195 #endif
196
197 /*
198 * Timeout intervals for retrying connections
199 * to hosts that don't accept PORT cmds. This
200 * is a kludge, but given the problems with TCP...
201 */
202 #define SWAITMAX 90 /* wait at most 90 seconds */
203 #define SWAITINT 5 /* interval between retries */
204
205 int swaitmax = SWAITMAX;
206 int swaitint = SWAITINT;
207
208 #ifdef HASSETPROCTITLE
209 char proctitle[BUFSIZ]; /* initial part of title */
210 #endif /* HASSETPROCTITLE */
211
212 static void ack __P((const char *));
213 static void myoob __P((int));
214 static int checkuser __P((const char *, const char *, int, int));
215 static int checkaccess __P((const char *));
216 static FILE *dataconn __P((const char *, off_t, const char *));
217 static void dolog __P((struct sockaddr_in *));
218 static void end_login __P((void));
219 static FILE *getdatasock __P((const char *));
220 static char *gunique __P((const char *));
221 static void lostconn __P((int));
222 static int receive_data __P((FILE *, FILE *));
223 static void replydirname __P((const char *, const char *));
224 static int send_data __P((FILE *, FILE *, off_t, int));
225 static struct passwd *
226 sgetpwnam __P((const char *));
227
228 int main __P((int, char *[]));
229
230 #if defined(KERBEROS) || defined(KERBEROS5)
231 int klogin __P((struct passwd *, char *, char *, char *));
232 void kdestroy __P((void));
233 #endif
234
235 int
236 main(argc, argv)
237 int argc;
238 char *argv[];
239 {
240 int addrlen, ch, on = 1, tos, keepalive;
241 char *cp, line[LINE_MAX];
242 FILE *fd;
243 #ifdef KERBEROS5
244 krb5_error_code kerror;
245 #endif
246
247 debug = 0;
248 logging = 0;
249 sflag = 0;
250 (void)strcpy(confdir, _DEFAULT_CONFDIR);
251
252 while ((ch = getopt(argc, argv, "a:c:C:dlst:T:u:v")) != -1) {
253 switch (ch) {
254 case 'a':
255 anondir = optarg;
256 break;
257
258 case 'c':
259 (void)strncpy(confdir, optarg, sizeof(confdir));
260 confdir[sizeof(confdir)-1] = '\0';
261 break;
262
263 case 'C':
264 exit(checkaccess(optarg));
265 /* NOTREACHED */
266
267 case 'd':
268 case 'v': /* deprecated */
269 debug = 1;
270 break;
271
272 case 'l':
273 logging++; /* > 1 == extra logging */
274 break;
275
276 case 's':
277 sflag = 1;
278 break;
279
280 case 't':
281 case 'T':
282 case 'u':
283 warnx("-%c has been deprecated in favour of ftpd.conf",
284 ch);
285 break;
286
287 default:
288 if (optopt == 'a' || optopt == 'C')
289 exit(1);
290 warnx("unknown flag -%c ignored", optopt);
291 break;
292 }
293 }
294
295 /*
296 * LOG_NDELAY sets up the logging connection immediately,
297 * necessary for anonymous ftp's that chroot and can't do it later.
298 */
299 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
300 addrlen = sizeof(his_addr);
301 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
302 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
303 exit(1);
304 }
305 addrlen = sizeof(ctrl_addr);
306 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
307 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
308 exit(1);
309 }
310 #ifdef IP_TOS
311 tos = IPTOS_LOWDELAY;
312 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
313 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
314 #endif
315 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
316
317 /* set this here so klogin can use it... */
318 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
319
320 (void) freopen(_PATH_DEVNULL, "w", stderr);
321 (void) signal(SIGPIPE, lostconn);
322 (void) signal(SIGCHLD, SIG_IGN);
323 if ((long)signal(SIGURG, myoob) < 0)
324 syslog(LOG_ERR, "signal: %m");
325
326 /* Try to handle urgent data inline */
327 #ifdef SO_OOBINLINE
328 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
329 syslog(LOG_ERR, "setsockopt: %m");
330 #endif
331 /* Set keepalives on the socket to detect dropped connections. */
332 #ifdef SO_KEEPALIVE
333 keepalive = 1;
334 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
335 sizeof(int)) < 0)
336 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
337 #endif
338
339 #ifdef F_SETOWN
340 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
341 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
342 #endif
343 dolog(&his_addr);
344 /*
345 * Set up default state
346 */
347 data = -1;
348 type = TYPE_A;
349 form = FORM_N;
350 stru = STRU_F;
351 mode = MODE_S;
352 tmpline[0] = '\0';
353 hasyyerrored = 0;
354
355 #ifdef KERBEROS5
356 kerror = krb5_init_context(&kcontext);
357 if (kerror) {
358 syslog(LOG_NOTICE, "%s when initializing Kerberos context",
359 error_message(kerror));
360 exit(0);
361 }
362 #endif /* KERBEROS5 */
363
364 /* If logins are disabled, print out the message. */
365 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
366 lreply(530, "");
367 while (fgets(line, sizeof(line), fd) != NULL) {
368 if ((cp = strchr(line, '\n')) != NULL)
369 *cp = '\0';
370 lreply(0, "%s", line);
371 }
372 (void) fflush(stdout);
373 (void) fclose(fd);
374 reply(530, "System not available.");
375 exit(0);
376 }
377 if ((fd = fopen(conffilename(_PATH_FTPWELCOME), "r")) != NULL) {
378 lreply(220, "");
379 while (fgets(line, sizeof(line), fd) != NULL) {
380 if ((cp = strchr(line, '\n')) != NULL)
381 *cp = '\0';
382 lreply(0, "%s", line);
383 }
384 (void) fflush(stdout);
385 (void) fclose(fd);
386 /* reply(220,) must follow */
387 }
388 (void)gethostname(hostname, sizeof(hostname));
389 hostname[sizeof(hostname) - 1] = '\0';
390 reply(220, "%s FTP server (%s) ready.", hostname, version);
391 curclass.timeout = 300; /* 5 minutes, as per login(1) */
392 (void) setjmp(errcatch);
393 for (;;)
394 (void) yyparse();
395 /* NOTREACHED */
396 }
397
398 static void
399 lostconn(signo)
400 int signo;
401 {
402
403 if (debug)
404 syslog(LOG_DEBUG, "lost connection");
405 dologout(1);
406 }
407
408 /*
409 * Save the result of a getpwnam. Used for USER command, since
410 * the data returned must not be clobbered by any other command
411 * (e.g., globbing).
412 */
413 static struct passwd *
414 sgetpwnam(name)
415 const char *name;
416 {
417 static struct passwd save;
418 struct passwd *p;
419
420 if ((p = getpwnam(name)) == NULL)
421 return (p);
422 if (save.pw_name) {
423 free((char *)save.pw_name);
424 free((char *)save.pw_passwd);
425 free((char *)save.pw_gecos);
426 free((char *)save.pw_dir);
427 free((char *)save.pw_shell);
428 }
429 save = *p;
430 save.pw_name = xstrdup(p->pw_name);
431 save.pw_passwd = xstrdup(p->pw_passwd);
432 save.pw_gecos = xstrdup(p->pw_gecos);
433 save.pw_dir = xstrdup(p->pw_dir);
434 save.pw_shell = xstrdup(p->pw_shell);
435 return (&save);
436 }
437
438 static int login_attempts; /* number of failed login attempts */
439 static int askpasswd; /* had user command, ask for passwd */
440 static char curname[10]; /* current USER name */
441
442 /*
443 * USER command.
444 * Sets global passwd pointer pw if named account exists and is acceptable;
445 * sets askpasswd if a PASS command is expected. If logged in previously,
446 * need to reset state. If name is "ftp" or "anonymous", the name is not in
447 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
448 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
449 * requesting login privileges. Disallow anyone who does not have a standard
450 * shell as returned by getusershell(). Disallow anyone mentioned in the file
451 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
452 */
453 void
454 user(name)
455 const char *name;
456 {
457 if (logged_in) {
458 if (guest) {
459 reply(530, "Can't change user from guest login.");
460 return;
461 } else if (dochroot) {
462 reply(530, "Can't change user from chroot user.");
463 return;
464 }
465 end_login();
466 }
467
468 #if defined(KERBEROS) || defined(KERBEROS5)
469 kdestroy();
470 #endif
471
472 guest = 0;
473 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
474 if (checkaccess("ftp") || checkaccess("anonymous"))
475 reply(530, "User %s access denied.", name);
476 else if ((pw = sgetpwnam("ftp")) != NULL) {
477 guest = 1;
478 askpasswd = 1;
479 reply(331,
480 "Guest login ok, type your name as password.");
481 } else
482 reply(530, "User %s unknown.", name);
483 if (!askpasswd && logging)
484 syslog(LOG_NOTICE,
485 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
486 return;
487 }
488
489 pw = sgetpwnam(name);
490 if (logging)
491 strncpy(curname, name, sizeof(curname)-1);
492
493 #ifdef SKEY
494 if (skey_haskey(name) == 0) {
495 char *myskey;
496
497 myskey = skey_keyinfo(name);
498 reply(331, "Password [%s] required for %s.",
499 myskey ? myskey : "error getting challenge", name);
500 } else
501 #endif
502 reply(331, "Password required for %s.", name);
503
504 askpasswd = 1;
505 /*
506 * Delay before reading passwd after first failed
507 * attempt to slow down passwd-guessing programs.
508 */
509 if (login_attempts)
510 sleep((unsigned) login_attempts);
511 }
512
513 /*
514 * Determine whether something is to happen (allow access, chroot)
515 * for a user. Each line is a shell-style glob followed by
516 * `yes' or `no'.
517 *
518 * For backward compatability, `allow' and `deny' are synonymns
519 * for `yes' and `no', respectively.
520 *
521 * Each glob is matched against the username in turn, and the first
522 * match found is used. If no match is found, the result is the
523 * argument `def'. If a match is found but without and explicit
524 * `yes'/`no', the result is the opposite of def.
525 *
526 * If the file doesn't exist at all, the result is the argument
527 * `nofile'
528 *
529 * Any line starting with `#' is considered a comment and ignored.
530 *
531 * Returns FALSE if the user is denied, or TRUE if they are allowed.
532 */
533 int
534 checkuser(fname, name, def, nofile)
535 const char *fname, *name;
536 int def, nofile;
537 {
538 FILE *fd;
539 int retval;
540 char *glob, *perm, line[BUFSIZ];
541
542 retval = def;
543 if ((fd = fopen(conffilename(fname), "r")) == NULL)
544 return nofile;
545
546 while (fgets(line, sizeof(line), fd) != NULL) {
547 glob = strtok(line, " \t\n");
548 if (glob[0] == '#')
549 continue;
550 perm = strtok(NULL, " \t\n");
551 if (fnmatch(glob, name, 0) == 0) {
552 if (perm != NULL &&
553 ((strcasecmp(perm, "allow") == 0) ||
554 (strcasecmp(perm, "yes") == 0)))
555 retval = TRUE;
556 else if (perm != NULL &&
557 ((strcasecmp(perm, "deny") == 0) ||
558 (strcasecmp(perm, "no") == 0)))
559 retval = FALSE;
560 else
561 retval = !def;
562 break;
563 }
564 }
565 (void) fclose(fd);
566 return (retval);
567 }
568
569 /*
570 * Check if user is allowed by /etc/ftpusers
571 * returns 0 for yes, 1 for no
572 */
573 int
574 checkaccess(name)
575 const char *name;
576 {
577
578 return (! checkuser(_PATH_FTPUSERS, name, TRUE, FALSE));
579 }
580
581 /*
582 * Terminate login as previous user, if any, resetting state;
583 * used when USER command is given or login fails.
584 */
585 static void
586 end_login()
587 {
588
589 (void) seteuid((uid_t)0);
590 if (logged_in)
591 logwtmp(ttyline, "", "");
592 pw = NULL;
593 logged_in = 0;
594 guest = 0;
595 dochroot = 0;
596 }
597
598 void
599 pass(passwd)
600 const char *passwd;
601 {
602 int rval;
603 FILE *fd;
604 char const *cp, *shell, *home;
605
606 if (logged_in || askpasswd == 0) {
607 reply(503, "Login with USER first.");
608 return;
609 }
610 askpasswd = 0;
611 if (!guest) { /* "ftp" is only account allowed no password */
612 if (pw == NULL) {
613 rval = 1; /* failure below */
614 goto skip;
615 }
616 #ifdef KERBEROS
617 if (klogin(pw, "", hostname, (char *)passwd) == 0) {
618 rval = 0;
619 goto skip;
620 }
621 #endif
622 #ifdef KERBEROS5
623 if (klogin(pw, "", hostname, (char *)passwd) == 0) {
624 rval = 0;
625 goto skip;
626 }
627 #endif
628 #ifdef SKEY
629 if (skey_haskey(pw->pw_name) == 0) {
630 char *p;
631 int r;
632
633 p = xstrdup(passwd);
634 r = skey_passcheck(pw->pw_name, p);
635 free(p);
636 if (r != -1) {
637 rval = 0;
638 goto skip;
639 }
640 }
641 #endif
642 if (!sflag && *pw->pw_passwd != '\0' &&
643 !strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) {
644 rval = 0;
645 goto skip;
646 }
647 rval = 1;
648
649 skip:
650 if (pw != NULL && pw->pw_expire && time(NULL) >= pw->pw_expire)
651 rval = 2;
652 /*
653 * If rval > 0, the user failed the authentication check
654 * above. If rval == 0, either Kerberos or local authentication
655 * succeeded.
656 */
657 if (rval) {
658 reply(530, rval == 2 ? "Password expired." :
659 "Login incorrect.");
660 if (logging) {
661 syslog(LOG_NOTICE,
662 "FTP LOGIN FAILED FROM %s", remotehost);
663 syslog(LOG_AUTHPRIV | LOG_NOTICE,
664 "FTP LOGIN FAILED FROM %s, %s",
665 remotehost, curname);
666 }
667 pw = NULL;
668 if (login_attempts++ >= 5) {
669 syslog(LOG_NOTICE,
670 "repeated login failures from %s",
671 remotehost);
672 exit(0);
673 }
674 return;
675 }
676 }
677
678 /* password was ok; see if anything else prevents login */
679 if (checkaccess(pw->pw_name)) {
680 reply(530, "User %s may not use FTP.", pw->pw_name);
681 if (logging)
682 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
683 remotehost, pw->pw_name);
684 pw = (struct passwd *) NULL;
685 return;
686 }
687 /* check for valid shell, if not guest user */
688 if ((shell = pw->pw_shell) == NULL || *shell == 0)
689 shell = _PATH_BSHELL;
690 while ((cp = getusershell()) != NULL)
691 if (strcmp(cp, shell) == 0)
692 break;
693 endusershell();
694 if (cp == NULL && guest == 0) {
695 reply(530, "User %s may not use FTP.", pw->pw_name);
696 if (logging)
697 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
698 remotehost, pw->pw_name);
699 pw = (struct passwd *) NULL;
700 return;
701 }
702
703 login_attempts = 0; /* this time successful */
704 if (setegid((gid_t)pw->pw_gid) < 0) {
705 reply(550, "Can't set gid.");
706 return;
707 }
708 (void) initgroups(pw->pw_name, pw->pw_gid);
709
710 /* open wtmp before chroot */
711 logwtmp(ttyline, pw->pw_name, remotehost);
712 logged_in = 1;
713
714 dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name, FALSE, FALSE);
715
716 /* parse ftpd.conf, setting up various parameters */
717 if (guest)
718 parse_conf(CLASS_GUEST);
719 else if (dochroot)
720 parse_conf(CLASS_CHROOT);
721 else
722 parse_conf(CLASS_REAL);
723
724 home = "/";
725 if (guest) {
726 /*
727 * We MUST do a chdir() after the chroot. Otherwise
728 * the old current directory will be accessible as "."
729 * outside the new root!
730 */
731 if (chroot(anondir ? anondir : pw->pw_dir) < 0 ||
732 chdir("/") < 0) {
733 reply(550, "Can't set guest privileges.");
734 goto bad;
735 }
736 } else if (dochroot) {
737 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
738 reply(550, "Can't change root.");
739 goto bad;
740 }
741 } else if (chdir(pw->pw_dir) < 0) {
742 if (chdir("/") < 0) {
743 reply(530, "User %s: can't change directory to %s.",
744 pw->pw_name, pw->pw_dir);
745 goto bad;
746 } else
747 lreply(230, "No directory! Logging in with home=/");
748 } else
749 home = pw->pw_dir;
750 if (seteuid((uid_t)pw->pw_uid) < 0) {
751 reply(550, "Can't set uid.");
752 goto bad;
753 }
754 setenv("HOME", home, 1);
755
756
757 /*
758 * Display a login message, if it exists.
759 * N.B. reply(230,) must follow the message.
760 */
761 if ((fd = fopen(conffilename(_PATH_FTPLOGINMESG), "r")) != NULL) {
762 char *cp, line[LINE_MAX];
763
764 lreply(230, "");
765 while (fgets(line, sizeof(line), fd) != NULL) {
766 if ((cp = strchr(line, '\n')) != NULL)
767 *cp = '\0';
768 lreply(0, "%s", line);
769 }
770 (void) fflush(stdout);
771 (void) fclose(fd);
772 }
773 show_chdir_messages(230);
774 if (guest) {
775 reply(230, "Guest login ok, access restrictions apply.");
776 #ifdef HASSETPROCTITLE
777 snprintf(proctitle, sizeof(proctitle),
778 "%s: anonymous/%.*s", remotehost,
779 (int) (sizeof(proctitle) - sizeof(remotehost) -
780 sizeof(": anonymous/")), passwd);
781 setproctitle(proctitle);
782 #endif /* HASSETPROCTITLE */
783 if (logging)
784 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
785 remotehost, passwd);
786 } else {
787 reply(230, "User %s logged in.", pw->pw_name);
788 #ifdef HASSETPROCTITLE
789 snprintf(proctitle, sizeof(proctitle),
790 "%s: %s", remotehost, pw->pw_name);
791 setproctitle(proctitle);
792 #endif /* HASSETPROCTITLE */
793 if (logging)
794 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
795 remotehost, pw->pw_name);
796 }
797 (void) umask(curclass.umask);
798 return;
799 bad:
800 /* Forget all about it... */
801 end_login();
802 }
803
804 void
805 retrieve(cmd, name)
806 const char *cmd, *name;
807 {
808 FILE *fin = NULL, *dout;
809 struct stat st;
810 int (*closefunc) __P((FILE *)) = NULL;
811 int log, sendrv, closerv, stderrfd, isconversion, isdata, isls;
812 struct timeval start, finish, td, *tdp;
813 char tline[BUFSIZ];
814 const char *dispname;
815
816 sendrv = closerv = stderrfd = -1;
817 isconversion = isdata = isls = log = 0;
818 tdp = NULL;
819 dispname = name;
820 if (cmd == NULL) {
821 log = 1;
822 isdata = 1;
823 fin = fopen(name, "r");
824 closefunc = fclose;
825 if (fin == NULL)
826 cmd = do_conversion(name);
827 if (cmd != NULL) {
828 isconversion++;
829 syslog(LOG_INFO, "get command: '%s'", cmd);
830 }
831 }
832 if (cmd != NULL) {
833 char temp[MAXPATHLEN + 1];
834
835 if (strncmp(cmd, INTERNAL_LS, sizeof(INTERNAL_LS) - 1) == 0 &&
836 strchr(" \t\n", cmd[sizeof(INTERNAL_LS) - 1]) != NULL) {
837 isls = 1;
838 stderrfd = -1;
839 } else {
840 (void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
841 stderrfd = mkstemp(temp);
842 if (stderrfd != -1)
843 (void)unlink(temp);
844 }
845 (void)snprintf(tline, sizeof(tline), cmd, name);
846 dispname = tline;
847 fin = ftpd_popen(tline, "r", stderrfd);
848 closefunc = ftpd_pclose;
849 st.st_size = -1;
850 st.st_blksize = BUFSIZ;
851 }
852 if (fin == NULL) {
853 if (errno != 0) {
854 perror_reply(550, dispname);
855 if (log)
856 logcmd("get", -1, name, NULL, NULL,
857 strerror(errno));
858 }
859 if (stderrfd != -1)
860 (void)close(stderrfd);
861 return;
862 }
863 byte_count = -1;
864 if (cmd == NULL
865 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
866 reply(550, "%s: not a plain file.", dispname);
867 goto done;
868 }
869 if (restart_point) {
870 if (type == TYPE_A) {
871 off_t i;
872 int c;
873
874 for (i = 0; i < restart_point; i++) {
875 if ((c=getc(fin)) == EOF) {
876 perror_reply(550, dispname);
877 goto done;
878 }
879 if (c == '\n')
880 i++;
881 }
882 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
883 perror_reply(550, dispname);
884 goto done;
885 }
886 }
887 dout = dataconn(dispname, st.st_size, "w");
888 if (dout == NULL)
889 goto done;
890
891 (void)gettimeofday(&start, NULL);
892 sendrv = send_data(fin, dout, st.st_blksize, isdata);
893 (void)gettimeofday(&finish, NULL);
894 (void) fclose(dout);
895 timersub(&finish, &start, &td);
896 tdp = &td;
897 data = -1;
898 pdata = -1;
899 done:
900 if (log)
901 logcmd("get", byte_count, name, NULL, tdp, NULL);
902 closerv = (*closefunc)(fin);
903 if (sendrv == 0) {
904 FILE *err;
905 struct stat sb;
906
907 if (!isls && cmd != NULL && closerv != 0) {
908 lreply(226,
909 "Command returned an exit status of %d",
910 closerv);
911 if (isconversion)
912 syslog(LOG_INFO,
913 "get command: '%s' returned %d",
914 cmd, closerv);
915 }
916 if (!isls && cmd != NULL && stderrfd != -1 &&
917 (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
918 ((err = fdopen(stderrfd, "r")) != NULL)) {
919 char *cp, line[LINE_MAX];
920
921 lreply(226, "Command error messages:");
922 rewind(err);
923 while (fgets(line, sizeof(line), err) != NULL) {
924 if ((cp = strchr(line, '\n')) != NULL)
925 *cp = '\0';
926 lreply(0, " %s", line);
927 }
928 (void) fflush(stdout);
929 (void) fclose(err);
930 /* a reply(226,) must follow */
931 }
932 reply(226, "Transfer complete.");
933 }
934 if (stderrfd != -1)
935 (void)close(stderrfd);
936 }
937
938 void
939 store(name, mode, unique)
940 const char *name, *mode;
941 int unique;
942 {
943 FILE *fout, *din;
944 struct stat st;
945 int (*closefunc) __P((FILE *));
946 struct timeval start, finish, td, *tdp;
947 char *desc;
948
949 desc = (*mode == 'w') ? "put" : "append";
950 if (unique && stat(name, &st) == 0 &&
951 (name = gunique(name)) == NULL) {
952 logcmd(desc, -1, name, NULL, NULL, "cannot create unique file");
953 return;
954 }
955
956 if (restart_point)
957 mode = "r+";
958 fout = fopen(name, mode);
959 closefunc = fclose;
960 tdp = NULL;
961 if (fout == NULL) {
962 perror_reply(553, name);
963 logcmd(desc, -1, name, NULL, NULL, strerror(errno));
964 return;
965 }
966 byte_count = -1;
967 if (restart_point) {
968 if (type == TYPE_A) {
969 off_t i;
970 int c;
971
972 for (i = 0; i < restart_point; i++) {
973 if ((c=getc(fout)) == EOF) {
974 perror_reply(550, name);
975 goto done;
976 }
977 if (c == '\n')
978 i++;
979 }
980 /*
981 * We must do this seek to "current" position
982 * because we are changing from reading to
983 * writing.
984 */
985 if (fseek(fout, 0L, SEEK_CUR) < 0) {
986 perror_reply(550, name);
987 goto done;
988 }
989 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
990 perror_reply(550, name);
991 goto done;
992 }
993 }
994 din = dataconn(name, (off_t)-1, "r");
995 if (din == NULL)
996 goto done;
997 (void)gettimeofday(&start, NULL);
998 if (receive_data(din, fout) == 0) {
999 if (unique)
1000 reply(226, "Transfer complete (unique file name:%s).",
1001 name);
1002 else
1003 reply(226, "Transfer complete.");
1004 }
1005 (void)gettimeofday(&finish, NULL);
1006 (void) fclose(din);
1007 timersub(&finish, &start, &td);
1008 tdp = &td;
1009 data = -1;
1010 pdata = -1;
1011 done:
1012 logcmd(desc, byte_count, name, NULL, tdp, NULL);
1013 (*closefunc)(fout);
1014 }
1015
1016 static FILE *
1017 getdatasock(mode)
1018 const char *mode;
1019 {
1020 int on = 1, s, t, tries;
1021
1022 if (data >= 0)
1023 return (fdopen(data, mode));
1024 (void) seteuid((uid_t)0);
1025 s = socket(AF_INET, SOCK_STREAM, 0);
1026 if (s < 0)
1027 goto bad;
1028 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1029 (char *) &on, sizeof(on)) < 0)
1030 goto bad;
1031 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1032 (char *) &on, sizeof(on)) < 0)
1033 goto bad;
1034 /* anchor socket to avoid multi-homing problems */
1035 data_source.sin_len = sizeof(struct sockaddr_in);
1036 data_source.sin_family = AF_INET;
1037 data_source.sin_addr = ctrl_addr.sin_addr;
1038 for (tries = 1; ; tries++) {
1039 if (bind(s, (struct sockaddr *)&data_source,
1040 sizeof(data_source)) >= 0)
1041 break;
1042 if (errno != EADDRINUSE || tries > 10)
1043 goto bad;
1044 sleep(tries);
1045 }
1046 (void) seteuid((uid_t)pw->pw_uid);
1047 #ifdef IP_TOS
1048 on = IPTOS_THROUGHPUT;
1049 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1050 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1051 #endif
1052 return (fdopen(s, mode));
1053 bad:
1054 /* Return the real value of errno (close may change it) */
1055 t = errno;
1056 (void) seteuid((uid_t)pw->pw_uid);
1057 (void) close(s);
1058 errno = t;
1059 return (NULL);
1060 }
1061
1062 static FILE *
1063 dataconn(name, size, mode)
1064 const char *name;
1065 off_t size;
1066 const char *mode;
1067 {
1068 char sizebuf[32];
1069 FILE *file;
1070 int retry = 0, tos, keepalive;
1071
1072 file_size = size;
1073 byte_count = 0;
1074 if (size != (off_t) -1)
1075 (void)snprintf(sizebuf, sizeof(sizebuf), " (%qd byte%s)",
1076 (qdfmt_t)size, PLURAL(size));
1077 else
1078 sizebuf[0] = '\0';
1079 if (pdata >= 0) {
1080 struct sockaddr_in from;
1081 int s, fromlen = sizeof(from);
1082
1083 (void) alarm(curclass.timeout);
1084 s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1085 (void) alarm(0);
1086 if (s < 0) {
1087 reply(425, "Can't open data connection.");
1088 (void) close(pdata);
1089 pdata = -1;
1090 return (NULL);
1091 }
1092 (void) close(pdata);
1093 pdata = s;
1094 #ifdef IP_TOS
1095 tos = IPTOS_THROUGHPUT;
1096 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1097 sizeof(int));
1098 #endif
1099 /* Set keepalives on the socket to detect dropped conns. */
1100 #ifdef SO_KEEPALIVE
1101 keepalive = 1;
1102 (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1103 (char *)&keepalive, sizeof(int));
1104 #endif
1105 reply(150, "Opening %s mode data connection for '%s'%s.",
1106 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1107 return (fdopen(pdata, mode));
1108 }
1109 if (data >= 0) {
1110 reply(125, "Using existing data connection for '%s'%s.",
1111 name, sizebuf);
1112 usedefault = 1;
1113 return (fdopen(data, mode));
1114 }
1115 if (usedefault)
1116 data_dest = his_addr;
1117 usedefault = 1;
1118 file = getdatasock(mode);
1119 if (file == NULL) {
1120 reply(425, "Can't create data socket (%s,%d): %s.",
1121 inet_ntoa(data_source.sin_addr),
1122 ntohs(data_source.sin_port), strerror(errno));
1123 return (NULL);
1124 }
1125 data = fileno(file);
1126 while (connect(data, (struct sockaddr *)&data_dest,
1127 sizeof(data_dest)) < 0) {
1128 if (errno == EADDRINUSE && retry < swaitmax) {
1129 sleep((unsigned) swaitint);
1130 retry += swaitint;
1131 continue;
1132 }
1133 perror_reply(425, "Can't build data connection");
1134 (void) fclose(file);
1135 data = -1;
1136 return (NULL);
1137 }
1138 reply(150, "Opening %s mode data connection for '%s'%s.",
1139 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1140 return (file);
1141 }
1142
1143 /*
1144 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1145 * encapsulation of the data subject * to Mode, Structure, and Type.
1146 *
1147 * NB: Form isn't handled.
1148 */
1149 static int
1150 send_data(instr, outstr, blksize, isdata)
1151 FILE *instr, *outstr;
1152 off_t blksize;
1153 int isdata;
1154 {
1155 int c, cnt, filefd, netfd, rval;
1156 char *buf;
1157
1158 transflag = 1;
1159 rval = -1;
1160 buf = NULL;
1161 if (setjmp(urgcatch))
1162 goto cleanup_send_data;
1163
1164 switch (type) {
1165
1166 case TYPE_A:
1167 (void) alarm(curclass.timeout);
1168 while ((c = getc(instr)) != EOF) {
1169 byte_count++;
1170 if (c == '\n') {
1171 if (ferror(outstr))
1172 goto data_err;
1173 (void) putc('\r', outstr);
1174 if (isdata) {
1175 total_data_out++;
1176 total_data++;
1177 }
1178 total_bytes_out++;
1179 total_bytes++;
1180 }
1181 (void) putc(c, outstr);
1182 if (isdata) {
1183 total_data_out++;
1184 total_data++;
1185 }
1186 total_bytes_out++;
1187 total_bytes++;
1188 if ((byte_count % 4096) == 0)
1189 (void) alarm(curclass.timeout);
1190 }
1191 (void) alarm(0);
1192 fflush(outstr);
1193 if (ferror(instr))
1194 goto file_err;
1195 if (ferror(outstr))
1196 goto data_err;
1197 rval = 0;
1198 goto cleanup_send_data;
1199
1200 case TYPE_I:
1201 case TYPE_L:
1202 if ((buf = malloc((size_t)blksize)) == NULL) {
1203 perror_reply(451, "Local resource failure: malloc");
1204 goto cleanup_send_data;
1205 }
1206 filefd = fileno(instr);
1207 netfd = fileno(outstr);
1208 (void) alarm(curclass.timeout);
1209 while ((cnt = read(filefd, buf, (size_t)blksize)) > 0) {
1210 if (write(netfd, buf, cnt) != cnt)
1211 goto data_err;
1212 (void) alarm(curclass.timeout);
1213 byte_count += cnt;
1214 if (isdata) {
1215 total_data_out += cnt;
1216 total_data += cnt;
1217 }
1218 total_bytes_out += cnt;
1219 total_bytes += cnt;
1220 }
1221 if (cnt < 0)
1222 goto file_err;
1223 rval = 0;
1224 goto cleanup_send_data;
1225
1226 default:
1227 reply(550, "Unimplemented TYPE %d in send_data", type);
1228 goto cleanup_send_data;
1229 }
1230
1231 data_err:
1232 (void) alarm(0);
1233 perror_reply(426, "Data connection");
1234 goto cleanup_send_data;
1235
1236 file_err:
1237 (void) alarm(0);
1238 perror_reply(551, "Error on input file");
1239 /* FALLTHROUGH */
1240
1241 cleanup_send_data:
1242 (void) alarm(0);
1243 transflag = 0;
1244 if (buf)
1245 free(buf);
1246 if (isdata) {
1247 total_files_out++;
1248 total_files++;
1249 }
1250 total_xfers_out++;
1251 total_xfers++;
1252 return (rval);
1253 }
1254
1255 /*
1256 * Transfer data from peer to "outstr" using the appropriate encapulation of
1257 * the data subject to Mode, Structure, and Type.
1258 *
1259 * N.B.: Form isn't handled.
1260 */
1261 static int
1262 receive_data(instr, outstr)
1263 FILE *instr, *outstr;
1264 {
1265 int c, cnt, bare_lfs, netfd, filefd, rval;
1266 char buf[BUFSIZ];
1267 #ifdef __GNUC__
1268 (void) &bare_lfs;
1269 #endif
1270
1271 bare_lfs = 0;
1272 transflag = 1;
1273 rval = -1;
1274 if (setjmp(urgcatch))
1275 goto cleanup_recv_data;
1276
1277 switch (type) {
1278
1279 case TYPE_I:
1280 case TYPE_L:
1281 netfd = fileno(instr);
1282 filefd = fileno(outstr);
1283 (void) alarm(curclass.timeout);
1284 while ((cnt = read(netfd, buf, sizeof(buf))) > 0) {
1285 if (write(filefd, buf, cnt) != cnt)
1286 goto file_err;
1287 (void) alarm(curclass.timeout);
1288 byte_count += cnt;
1289 total_data_in += cnt;
1290 total_data += cnt;
1291 total_bytes_in += cnt;
1292 total_bytes += cnt;
1293 }
1294 if (cnt < 0)
1295 goto data_err;
1296 rval = 0;
1297 goto cleanup_recv_data;
1298
1299 case TYPE_E:
1300 reply(553, "TYPE E not implemented.");
1301 goto cleanup_recv_data;
1302
1303 case TYPE_A:
1304 (void) alarm(curclass.timeout);
1305 while ((c = getc(instr)) != EOF) {
1306 byte_count++;
1307 total_data_in++;
1308 total_data++;
1309 total_bytes_in++;
1310 total_bytes++;
1311 if ((byte_count % 4096) == 0)
1312 (void) alarm(curclass.timeout);
1313 if (c == '\n')
1314 bare_lfs++;
1315 while (c == '\r') {
1316 if (ferror(outstr))
1317 goto data_err;
1318 if ((c = getc(instr)) != '\n') {
1319 byte_count++;
1320 total_data_in++;
1321 total_data++;
1322 total_bytes_in++;
1323 total_bytes++;
1324 if ((byte_count % 4096) == 0)
1325 (void) alarm(curclass.timeout);
1326 (void) putc ('\r', outstr);
1327 if (c == '\0' || c == EOF)
1328 goto contin2;
1329 }
1330 }
1331 (void) putc(c, outstr);
1332 contin2: ;
1333 }
1334 (void) alarm(0);
1335 fflush(outstr);
1336 if (ferror(instr))
1337 goto data_err;
1338 if (ferror(outstr))
1339 goto file_err;
1340 if (bare_lfs) {
1341 lreply(226,
1342 "WARNING! %d bare linefeeds received in ASCII mode",
1343 bare_lfs);
1344 lreply(0, "File may not have transferred correctly.");
1345 }
1346 rval = 0;
1347 goto cleanup_recv_data;
1348
1349 default:
1350 reply(550, "Unimplemented TYPE %d in receive_data", type);
1351 goto cleanup_recv_data;
1352 }
1353
1354 data_err:
1355 (void) alarm(0);
1356 perror_reply(426, "Data Connection");
1357 goto cleanup_recv_data;
1358
1359 file_err:
1360 (void) alarm(0);
1361 perror_reply(452, "Error writing file");
1362 goto cleanup_recv_data;
1363
1364 cleanup_recv_data:
1365 (void) alarm(0);
1366 transflag = 0;
1367 total_files_in++;
1368 total_files++;
1369 total_xfers_in++;
1370 total_xfers++;
1371 return (rval);
1372 }
1373
1374 void
1375 statfilecmd(filename)
1376 const char *filename;
1377 {
1378 FILE *fin;
1379 int c;
1380 char line[LINE_MAX];
1381
1382 (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1383 fin = ftpd_popen(line, "r", STDOUT_FILENO);
1384 lreply(211, "status of %s:", filename);
1385 while ((c = getc(fin)) != EOF) {
1386 if (c == '\n') {
1387 if (ferror(stdout)){
1388 perror_reply(421, "control connection");
1389 (void) ftpd_pclose(fin);
1390 dologout(1);
1391 /* NOTREACHED */
1392 }
1393 if (ferror(fin)) {
1394 perror_reply(551, filename);
1395 (void) ftpd_pclose(fin);
1396 return;
1397 }
1398 (void) putc('\r', stdout);
1399 total_bytes++;
1400 total_bytes_out++;
1401 }
1402 (void) putc(c, stdout);
1403 total_bytes++;
1404 total_bytes_out++;
1405 }
1406 (void) ftpd_pclose(fin);
1407 reply(211, "End of Status");
1408 }
1409
1410 void
1411 statcmd()
1412 {
1413 struct sockaddr_in *sin;
1414 u_char *a, *p;
1415 off_t b, otbi, otbo, otb;
1416
1417 lreply(211, "%s FTP server status:", hostname);
1418 lreply(0, "%s", version);
1419 if (isdigit(remotehost[0]))
1420 lreply(0, "Connected to %s", remotehost);
1421 else
1422 lreply(0, "Connected to %s (%s)", remotehost,
1423 inet_ntoa(his_addr.sin_addr));
1424 if (logged_in) {
1425 if (guest)
1426 lreply(0, "Logged in anonymously");
1427 else
1428 lreply(0, "Logged in as %s", pw->pw_name);
1429 } else if (askpasswd)
1430 lreply(0, "Waiting for password");
1431 else
1432 lreply(0, "Waiting for user name");
1433 b = printf(" TYPE: %s", typenames[type]);
1434 total_bytes += b;
1435 total_bytes_out += b;
1436 if (type == TYPE_A || type == TYPE_E) {
1437 b = printf(", FORM: %s", formnames[form]);
1438 total_bytes += b;
1439 total_bytes_out += b;
1440 }
1441 if (type == TYPE_L) {
1442 #if NBBY == 8
1443 b = printf(" %d", NBBY);
1444 #else
1445 /* XXX: `bytesize' needs to be defined in this case */
1446 b = printf(" %d", bytesize);
1447 #endif
1448 total_bytes += b;
1449 total_bytes_out += b;
1450 }
1451 b = printf("; STRUcture: %s; transfer MODE: %s\r\n",
1452 strunames[stru], modenames[mode]);
1453 total_bytes += b;
1454 total_bytes_out += b;
1455 if (data != -1)
1456 lreply(0, "Data connection open");
1457 else if (pdata != -1) {
1458 b = printf(" in Passive mode");
1459 total_bytes += b;
1460 total_bytes_out += b;
1461 sin = &pasv_addr;
1462 goto printaddr;
1463 } else if (usedefault == 0) {
1464 b = printf(" PORT");
1465 total_bytes += b;
1466 total_bytes_out += b;
1467 sin = &data_dest;
1468 printaddr:
1469 a = (u_char *) &sin->sin_addr;
1470 p = (u_char *) &sin->sin_port;
1471 #define UC(b) (((int) b) & 0xff)
1472 b = printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1473 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1474 #undef UC
1475 total_bytes += b;
1476 total_bytes_out += b;
1477 } else
1478 lreply(0, "No data connection");
1479
1480 if (logged_in) {
1481 lreply(0, "Data sent: %qd byte%s in %qd file%s",
1482 (qdfmt_t)total_data_out, PLURAL(total_data_out),
1483 (qdfmt_t)total_files_out, PLURAL(total_files_out));
1484 lreply(0, "Data received: %qd byte%s in %qd file%s",
1485 (qdfmt_t)total_data_in, PLURAL(total_data_in),
1486 (qdfmt_t)total_files_in, PLURAL(total_files_in));
1487 lreply(0, "Total data: %qd byte%s in %qd file%s",
1488 (qdfmt_t)total_data, PLURAL(total_data),
1489 (qdfmt_t)total_files, PLURAL(total_files));
1490 }
1491 otbi = total_bytes_in;
1492 otbo = total_bytes_out;
1493 otb = total_bytes;
1494 lreply(0, "Traffic sent: %qd byte%s in %qd transfer%s",
1495 (qdfmt_t)otbo, PLURAL(otbo),
1496 (qdfmt_t)total_xfers_out, PLURAL(total_xfers_out));
1497 lreply(0, "Traffic received: %qd byte%s in %qd transfer%s",
1498 (qdfmt_t)otbi, PLURAL(otbi),
1499 (qdfmt_t)total_xfers_in, PLURAL(total_xfers_in));
1500 lreply(0, "Total traffic: %qd byte%s in %qd transfer%s",
1501 (qdfmt_t)otb, PLURAL(otb),
1502 (qdfmt_t)total_xfers, PLURAL(total_xfers));
1503
1504 if (logged_in) {
1505 struct ftpconv *cp;
1506
1507 lreply(0, "");
1508 lreply(0, "Class: %s", curclass.classname);
1509 lreply(0, "Check PORT commands: %sabled",
1510 curclass.checkportcmd ? "en" : "dis");
1511 if (curclass.display)
1512 lreply(0, "Display file: %s", curclass.display);
1513 if (curclass.notify)
1514 lreply(0, "Notify fileglob: %s", curclass.notify);
1515 lreply(0, "Idle timeout: %d, maximum timeout: %d",
1516 curclass.timeout, curclass.maxtimeout);
1517 lreply(0, "DELE, MKD, RMD, UMASK, CHMOD commands: %sabled",
1518 curclass.modify ? "en" : "dis");
1519 lreply(0, "Umask: %.04o", curclass.umask);
1520 for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
1521 if (cp->suffix == NULL || cp->types == NULL ||
1522 cp->command == NULL)
1523 continue;
1524 lreply(0,
1525 "Conversion: %s [%s] disable: %s, command: %s",
1526 cp->suffix, cp->types, cp->disable, cp->command);
1527 }
1528 }
1529
1530 reply(211, "End of status");
1531 }
1532
1533 void
1534 fatal(s)
1535 const char *s;
1536 {
1537
1538 reply(451, "Error in server: %s\n", s);
1539 reply(221, "Closing connection due to server error.");
1540 dologout(0);
1541 /* NOTREACHED */
1542 }
1543
1544 void
1545 #ifdef __STDC__
1546 reply(int n, const char *fmt, ...)
1547 #else
1548 reply(n, fmt, va_alist)
1549 int n;
1550 char *fmt;
1551 va_dcl
1552 #endif
1553 {
1554 off_t b;
1555 va_list ap;
1556 #ifdef __STDC__
1557 va_start(ap, fmt);
1558 #else
1559 va_start(ap);
1560 #endif
1561 b = 0;
1562 b += printf("%d ", n);
1563 b += vprintf(fmt, ap);
1564 b += printf("\r\n");
1565 total_bytes += b;
1566 total_bytes_out += b;
1567 (void)fflush(stdout);
1568 if (debug) {
1569 syslog(LOG_DEBUG, "<--- %d ", n);
1570 vsyslog(LOG_DEBUG, fmt, ap);
1571 }
1572 }
1573
1574 void
1575 #ifdef __STDC__
1576 lreply(int n, const char *fmt, ...)
1577 #else
1578 lreply(n, fmt, va_alist)
1579 int n;
1580 char *fmt;
1581 va_dcl
1582 #endif
1583 {
1584 off_t b;
1585 va_list ap;
1586 #ifdef __STDC__
1587 va_start(ap, fmt);
1588 #else
1589 va_start(ap);
1590 #endif
1591 b = 0;
1592 switch (n) {
1593 case 0:
1594 b += printf(" ");
1595 case -1:
1596 break;
1597 default:
1598 b += printf("%d-", n);
1599 break;
1600 }
1601 b += vprintf(fmt, ap);
1602 b += printf("\r\n");
1603 total_bytes += b;
1604 total_bytes_out += b;
1605 (void)fflush(stdout);
1606 if (debug) {
1607 syslog(LOG_DEBUG, "<--- %d- ", n);
1608 vsyslog(LOG_DEBUG, fmt, ap);
1609 }
1610 }
1611
1612 static void
1613 ack(s)
1614 const char *s;
1615 {
1616
1617 reply(250, "%s command successful.", s);
1618 }
1619
1620 void
1621 delete(name)
1622 const char *name;
1623 {
1624 char *p = NULL;
1625
1626 if (remove(name) < 0) {
1627 p = strerror(errno);
1628 perror_reply(550, name);
1629 } else
1630 ack("DELE");
1631 logcmd("delete", -1, name, NULL, NULL, p);
1632 }
1633
1634 void
1635 cwd(path)
1636 const char *path;
1637 {
1638
1639 if (chdir(path) < 0)
1640 perror_reply(550, path);
1641 else {
1642 show_chdir_messages(250);
1643 ack("CWD");
1644 }
1645 }
1646
1647 static void
1648 replydirname(name, message)
1649 const char *name, *message;
1650 {
1651 char npath[MAXPATHLEN + 1];
1652 int i;
1653
1654 for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
1655 npath[i] = *name;
1656 if (*name == '"')
1657 npath[++i] = '"';
1658 }
1659 npath[i] = '\0';
1660 reply(257, "\"%s\" %s", npath, message);
1661 }
1662
1663 void
1664 makedir(name)
1665 const char *name;
1666 {
1667 char *p = NULL;
1668
1669 if (mkdir(name, 0777) < 0) {
1670 p = strerror(errno);
1671 perror_reply(550, name);
1672 } else
1673 replydirname(name, "directory created.");
1674 logcmd("mkdir", -1, name, NULL, NULL, p);
1675 }
1676
1677 void
1678 removedir(name)
1679 const char *name;
1680 {
1681 char *p = NULL;
1682
1683 if (rmdir(name) < 0) {
1684 p = strerror(errno);
1685 perror_reply(550, name);
1686 } else
1687 ack("RMD");
1688 logcmd("rmdir", -1, name, NULL, NULL, p);
1689 }
1690
1691 void
1692 pwd()
1693 {
1694 char path[MAXPATHLEN + 1];
1695
1696 if (getcwd(path, sizeof(path) - 1) == NULL)
1697 reply(550, "Can't get the current directory: %s.",
1698 strerror(errno));
1699 else
1700 replydirname(path, "is the current directory.");
1701 }
1702
1703 char *
1704 renamefrom(name)
1705 char *name;
1706 {
1707 struct stat st;
1708
1709 if (stat(name, &st) < 0) {
1710 perror_reply(550, name);
1711 return (NULL);
1712 }
1713 reply(350, "File exists, ready for destination name");
1714 return (name);
1715 }
1716
1717 void
1718 renamecmd(from, to)
1719 const char *from, *to;
1720 {
1721 char *p = NULL;
1722
1723 if (rename(from, to) < 0) {
1724 p = strerror(errno);
1725 perror_reply(550, "rename");
1726 } else
1727 ack("RNTO");
1728 logcmd("rename", -1, from, to, NULL, p);
1729 }
1730
1731 static void
1732 dolog(sin)
1733 struct sockaddr_in *sin;
1734 {
1735 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1736 sizeof(struct in_addr), AF_INET);
1737
1738 if (hp)
1739 (void)strncpy(remotehost, hp->h_name, sizeof(remotehost));
1740 else
1741 (void)strncpy(remotehost, inet_ntoa(sin->sin_addr),
1742 sizeof(remotehost));
1743 remotehost[sizeof(remotehost) - 1] = '\0';
1744 #ifdef HASSETPROCTITLE
1745 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1746 setproctitle(proctitle);
1747 #endif /* HASSETPROCTITLE */
1748
1749 if (logging)
1750 syslog(LOG_INFO, "connection from %s", remotehost);
1751 }
1752
1753 /*
1754 * Record logout in wtmp file
1755 * and exit with supplied status.
1756 */
1757 void
1758 dologout(status)
1759 int status;
1760 {
1761 /*
1762 * Prevent reception of SIGURG from resulting in a resumption
1763 * back to the main program loop.
1764 */
1765 transflag = 0;
1766
1767 if (logged_in) {
1768 (void) seteuid((uid_t)0);
1769 logwtmp(ttyline, "", "");
1770 #ifdef KERBEROS
1771 if (!notickets && krbtkfile_env)
1772 unlink(krbtkfile_env);
1773 #endif
1774 }
1775 /* beware of flushing buffers after a SIGPIPE */
1776 _exit(status);
1777 }
1778
1779 static void
1780 myoob(signo)
1781 int signo;
1782 {
1783 char *cp;
1784
1785 /* only process if transfer occurring */
1786 if (!transflag)
1787 return;
1788 cp = tmpline;
1789 if (getline(cp, 7, stdin) == NULL) {
1790 reply(221, "You could at least say goodbye.");
1791 dologout(0);
1792 }
1793 if (strcasecmp(cp, "ABOR\r\n") == 0) {
1794 tmpline[0] = '\0';
1795 reply(426, "Transfer aborted. Data connection closed.");
1796 reply(226, "Abort successful");
1797 longjmp(urgcatch, 1);
1798 }
1799 if (strcasecmp(cp, "STAT\r\n") == 0) {
1800 if (file_size != (off_t) -1)
1801 reply(213, "Status: %qd of %qd byte%s transferred",
1802 (qdfmt_t)byte_count, (qdfmt_t)file_size,
1803 PLURAL(byte_count));
1804 else
1805 reply(213, "Status: %qd byte%s transferred",
1806 (qdfmt_t)byte_count, PLURAL(byte_count));
1807 }
1808 }
1809
1810 /*
1811 * Note: a response of 425 is not mentioned as a possible response to
1812 * the PASV command in RFC959. However, it has been blessed as
1813 * a legitimate response by Jon Postel in a telephone conversation
1814 * with Rick Adams on 25 Jan 89.
1815 */
1816 void
1817 passive()
1818 {
1819 int len;
1820 char *p, *a;
1821
1822 pdata = socket(AF_INET, SOCK_STREAM, 0);
1823 if (pdata < 0 || !logged_in) {
1824 perror_reply(425, "Can't open passive connection");
1825 return;
1826 }
1827 pasv_addr = ctrl_addr;
1828 pasv_addr.sin_port = 0;
1829 (void) seteuid((uid_t)0);
1830 if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
1831 (void) seteuid((uid_t)pw->pw_uid);
1832 goto pasv_error;
1833 }
1834 (void) seteuid((uid_t)pw->pw_uid);
1835 len = sizeof(pasv_addr);
1836 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1837 goto pasv_error;
1838 if (listen(pdata, 1) < 0)
1839 goto pasv_error;
1840 a = (char *) &pasv_addr.sin_addr;
1841 p = (char *) &pasv_addr.sin_port;
1842
1843 #define UC(b) (((int) b) & 0xff)
1844
1845 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1846 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1847 return;
1848
1849 pasv_error:
1850 (void) close(pdata);
1851 pdata = -1;
1852 perror_reply(425, "Can't open passive connection");
1853 return;
1854 }
1855
1856 /*
1857 * Generate unique name for file with basename "local".
1858 * The file named "local" is already known to exist.
1859 * Generates failure reply on error.
1860 *
1861 * XXX this function should under go changes similar to
1862 * the mktemp(3)/mkstemp(3) changes.
1863 */
1864 static char *
1865 gunique(local)
1866 const char *local;
1867 {
1868 static char new[MAXPATHLEN + 1];
1869 struct stat st;
1870 int count, len;
1871 char *cp;
1872
1873 cp = strrchr(local, '/');
1874 if (cp)
1875 *cp = '\0';
1876 if (stat(cp ? local : ".", &st) < 0) {
1877 perror_reply(553, cp ? local : ".");
1878 return (NULL);
1879 }
1880 if (cp)
1881 *cp = '/';
1882 (void) strcpy(new, local);
1883 len = strlen(new);
1884 cp = new + len;
1885 *cp++ = '.';
1886 for (count = 1; count < 100; count++) {
1887 (void)snprintf(cp, sizeof(new) - len - 2, "%d", count);
1888 if (stat(new, &st) < 0)
1889 return (new);
1890 }
1891 reply(452, "Unique file name cannot be created.");
1892 return (NULL);
1893 }
1894
1895 /*
1896 * Format and send reply containing system error number.
1897 */
1898 void
1899 perror_reply(code, string)
1900 int code;
1901 const char *string;
1902 {
1903 int save_errno;
1904
1905 save_errno = errno;
1906 reply(code, "%s: %s.", string, strerror(errno));
1907 errno = save_errno;
1908 }
1909
1910 static char *onefile[] = {
1911 "",
1912 0
1913 };
1914
1915 void
1916 send_file_list(whichf)
1917 const char *whichf;
1918 {
1919 struct stat st;
1920 DIR *dirp = NULL;
1921 struct dirent *dir;
1922 FILE *dout = NULL;
1923 char **dirlist, *dirname, *p;
1924 int simple = 0;
1925 int freeglob = 0;
1926 glob_t gl;
1927 off_t b;
1928
1929 #ifdef __GNUC__
1930 (void) &dout;
1931 (void) &dirlist;
1932 (void) &simple;
1933 (void) &freeglob;
1934 #endif
1935
1936 p = NULL;
1937 if (strpbrk(whichf, "~{[*?") != NULL) {
1938 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
1939
1940 memset(&gl, 0, sizeof(gl));
1941 freeglob = 1;
1942 if (glob(whichf, flags, 0, &gl)) {
1943 reply(550, "not found");
1944 goto out;
1945 } else if (gl.gl_pathc == 0) {
1946 errno = ENOENT;
1947 perror_reply(550, whichf);
1948 goto out;
1949 }
1950 dirlist = gl.gl_pathv;
1951 } else {
1952 p = xstrdup(whichf);
1953 onefile[0] = p;
1954 dirlist = onefile;
1955 simple = 1;
1956 }
1957 /* XXX: } for vi sm */
1958
1959 if (setjmp(urgcatch)) {
1960 transflag = 0;
1961 goto out;
1962 }
1963 while ((dirname = *dirlist++) != NULL) {
1964 int trailingslash = 0;
1965
1966 if (stat(dirname, &st) < 0) {
1967 /*
1968 * If user typed "ls -l", etc, and the client
1969 * used NLST, do what the user meant.
1970 */
1971 if (dirname[0] == '-' && *dirlist == NULL &&
1972 transflag == 0) {
1973 retrieve("/bin/ls %s", dirname);
1974 goto out;
1975 }
1976 perror_reply(550, whichf);
1977 if (dout != NULL) {
1978 (void) fclose(dout);
1979 transflag = 0;
1980 data = -1;
1981 pdata = -1;
1982 }
1983 goto out;
1984 }
1985
1986 if (S_ISREG(st.st_mode)) {
1987 if (dout == NULL) {
1988 dout = dataconn("file list", (off_t)-1, "w");
1989 if (dout == NULL)
1990 goto out;
1991 transflag++;
1992 }
1993 b = fprintf(dout, "%s%s\n", dirname,
1994 type == TYPE_A ? "\r" : "");
1995 total_bytes += b;
1996 total_bytes_out += b;
1997 byte_count += strlen(dirname) + 1;
1998 continue;
1999 } else if (!S_ISDIR(st.st_mode))
2000 continue;
2001
2002 if (dirname[strlen(dirname) - 1] == '/')
2003 trailingslash++;
2004
2005 if ((dirp = opendir(dirname)) == NULL)
2006 continue;
2007
2008 while ((dir = readdir(dirp)) != NULL) {
2009 char nbuf[MAXPATHLEN + 1];
2010
2011 if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2012 continue;
2013 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2014 dir->d_namlen == 2)
2015 continue;
2016
2017 (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
2018 trailingslash ? "" : "/", dir->d_name);
2019
2020 /*
2021 * We have to do a stat to ensure it's
2022 * not a directory or special file.
2023 */
2024 if (simple || (stat(nbuf, &st) == 0 &&
2025 S_ISREG(st.st_mode))) {
2026 char *p;
2027
2028 if (dout == NULL) {
2029 dout = dataconn("file list", (off_t)-1,
2030 "w");
2031 if (dout == NULL)
2032 goto out;
2033 transflag++;
2034 }
2035 p = nbuf;
2036 if (nbuf[0] == '.' && nbuf[1] == '/')
2037 p = &nbuf[2];
2038 b = fprintf(dout, "%s%s\n", p,
2039 type == TYPE_A ? "\r" : "");
2040 total_bytes += b;
2041 total_bytes_out += b;
2042 byte_count += strlen(nbuf) + 1;
2043 }
2044 }
2045 (void) closedir(dirp);
2046 }
2047
2048 if (dout == NULL)
2049 reply(550, "No files found.");
2050 else if (ferror(dout) != 0)
2051 perror_reply(550, "Data connection");
2052 else
2053 reply(226, "Transfer complete.");
2054
2055 transflag = 0;
2056 if (dout != NULL)
2057 (void) fclose(dout);
2058 data = -1;
2059 pdata = -1;
2060 out:
2061 total_xfers++;
2062 total_xfers_out++;
2063 if (p)
2064 free(p);
2065 if (freeglob)
2066 globfree(&gl);
2067 }
2068
2069 char *
2070 conffilename(s)
2071 const char *s;
2072 {
2073 static char filename[MAXPATHLEN + 1];
2074
2075 (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
2076 return filename;
2077 }
2078
2079 /*
2080 * logcmd --
2081 * based on the arguments, syslog a message:
2082 * if bytes != -1 "<command> <file1> = <bytes> bytes"
2083 * else if file2 != NULL "<command> <file1> <file2>"
2084 * else "<command> <file1>"
2085 * if elapsed != NULL, append "in xxx.yyy seconds"
2086 * if error != NULL, append ": " + error
2087 */
2088
2089 void
2090 logcmd(command, bytes, file1, file2, elapsed, error)
2091 const char *command;
2092 off_t bytes;
2093 const char *file1;
2094 const char *file2;
2095 const struct timeval *elapsed;
2096 const char *error;
2097 {
2098 char buf[MAXPATHLEN + 100], realfile[MAXPATHLEN + 1];
2099 const char *p;
2100 size_t len;
2101
2102 if (logging <=1)
2103 return;
2104
2105 if ((p = realpath(file1, realfile)) == NULL) {
2106 #if 0 /* XXX: too noisy */
2107 syslog(LOG_WARNING, "realpath `%s' failed: %s",
2108 realfile, strerror(errno));
2109 #endif
2110 p = file1;
2111 }
2112 len = snprintf(buf, sizeof(buf), "%s %s", command, p);
2113
2114 if (bytes != (off_t)-1) {
2115 len += snprintf(buf + len, sizeof(buf) - len,
2116 " = %qd byte%s", (qdfmt_t) bytes, PLURAL(bytes));
2117 } else if (file2 != NULL) {
2118 if ((p = realpath(file2, realfile)) == NULL) {
2119 #if 0 /* XXX: too noisy */
2120 syslog(LOG_WARNING, "realpath `%s' failed: %s",
2121 realfile, strerror(errno));
2122 #endif
2123 p = file2;
2124 }
2125 len += snprintf(buf + len, sizeof(buf) - len, " %s", p);
2126 }
2127
2128 if (elapsed != NULL) {
2129 len += snprintf(buf + len, sizeof(buf) - len,
2130 " in %ld.%.03d seconds", elapsed->tv_sec,
2131 (int)(elapsed->tv_usec / 1000));
2132 }
2133
2134 if (error != NULL)
2135 len += snprintf(buf + len, sizeof(buf) - len, ": %s", error);
2136
2137 syslog(LOG_INFO, "%s", buf);
2138 }
2139
2140 char *
2141 xstrdup(s)
2142 const char *s;
2143 {
2144 char *new = strdup(s);
2145
2146 if (new == NULL)
2147 fatal("Local resource failure: malloc");
2148 /* NOTREACHED */
2149 return (new);
2150 }
2151