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