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