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