check for innetgr
[heimdal.git] / appl / ftp / ftpd / ftpd.c
blobe0d8d1f3f6ae35005f60e39faa317dcb2edfba6d
1 /*
2 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
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.
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.
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 RCSID("$Id$");
37 #endif
40 * FTP server.
42 #ifdef HAVE_SYS_TYPES_H
43 #include <sys/types.h>
44 #endif
45 #ifdef HAVE_SYS_PARAM_H
46 #include <sys/param.h>
47 #endif
48 #ifdef HAVE_SYS_STAT_H
49 #include <sys/stat.h>
50 #endif
51 #ifdef HAVE_SYS_SOCKET_H
52 #include <sys/socket.h>
53 #endif
54 #if defined(HAVE_SYS_IOCTL_H) && SunOS != 4
55 #include <sys/ioctl.h>
56 #endif
57 #ifdef TIME_WITH_SYS_TIME
58 #include <sys/time.h>
59 #include <time.h>
60 #elif defined(HAVE_SYS_TIME_H)
61 #include <sys/time.h>
62 #else
63 #include <time.h>
64 #endif
65 #ifdef HAVE_SYS_RESOURCE_H
66 #include <sys/resource.h>
67 #endif
68 #ifdef HAVE_SYS_WAIT_H
69 #include <sys/wait.h>
70 #endif
72 #ifdef HAVE_NETINET_IN_H
73 #include <netinet/in.h>
74 #endif
75 #ifdef HAVE_NETINET_IN_SYSTM_H
76 #include <netinet/in_systm.h>
77 #endif
78 #ifdef HAVE_NETINET_IP_H
79 #include <netinet/ip.h>
80 #endif
82 #ifdef HAVE_SYS_MMAN_H
83 #include <sys/mman.h>
84 #endif
86 #define FTP_NAMES
87 #include <arpa/ftp.h>
88 #ifdef HAVE_ARPA_INET_H
89 #include <arpa/inet.h>
90 #endif
91 #ifdef HAVE_ARPA_TELNET_H
92 #include <arpa/telnet.h>
93 #endif
95 #include <ctype.h>
96 #ifdef HAVE_DIRENT_H
97 #include <dirent.h>
98 #endif
99 #include <errno.h>
100 #ifdef HAVE_FCNTL_H
101 #include <fcntl.h>
102 #endif
103 #include <glob.h>
104 #include <limits.h>
105 #ifdef HAVE_PWD_H
106 #include <pwd.h>
107 #endif
108 #include <setjmp.h>
109 #include <signal.h>
110 #include <stdio.h>
111 #include <stdlib.h>
112 #include <stdarg.h>
113 #include <string.h>
114 #ifdef HAVE_SYSLOG_H
115 #include <syslog.h>
116 #endif
117 #include <time.h>
118 #ifdef HAVE_UNISTD_H
119 #include <unistd.h>
120 #endif
121 #ifdef HAVE_GRP_H
122 #include <grp.h>
123 #endif
125 #include <err.h>
127 #include "pathnames.h"
128 #include "extern.h"
129 #include "common.h"
131 #include "auth.h"
133 #include <krb.h>
135 #include <kafs.h>
136 #include "roken.h"
138 #ifdef OTP
139 #include <otp.h>
140 #endif
142 #ifdef SOCKS
143 #include <socks.h>
144 extern int LIBPREFIX(fclose) __P((FILE *));
145 #endif
147 void yyparse();
149 #ifndef LOG_FTP
150 #define LOG_FTP LOG_DAEMON
151 #endif
153 static char version[] = "Version 6.00";
155 extern off_t restart_point;
156 extern char cbuf[];
158 struct sockaddr_in ctrl_addr;
159 struct sockaddr_in data_source;
160 struct sockaddr_in data_dest;
161 struct sockaddr_in his_addr;
162 struct sockaddr_in pasv_addr;
164 int data;
165 jmp_buf errcatch, urgcatch;
166 int oobflag;
167 int logged_in;
168 struct passwd *pw;
169 int debug = 0;
170 int ftpd_timeout = 900; /* timeout after 15 minutes of inactivity */
171 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
172 int logging;
173 int guest;
174 int dochroot;
175 int type;
176 int form;
177 int stru; /* avoid C keyword */
178 int mode;
179 int usedefault = 1; /* for data transfers */
180 int pdata = -1; /* for passive mode */
181 int transflag;
182 off_t file_size;
183 off_t byte_count;
184 #if !defined(CMASK) || CMASK == 0
185 #undef CMASK
186 #define CMASK 027
187 #endif
188 int defumask = CMASK; /* default umask value */
189 int guest_umask = 0777; /* Paranoia for anonymous users */
190 char tmpline[10240];
191 char hostname[MaxHostNameLen];
192 char remotehost[MaxHostNameLen];
193 static char ttyline[20];
195 #define AUTH_PLAIN (1 << 0) /* allow sending passwords */
196 #define AUTH_OTP (1 << 1) /* passwords are one-time */
197 #define AUTH_FTP (1 << 2) /* allow anonymous login */
199 static int auth_level = 0; /* Only allow kerberos login by default */
202 * Timeout intervals for retrying connections
203 * to hosts that don't accept PORT cmds. This
204 * is a kludge, but given the problems with TCP...
206 #define SWAITMAX 90 /* wait at most 90 seconds */
207 #define SWAITINT 5 /* interval between retries */
209 int swaitmax = SWAITMAX;
210 int swaitint = SWAITINT;
212 #ifdef HAVE_SETPROCTITLE
213 char proctitle[BUFSIZ]; /* initial part of title */
214 #endif /* HAVE_SETPROCTITLE */
216 #define LOGCMD(cmd, file) \
217 if (logging > 1) \
218 syslog(LOG_INFO,"%s %s%s", cmd, \
219 *(file) == '/' ? "" : curdir(), file);
220 #define LOGCMD2(cmd, file1, file2) \
221 if (logging > 1) \
222 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
223 *(file1) == '/' ? "" : curdir(), file1, \
224 *(file2) == '/' ? "" : curdir(), file2);
225 #define LOGBYTES(cmd, file, cnt) \
226 if (logging > 1) { \
227 if (cnt == (off_t)-1) \
228 syslog(LOG_INFO,"%s %s%s", cmd, \
229 *(file) == '/' ? "" : curdir(), file); \
230 else \
231 syslog(LOG_INFO, "%s %s%s = %ld bytes", \
232 cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \
235 static void ack (char *);
236 static void myoob (int);
237 static int checkuser (char *, char *);
238 static int checkaccess (char *);
239 static FILE *dataconn (char *, off_t, char *);
240 static void dolog (struct sockaddr_in *);
241 static void end_login (void);
242 static FILE *getdatasock (char *);
243 static char *gunique (char *);
244 static RETSIGTYPE lostconn (int);
245 static int receive_data (FILE *, FILE *);
246 static void send_data (FILE *, FILE *);
247 static struct passwd * sgetpwnam (char *);
248 static void usage(void);
250 static char *
251 curdir(void)
253 static char path[MaxPathLen+1+1]; /* path + '/' + '\0' */
255 if (getcwd(path, sizeof(path)-2) == NULL)
256 return ("");
257 if (path[1] != '\0') /* special case for root dir. */
258 strcat(path, "/");
259 /* For guest account, skip / since it's chrooted */
260 return (guest ? path+1 : path);
263 #ifndef LINE_MAX
264 #define LINE_MAX 1024
265 #endif
267 static int
268 parse_auth_level(char *str)
270 char *p;
271 int ret = 0;
272 char *foo = NULL;
274 for(p = strtok_r(str, ",", &foo);
276 p = strtok_r(NULL, ",", &foo)) {
277 if(strcmp(p, "user") == 0)
279 #ifdef OTP
280 else if(strcmp(p, "otp") == 0)
281 ret |= AUTH_PLAIN|AUTH_OTP;
282 #endif
283 else if(strcmp(p, "ftp") == 0 ||
284 strcmp(p, "safe") == 0)
285 ret |= AUTH_FTP;
286 else if(strcmp(p, "plain") == 0)
287 ret |= AUTH_PLAIN;
288 else if(strcmp(p, "none") == 0)
289 ret |= AUTH_PLAIN|AUTH_FTP;
290 else
291 warnx("bad value for -a: `%s'", p);
293 return ret;
297 * Print usage and die.
300 static void
301 usage (void)
303 fprintf (stderr,
304 "Usage: %s [-d] [-i] [-g guest_umask] [-l] [-p port]"
305 " [-t timeout] [-T max_timeout] [-u umask] [-v]"
306 " [-a auth_level] \n",
307 __progname);
308 exit (1);
312 main(int argc, char **argv)
314 int addrlen, ch, on = 1, tos;
315 char *cp, line[LINE_MAX];
316 FILE *fd;
317 int not_inetd = 0;
318 int port;
319 struct servent *sp;
320 char tkfile[1024];
322 set_progname (argv[0]);
324 /* detach from any tickets and tokens */
326 snprintf(tkfile, sizeof(tkfile),
327 "/tmp/ftp_%u", (unsigned)getpid());
328 krb_set_tkt_string(tkfile);
329 if(k_hasafs())
330 k_setpag();
332 sp = getservbyname("ftp", "tcp");
333 if(sp)
334 port = sp->s_port;
335 else
336 port = htons(21);
338 while ((ch = getopt(argc, argv, "a:dg:ilp:t:T:u:v")) != EOF) {
339 switch (ch) {
340 case 'a':
341 auth_level = parse_auth_level(optarg);
342 break;
343 case 'd':
344 debug = 1;
345 break;
347 case 'i':
348 not_inetd = 1;
349 break;
350 case 'g':
352 long val = 0;
354 val = strtol(optarg, &optarg, 8);
355 if (*optarg != '\0' || val < 0)
356 warnx("bad value for -g");
357 else
358 guest_umask = val;
359 break;
361 case 'l':
362 logging++; /* > 1 == extra logging */
363 break;
365 case 'p':
366 sp = getservbyname(optarg, "tcp");
367 if(sp)
368 port = sp->s_port;
369 else
370 if(isdigit(optarg[0]))
371 port = htons(atoi(optarg));
372 else
373 warnx("bad value for -p");
374 break;
376 case 't':
377 ftpd_timeout = atoi(optarg);
378 if (maxtimeout < ftpd_timeout)
379 maxtimeout = ftpd_timeout;
380 break;
382 case 'T':
383 maxtimeout = atoi(optarg);
384 if (ftpd_timeout > maxtimeout)
385 ftpd_timeout = maxtimeout;
386 break;
388 case 'u':
390 long val = 0;
392 val = strtol(optarg, &optarg, 8);
393 if (*optarg != '\0' || val < 0)
394 warnx("bad value for -u");
395 else
396 defumask = val;
397 break;
400 case 'v':
401 debug = 1;
402 break;
404 default:
405 usage ();
409 if(not_inetd)
410 mini_inetd (port);
413 * LOG_NDELAY sets up the logging connection immediately,
414 * necessary for anonymous ftp's that chroot and can't do it later.
416 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
417 addrlen = sizeof(his_addr);
418 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
419 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
420 exit(1);
422 addrlen = sizeof(ctrl_addr);
423 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
424 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
425 exit(1);
427 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
428 tos = IPTOS_LOWDELAY;
429 if (setsockopt(0, IPPROTO_IP, IP_TOS, (void *)&tos, sizeof(int)) < 0)
430 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
431 #endif
432 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
434 /* set this here so it can be put in wtmp */
435 snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
438 /* freopen(_PATH_DEVNULL, "w", stderr); */
439 signal(SIGPIPE, lostconn);
440 signal(SIGCHLD, SIG_IGN);
441 #ifdef SIGURG
442 if (signal(SIGURG, myoob) == SIG_ERR)
443 syslog(LOG_ERR, "signal: %m");
444 #endif
446 auth_init();
448 /* Try to handle urgent data inline */
449 #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
450 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on,
451 sizeof(on)) < 0)
452 syslog(LOG_ERR, "setsockopt: %m");
453 #endif
455 #ifdef F_SETOWN
456 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
457 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
458 #endif
459 dolog(&his_addr);
461 * Set up default state
463 data = -1;
464 type = TYPE_A;
465 form = FORM_N;
466 stru = STRU_F;
467 mode = MODE_S;
468 tmpline[0] = '\0';
470 /* If logins are disabled, print out the message. */
471 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
472 while (fgets(line, sizeof(line), fd) != NULL) {
473 if ((cp = strchr(line, '\n')) != NULL)
474 *cp = '\0';
475 lreply(530, "%s", line);
477 fflush(stdout);
478 fclose(fd);
479 reply(530, "System not available.");
480 exit(0);
482 if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
483 while (fgets(line, sizeof(line), fd) != NULL) {
484 if ((cp = strchr(line, '\n')) != NULL)
485 *cp = '\0';
486 lreply(220, "%s", line);
488 fflush(stdout);
489 fclose(fd);
490 /* reply(220,) must follow */
492 gethostname(hostname, sizeof(hostname));
493 reply(220, "%s FTP server (%s+%s) ready.", hostname,
494 version, krb4_version);
495 setjmp(errcatch);
496 for (;;)
497 yyparse();
498 /* NOTREACHED */
501 static RETSIGTYPE
502 lostconn(int signo)
505 if (debug)
506 syslog(LOG_DEBUG, "lost connection");
507 dologout(-1);
511 * Helper function for sgetpwnam().
513 static char *
514 sgetsave(char *s)
516 char *new = strdup(s);
518 if (new == NULL) {
519 perror_reply(421, "Local resource failure: malloc");
520 dologout(1);
521 /* NOTREACHED */
523 return new;
527 * Save the result of a getpwnam. Used for USER command, since
528 * the data returned must not be clobbered by any other command
529 * (e.g., globbing).
531 static struct passwd *
532 sgetpwnam(char *name)
534 static struct passwd save;
535 struct passwd *p;
537 if ((p = k_getpwnam(name)) == NULL)
538 return (p);
539 if (save.pw_name) {
540 free(save.pw_name);
541 free(save.pw_passwd);
542 free(save.pw_gecos);
543 free(save.pw_dir);
544 free(save.pw_shell);
546 save = *p;
547 save.pw_name = sgetsave(p->pw_name);
548 save.pw_passwd = sgetsave(p->pw_passwd);
549 save.pw_gecos = sgetsave(p->pw_gecos);
550 save.pw_dir = sgetsave(p->pw_dir);
551 save.pw_shell = sgetsave(p->pw_shell);
552 return (&save);
555 static int login_attempts; /* number of failed login attempts */
556 static int askpasswd; /* had user command, ask for passwd */
557 static char curname[10]; /* current USER name */
558 #ifdef OTP
559 OtpContext otp_ctx;
560 #endif
563 * USER command.
564 * Sets global passwd pointer pw if named account exists and is acceptable;
565 * sets askpasswd if a PASS command is expected. If logged in previously,
566 * need to reset state. If name is "ftp" or "anonymous", the name is not in
567 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
568 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
569 * requesting login privileges. Disallow anyone who does not have a standard
570 * shell as returned by getusershell(). Disallow anyone mentioned in the file
571 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
573 void
574 user(char *name)
576 char *cp, *shell;
578 if(auth_level == 0 && !auth_complete){
579 reply(530, "No login allowed without authorization.");
580 return;
583 if (logged_in) {
584 if (guest) {
585 reply(530, "Can't change user from guest login.");
586 return;
587 } else if (dochroot) {
588 reply(530, "Can't change user from chroot user.");
589 return;
591 end_login();
594 guest = 0;
595 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
596 if ((auth_level & AUTH_FTP) == 0 ||
597 checkaccess("ftp") ||
598 checkaccess("anonymous"))
599 reply(530, "User %s access denied.", name);
600 else if ((pw = sgetpwnam("ftp")) != NULL) {
601 guest = 1;
602 defumask = guest_umask; /* paranoia for incoming */
603 askpasswd = 1;
604 reply(331, "Guest login ok, type your name as password.");
605 } else
606 reply(530, "User %s unknown.", name);
607 if (!askpasswd && logging)
608 syslog(LOG_NOTICE,
609 "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
610 remotehost, inet_ntoa(his_addr.sin_addr));
611 return;
613 if((auth_level & AUTH_PLAIN) == 0 && !auth_complete){
614 reply(530, "Only authorized and anonymous login allowed.");
615 return;
617 if ((pw = sgetpwnam(name))) {
618 if ((shell = pw->pw_shell) == NULL || *shell == 0)
619 shell = _PATH_BSHELL;
620 while ((cp = getusershell()) != NULL)
621 if (strcmp(cp, shell) == 0)
622 break;
623 endusershell();
625 if (cp == NULL || checkaccess(name)) {
626 reply(530, "User %s access denied.", name);
627 if (logging)
628 syslog(LOG_NOTICE,
629 "FTP LOGIN REFUSED FROM %s(%s), %s",
630 remotehost,
631 inet_ntoa(his_addr.sin_addr),
632 name);
633 pw = (struct passwd *) NULL;
634 return;
637 if (logging)
638 strncpy(curname, name, sizeof(curname)-1);
639 if(auth_ok())
640 ct->userok(name);
641 else {
642 char ss[256];
644 #ifdef OTP
645 if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) {
646 reply(331, "Password %s for %s required.",
647 ss, name);
648 askpasswd = 1;
649 } else
650 #endif
651 if ((auth_level & AUTH_OTP) == 0) {
652 reply(331, "Password required for %s.", name);
653 askpasswd = 1;
654 } else {
655 char *s;
657 #ifdef OTP
658 if (s = otp_error (&otp_ctx))
659 lreply(530, "OTP: %s", s);
660 #endif
661 reply(530,
662 "Only authorized, anonymous"
663 #ifdef OTP
664 " and OTP "
665 #endif
666 "login allowed.");
671 * Delay before reading passwd after first failed
672 * attempt to slow down passwd-guessing programs.
674 if (login_attempts)
675 sleep(login_attempts);
679 * Check if a user is in the file "fname"
681 static int
682 checkuser(char *fname, char *name)
684 FILE *fd;
685 int found = 0;
686 char *p, line[BUFSIZ];
688 if ((fd = fopen(fname, "r")) != NULL) {
689 while (fgets(line, sizeof(line), fd) != NULL)
690 if ((p = strchr(line, '\n')) != NULL) {
691 *p = '\0';
692 if (line[0] == '#')
693 continue;
694 if (strcmp(line, name) == 0) {
695 found = 1;
696 break;
699 fclose(fd);
701 return (found);
706 * Determine whether a user has access, based on information in
707 * _PATH_FTPUSERS. The users are listed one per line, with `allow'
708 * or `deny' after the username. If anything other than `allow', or
709 * just nothing, is given after the username, `deny' is assumed.
711 * If the user is not found in the file, but the pseudo-user `*' is,
712 * the permission is taken from that line.
714 * This preserves the old semantics where if a user was listed in the
715 * file he was denied, otherwise he was allowed.
717 * Return 1 if the user is denied, or 0 if he is allowed. */
719 static int
720 match(const char *pattern, const char *string)
722 #ifdef HAVE_FNMATCH
723 return fnmatch(pattern, string, FNM_NOESCAPE);
724 #else
725 return strcmp(pattern, "*") != 0 && strcmp(pattern, string) != 0;
726 #endif
729 static int
730 checkaccess(char *name)
732 #define ALLOWED 0
733 #define NOT_ALLOWED 1
734 FILE *fd;
735 int allowed = ALLOWED;
736 char *user, *perm, line[BUFSIZ];
737 char *foo;
739 fd = fopen(_PATH_FTPUSERS, "r");
741 if(fd == NULL)
742 return allowed;
744 while (fgets(line, sizeof(line), fd) != NULL) {
745 foo = NULL;
746 user = strtok_r(line, " \t\n", &foo);
747 if (user == NULL || user[0] == '#')
748 continue;
749 perm = strtok_r(NULL, " \t\n", &foo);
750 if (match(user, name) == 0){
751 if(perm && strcmp(perm, "allow") == 0)
752 allowed = ALLOWED;
753 else
754 allowed = NOT_ALLOWED;
755 break;
758 fclose(fd);
759 return allowed;
761 #undef ALLOWED
762 #undef NOT_ALLOWED
764 int do_login(int code, char *passwd)
766 FILE *fd;
767 login_attempts = 0; /* this time successful */
768 if (setegid((gid_t)pw->pw_gid) < 0) {
769 reply(550, "Can't set gid.");
770 return -1;
772 initgroups(pw->pw_name, pw->pw_gid);
774 /* open wtmp before chroot */
775 logwtmp(ttyline, pw->pw_name, remotehost);
776 logged_in = 1;
778 dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
779 if (guest) {
781 * We MUST do a chdir() after the chroot. Otherwise
782 * the old current directory will be accessible as "."
783 * outside the new root!
785 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
786 reply(550, "Can't set guest privileges.");
787 return -1;
789 } else if (dochroot) {
790 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
791 reply(550, "Can't change root.");
792 return -1;
794 } else if (chdir(pw->pw_dir) < 0) {
795 if (chdir("/") < 0) {
796 reply(530, "User %s: can't change directory to %s.",
797 pw->pw_name, pw->pw_dir);
798 return -1;
799 } else
800 lreply(code, "No directory! Logging in with home=/");
802 if (seteuid((uid_t)pw->pw_uid) < 0) {
803 reply(550, "Can't set uid.");
804 return -1;
807 * Display a login message, if it exists.
808 * N.B. reply(code,) must follow the message.
810 if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
811 char *cp, line[LINE_MAX];
813 while (fgets(line, sizeof(line), fd) != NULL) {
814 if ((cp = strchr(line, '\n')) != NULL)
815 *cp = '\0';
816 lreply(code, "%s", line);
819 if (guest) {
820 reply(code, "Guest login ok, access restrictions apply.");
821 #ifdef HAVE_SETPROCTITLE
822 snprintf (proctitle, sizeof(proctitle),
823 "%s: anonymous/%s",
824 remotehost,
825 passwd);
826 #endif /* HAVE_SETPROCTITLE */
827 if (logging)
828 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
829 remotehost,
830 inet_ntoa(his_addr.sin_addr),
831 passwd);
832 } else {
833 reply(code, "User %s logged in.", pw->pw_name);
834 #ifdef HAVE_SETPROCTITLE
835 snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
836 setproctitle(proctitle);
837 #endif /* HAVE_SETPROCTITLE */
838 if (logging)
839 syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
840 remotehost,
841 inet_ntoa(his_addr.sin_addr),
842 pw->pw_name);
844 umask(defumask);
845 return 0;
849 * Terminate login as previous user, if any, resetting state;
850 * used when USER command is given or login fails.
852 static void
853 end_login(void)
856 seteuid((uid_t)0);
857 if (logged_in)
858 logwtmp(ttyline, "", "");
859 pw = NULL;
860 logged_in = 0;
861 guest = 0;
862 dochroot = 0;
865 void
866 pass(char *passwd)
868 int rval;
870 /* some clients insists on sending a password */
871 if (logged_in && askpasswd == 0){
872 reply(230, "Dumpucko!");
873 return;
876 if (logged_in || askpasswd == 0) {
877 reply(503, "Login with USER first.");
878 return;
880 askpasswd = 0;
881 rval = 1;
882 if (!guest) { /* "ftp" is only account allowed no password */
883 if (pw == NULL)
884 rval = 1; /* failure below */
885 #ifdef OTP
886 else if (otp_verify_user (&otp_ctx, passwd) == 0) {
887 rval = 0;
889 #endif
890 else if((auth_level & AUTH_OTP) == 0) {
891 char realm[REALM_SZ];
892 if((rval = krb_get_lrealm(realm, 1)) == KSUCCESS)
893 rval = krb_verify_user(pw->pw_name, "", realm,
894 passwd, 1, NULL);
895 if (rval == KSUCCESS ) {
896 chown (tkt_string(), pw->pw_uid, pw->pw_gid);
897 if(k_hasafs())
898 k_afsklog(0, 0);
899 } else
900 rval = unix_verify_user(pw->pw_name, passwd);
901 } else {
902 char *s;
904 #ifdef OTP
905 if (s = otp_error(&otp_ctx))
906 lreply(530, "OTP: %s", s);
907 #endif
909 memset (passwd, 0, strlen(passwd));
912 * If rval == 1, the user failed the authentication
913 * check above. If rval == 0, either Kerberos or
914 * local authentication succeeded.
916 if (rval) {
917 reply(530, "Login incorrect.");
918 if (logging)
919 syslog(LOG_NOTICE,
920 "FTP LOGIN FAILED FROM %s(%s), %s",
921 remotehost,
922 inet_ntoa(his_addr.sin_addr),
923 curname);
924 pw = NULL;
925 if (login_attempts++ >= 5) {
926 syslog(LOG_NOTICE,
927 "repeated login failures from %s(%s)",
928 remotehost,
929 inet_ntoa(his_addr.sin_addr));
930 exit(0);
932 return;
935 if(!do_login(230, passwd))
936 return;
938 /* Forget all about it... */
939 end_login();
942 void
943 retrieve(char *cmd, char *name)
945 FILE *fin = NULL, *dout;
946 struct stat st;
947 int (*closefunc) (FILE *);
948 char line[BUFSIZ];
951 if (cmd == 0) {
952 fin = fopen(name, "r");
953 closefunc = fclose;
954 st.st_size = 0;
955 if(fin == NULL){
956 struct cmds {
957 char *ext;
958 char *cmd;
959 } cmds[] = {
960 {".tar", "/bin/gtar cPf - %s"},
961 {".tar.gz", "/bin/gtar zcPf - %s"},
962 {".tar.Z", "/bin/gtar ZcPf - %s"},
963 {".gz", "/bin/gzip -c %s"},
964 {".Z", "/bin/compress -c %s"},
965 {NULL, NULL}
967 struct cmds *p;
968 for(p = cmds; p->ext; p++){
969 char *tail = name + strlen(name) - strlen(p->ext);
970 char c = *tail;
972 if(strcmp(tail, p->ext) == 0 &&
973 (*tail = 0) == 0 &&
974 access(name, R_OK) == 0){
975 snprintf (line, sizeof(line), p->cmd, name);
976 *tail = c;
977 break;
979 *tail = c;
981 if(p->ext){
982 fin = ftpd_popen(line, "r", 0, 0);
983 closefunc = ftpd_pclose;
984 st.st_size = -1;
985 cmd = line;
988 } else {
989 snprintf(line, sizeof(line), cmd, name);
990 name = line;
991 fin = ftpd_popen(line, "r", 1, 0);
992 closefunc = ftpd_pclose;
993 st.st_size = -1;
995 if (fin == NULL) {
996 if (errno != 0) {
997 perror_reply(550, name);
998 if (cmd == 0) {
999 LOGCMD("get", name);
1002 return;
1004 byte_count = -1;
1005 if (cmd == 0){
1006 if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
1007 reply(550, "%s: not a plain file.", name);
1008 goto done;
1011 if (restart_point) {
1012 if (type == TYPE_A) {
1013 off_t i, n;
1014 int c;
1016 n = restart_point;
1017 i = 0;
1018 while (i++ < n) {
1019 if ((c=getc(fin)) == EOF) {
1020 perror_reply(550, name);
1021 goto done;
1023 if (c == '\n')
1024 i++;
1026 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1027 perror_reply(550, name);
1028 goto done;
1031 dout = dataconn(name, st.st_size, "w");
1032 if (dout == NULL)
1033 goto done;
1034 set_buffer_size(fileno(dout), 0);
1035 send_data(fin, dout);
1036 fclose(dout);
1037 data = -1;
1038 pdata = -1;
1039 done:
1040 if (cmd == 0)
1041 LOGBYTES("get", name, byte_count);
1042 (*closefunc)(fin);
1045 /* filename sanity check */
1047 int
1048 filename_check(char *filename)
1050 static const char good_chars[] = "+-=_,.";
1051 char *p;
1053 p = strrchr(filename, '/');
1054 if(p)
1055 filename = p + 1;
1057 p = filename;
1059 if(isalnum(*p)){
1060 p++;
1061 while(*p && (isalnum(*p) || strchr(good_chars, *p)))
1062 p++;
1063 if(*p == '\0')
1064 return 0;
1066 lreply(553, "\"%s\" is an illegal filename.", filename);
1067 lreply(553, "The filename must start with an alphanumeric "
1068 "character and must only");
1069 reply(553, "consist of alphanumeric characters or any of the following: %s",
1070 good_chars);
1071 return 1;
1074 void
1075 do_store(char *name, char *mode, int unique)
1077 FILE *fout, *din;
1078 struct stat st;
1079 int (*closefunc) (FILE *);
1081 if(guest && filename_check(name))
1082 return;
1083 if (unique && stat(name, &st) == 0 &&
1084 (name = gunique(name)) == NULL) {
1085 LOGCMD(*mode == 'w' ? "put" : "append", name);
1086 return;
1089 if (restart_point)
1090 mode = "r+";
1091 fout = fopen(name, mode);
1092 closefunc = fclose;
1093 if (fout == NULL) {
1094 perror_reply(553, name);
1095 LOGCMD(*mode == 'w' ? "put" : "append", name);
1096 return;
1098 byte_count = -1;
1099 if (restart_point) {
1100 if (type == TYPE_A) {
1101 off_t i, n;
1102 int c;
1104 n = restart_point;
1105 i = 0;
1106 while (i++ < n) {
1107 if ((c=getc(fout)) == EOF) {
1108 perror_reply(550, name);
1109 goto done;
1111 if (c == '\n')
1112 i++;
1115 * We must do this seek to "current" position
1116 * because we are changing from reading to
1117 * writing.
1119 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1120 perror_reply(550, name);
1121 goto done;
1123 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1124 perror_reply(550, name);
1125 goto done;
1128 din = dataconn(name, (off_t)-1, "r");
1129 if (din == NULL)
1130 goto done;
1131 set_buffer_size(fileno(din), 1);
1132 if (receive_data(din, fout) == 0) {
1133 if (unique)
1134 reply(226, "Transfer complete (unique file name:%s).",
1135 name);
1136 else
1137 reply(226, "Transfer complete.");
1139 fclose(din);
1140 data = -1;
1141 pdata = -1;
1142 done:
1143 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1144 (*closefunc)(fout);
1147 static FILE *
1148 getdatasock(char *mode)
1150 int on = 1, s, t, tries;
1152 if (data >= 0)
1153 return (fdopen(data, mode));
1154 seteuid((uid_t)0);
1155 s = socket(AF_INET, SOCK_STREAM, 0);
1156 if (s < 0)
1157 goto bad;
1158 #if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
1159 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1160 (void *) &on, sizeof(on)) < 0)
1161 goto bad;
1162 #endif
1163 /* anchor socket to avoid multi-homing problems */
1164 data_source.sin_family = AF_INET;
1165 data_source.sin_addr = ctrl_addr.sin_addr;
1166 for (tries = 1; ; tries++) {
1167 if (bind(s, (struct sockaddr *)&data_source,
1168 sizeof(data_source)) >= 0)
1169 break;
1170 if (errno != EADDRINUSE || tries > 10)
1171 goto bad;
1172 sleep(tries);
1174 seteuid((uid_t)pw->pw_uid);
1175 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
1176 on = IPTOS_THROUGHPUT;
1177 if (setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&on, sizeof(int)) < 0)
1178 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1179 #endif
1180 return (fdopen(s, mode));
1181 bad:
1182 /* Return the real value of errno (close may change it) */
1183 t = errno;
1184 seteuid((uid_t)pw->pw_uid);
1185 close(s);
1186 errno = t;
1187 return (NULL);
1190 static FILE *
1191 dataconn(char *name, off_t size, char *mode)
1193 char sizebuf[32];
1194 FILE *file;
1195 int retry = 0, tos;
1197 file_size = size;
1198 byte_count = 0;
1199 if (size != (off_t) -1)
1200 snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", size);
1201 else
1202 strcpy(sizebuf, "");
1203 if (pdata >= 0) {
1204 struct sockaddr_in from;
1205 int s, fromlen = sizeof(from);
1207 s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1208 if (s < 0) {
1209 reply(425, "Can't open data connection.");
1210 close(pdata);
1211 pdata = -1;
1212 return (NULL);
1214 close(pdata);
1215 pdata = s;
1216 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
1217 tos = IPTOS_THROUGHPUT;
1218 setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&tos,
1219 sizeof(int));
1220 #endif
1221 reply(150, "Opening %s mode data connection for '%s'%s.",
1222 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1223 return (fdopen(pdata, mode));
1225 if (data >= 0) {
1226 reply(125, "Using existing data connection for '%s'%s.",
1227 name, sizebuf);
1228 usedefault = 1;
1229 return (fdopen(data, mode));
1231 if (usedefault)
1232 data_dest = his_addr;
1233 usedefault = 1;
1234 file = getdatasock(mode);
1235 if (file == NULL) {
1236 reply(425, "Can't create data socket (%s,%d): %s.",
1237 inet_ntoa(data_source.sin_addr),
1238 ntohs(data_source.sin_port), strerror(errno));
1239 return (NULL);
1241 data = fileno(file);
1242 while (connect(data, (struct sockaddr *)&data_dest,
1243 sizeof(data_dest)) < 0) {
1244 if (errno == EADDRINUSE && retry < swaitmax) {
1245 sleep((unsigned) swaitint);
1246 retry += swaitint;
1247 continue;
1249 perror_reply(425, "Can't build data connection");
1250 fclose(file);
1251 data = -1;
1252 return (NULL);
1254 reply(150, "Opening %s mode data connection for '%s'%s.",
1255 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1256 return (file);
1260 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1261 * encapsulation of the data subject * to Mode, Structure, and Type.
1263 * NB: Form isn't handled.
1265 static void
1266 send_data(FILE *instr, FILE *outstr)
1268 int c, cnt, filefd, netfd;
1269 static char *buf;
1270 static size_t bufsize;
1271 int i = 0;
1272 char s[1024];
1274 transflag++;
1275 if (setjmp(urgcatch)) {
1276 transflag = 0;
1277 return;
1279 switch (type) {
1281 case TYPE_A:
1282 while ((c = getc(instr)) != EOF) {
1283 byte_count++;
1284 if(i > 1022){
1285 auth_write(fileno(outstr), s, i);
1286 i = 0;
1288 if(c == '\n')
1289 s[i++] = '\r';
1290 s[i++] = c;
1292 if(i)
1293 auth_write(fileno(outstr), s, i);
1294 auth_write(fileno(outstr), s, 0);
1295 fflush(outstr);
1296 transflag = 0;
1297 if (ferror(instr))
1298 goto file_err;
1299 if (ferror(outstr))
1300 goto data_err;
1301 reply(226, "Transfer complete.");
1302 return;
1304 case TYPE_I:
1305 case TYPE_L:
1306 #ifdef HAVE_MMAP
1307 #ifndef MAP_FAILED
1308 #define MAP_FAILED (-1)
1309 #endif
1311 struct stat st;
1312 char *chunk;
1313 int in = fileno(instr);
1314 if(fstat(in, &st) == 0 && S_ISREG(st.st_mode)) {
1315 chunk = mmap(0, st.st_size, PROT_READ, MAP_SHARED, in, 0);
1316 if(chunk != (void *)MAP_FAILED) {
1317 cnt = st.st_size - restart_point;
1318 auth_write(fileno(outstr),
1319 chunk + restart_point,
1320 cnt);
1321 munmap(chunk, st.st_size);
1322 auth_write(fileno(outstr), NULL, 0);
1323 byte_count = cnt;
1324 transflag = 0;
1329 #endif
1330 if(transflag){
1331 struct stat st;
1333 netfd = fileno(outstr);
1334 filefd = fileno(instr);
1335 buf = alloc_buffer (buf, &bufsize,
1336 fstat(filefd, &st) >= 0 ? &st : NULL);
1337 if (buf == NULL) {
1338 transflag = 0;
1339 perror_reply(451, "Local resource failure: malloc");
1340 return;
1342 while ((cnt = read(filefd, buf, bufsize)) > 0 &&
1343 auth_write(netfd, buf, cnt) == cnt)
1344 byte_count += cnt;
1345 auth_write(netfd, buf, 0); /* to end an encrypted stream */
1346 transflag = 0;
1347 if (cnt != 0) {
1348 if (cnt < 0)
1349 goto file_err;
1350 goto data_err;
1353 reply(226, "Transfer complete.");
1354 return;
1355 default:
1356 transflag = 0;
1357 reply(550, "Unimplemented TYPE %d in send_data", type);
1358 return;
1361 data_err:
1362 transflag = 0;
1363 perror_reply(426, "Data connection");
1364 return;
1366 file_err:
1367 transflag = 0;
1368 perror_reply(551, "Error on input file");
1372 * Transfer data from peer to "outstr" using the appropriate encapulation of
1373 * the data subject to Mode, Structure, and Type.
1375 * N.B.: Form isn't handled.
1377 static int
1378 receive_data(FILE *instr, FILE *outstr)
1380 int cnt, bare_lfs = 0;
1381 static char *buf;
1382 static size_t bufsize;
1383 struct stat st;
1385 transflag++;
1386 if (setjmp(urgcatch)) {
1387 transflag = 0;
1388 return (-1);
1391 buf = alloc_buffer (buf, &bufsize,
1392 fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
1393 if (buf == NULL) {
1394 transflag = 0;
1395 perror_reply(451, "Local resource failure: malloc");
1396 return -1;
1399 switch (type) {
1401 case TYPE_I:
1402 case TYPE_L:
1403 while ((cnt = auth_read(fileno(instr), buf, bufsize)) > 0) {
1404 if (write(fileno(outstr), buf, cnt) != cnt)
1405 goto file_err;
1406 byte_count += cnt;
1408 if (cnt < 0)
1409 goto data_err;
1410 transflag = 0;
1411 return (0);
1413 case TYPE_E:
1414 reply(553, "TYPE E not implemented.");
1415 transflag = 0;
1416 return (-1);
1418 case TYPE_A:
1420 char *p, *q;
1421 int cr_flag = 0;
1422 while ((cnt = auth_read(fileno(instr),
1423 buf + cr_flag,
1424 bufsize - cr_flag)) > 0){
1425 byte_count += cnt;
1426 cnt += cr_flag;
1427 cr_flag = 0;
1428 for(p = buf, q = buf; p < buf + cnt;) {
1429 if(*p == '\n')
1430 bare_lfs++;
1431 if(*p == '\r')
1432 if(p == buf + cnt - 1){
1433 cr_flag = 1;
1434 p++;
1435 continue;
1436 }else if(p[1] == '\n'){
1437 *q++ = '\n';
1438 p += 2;
1439 continue;
1441 *q++ = *p++;
1443 fwrite(buf, q - buf, 1, outstr);
1444 if(cr_flag)
1445 buf[0] = '\r';
1447 if(cr_flag)
1448 putc('\r', outstr);
1449 fflush(outstr);
1450 if (ferror(instr))
1451 goto data_err;
1452 if (ferror(outstr))
1453 goto file_err;
1454 transflag = 0;
1455 if (bare_lfs) {
1456 lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
1457 " File may not have transferred correctly.\r\n",
1458 bare_lfs);
1460 return (0);
1462 default:
1463 reply(550, "Unimplemented TYPE %d in receive_data", type);
1464 transflag = 0;
1465 return (-1);
1468 data_err:
1469 transflag = 0;
1470 perror_reply(426, "Data Connection");
1471 return (-1);
1473 file_err:
1474 transflag = 0;
1475 perror_reply(452, "Error writing file");
1476 return (-1);
1479 void
1480 statfilecmd(char *filename)
1482 FILE *fin;
1483 int c;
1484 char line[LINE_MAX];
1486 snprintf(line, sizeof(line), "/bin/ls -la %s", filename);
1487 fin = ftpd_popen(line, "r", 1, 0);
1488 lreply(211, "status of %s:", filename);
1489 while ((c = getc(fin)) != EOF) {
1490 if (c == '\n') {
1491 if (ferror(stdout)){
1492 perror_reply(421, "control connection");
1493 ftpd_pclose(fin);
1494 dologout(1);
1495 /* NOTREACHED */
1497 if (ferror(fin)) {
1498 perror_reply(551, filename);
1499 ftpd_pclose(fin);
1500 return;
1502 putc('\r', stdout);
1504 putc(c, stdout);
1506 ftpd_pclose(fin);
1507 reply(211, "End of Status");
1510 void
1511 statcmd(void)
1513 #if 0
1514 struct sockaddr_in *sin;
1515 u_char *a, *p;
1517 lreply(211, "%s FTP server status:", hostname, version);
1518 printf(" %s\r\n", version);
1519 printf(" Connected to %s", remotehost);
1520 if (!isdigit(remotehost[0]))
1521 printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1522 printf("\r\n");
1523 if (logged_in) {
1524 if (guest)
1525 printf(" Logged in anonymously\r\n");
1526 else
1527 printf(" Logged in as %s\r\n", pw->pw_name);
1528 } else if (askpasswd)
1529 printf(" Waiting for password\r\n");
1530 else
1531 printf(" Waiting for user name\r\n");
1532 printf(" TYPE: %s", typenames[type]);
1533 if (type == TYPE_A || type == TYPE_E)
1534 printf(", FORM: %s", formnames[form]);
1535 if (type == TYPE_L)
1536 #if NBBY == 8
1537 printf(" %d", NBBY);
1538 #else
1539 printf(" %d", bytesize); /* need definition! */
1540 #endif
1541 printf("; STRUcture: %s; transfer MODE: %s\r\n",
1542 strunames[stru], modenames[mode]);
1543 if (data != -1)
1544 printf(" Data connection open\r\n");
1545 else if (pdata != -1) {
1546 printf(" in Passive mode");
1547 sin = &pasv_addr;
1548 goto printaddr;
1549 } else if (usedefault == 0) {
1550 printf(" PORT");
1551 sin = &data_dest;
1552 printaddr:
1553 a = (u_char *) &sin->sin_addr;
1554 p = (u_char *) &sin->sin_port;
1555 #define UC(b) (((int) b) & 0xff)
1556 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1557 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1558 #undef UC
1559 } else
1560 printf(" No data connection\r\n");
1561 #endif
1562 reply(211, "End of status");
1565 void
1566 fatal(char *s)
1569 reply(451, "Error in server: %s\n", s);
1570 reply(221, "Closing connection due to server error.");
1571 dologout(0);
1572 /* NOTREACHED */
1575 static void
1576 int_reply(int, char *, const char *, va_list)
1577 #ifdef __GNUC__
1578 __attribute__ ((format (printf, 3, 0)))
1579 #endif
1582 static void
1583 int_reply(int n, char *c, const char *fmt, va_list ap)
1585 char buf[10240];
1586 char *p;
1587 p=buf;
1588 if(n){
1589 snprintf(p, sizeof(buf), "%d%s", n, c);
1590 p+=strlen(p);
1592 vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap);
1593 p+=strlen(p);
1594 snprintf(p, sizeof(buf) - strlen(p), "\r\n");
1595 p+=strlen(p);
1596 auth_printf("%s", buf);
1597 fflush(stdout);
1598 if (debug)
1599 syslog(LOG_DEBUG, "<--- %s- ", buf);
1602 void
1603 reply(int n, const char *fmt, ...)
1605 va_list ap;
1606 va_start(ap, fmt);
1607 int_reply(n, " ", fmt, ap);
1608 delete_ftp_command();
1609 va_end(ap);
1612 void
1613 lreply(int n, const char *fmt, ...)
1615 va_list ap;
1616 va_start(ap, fmt);
1617 int_reply(n, "-", fmt, ap);
1618 va_end(ap);
1621 void
1622 nreply(const char *fmt, ...)
1624 va_list ap;
1625 va_start(ap, fmt);
1626 int_reply(0, NULL, fmt, ap);
1627 va_end(ap);
1630 static void
1631 ack(char *s)
1634 reply(250, "%s command successful.", s);
1637 void
1638 nack(char *s)
1641 reply(502, "%s command not implemented.", s);
1644 /* ARGSUSED */
1645 void
1646 yyerror(char *s)
1648 char *cp;
1650 if ((cp = strchr(cbuf,'\n')))
1651 *cp = '\0';
1652 reply(500, "'%s': command not understood.", cbuf);
1655 void
1656 do_delete(char *name)
1658 struct stat st;
1660 LOGCMD("delete", name);
1661 if (stat(name, &st) < 0) {
1662 perror_reply(550, name);
1663 return;
1665 if ((st.st_mode&S_IFMT) == S_IFDIR) {
1666 if (rmdir(name) < 0) {
1667 perror_reply(550, name);
1668 return;
1670 goto done;
1672 if (unlink(name) < 0) {
1673 perror_reply(550, name);
1674 return;
1676 done:
1677 ack("DELE");
1680 void
1681 cwd(char *path)
1684 if (chdir(path) < 0)
1685 perror_reply(550, path);
1686 else
1687 ack("CWD");
1690 void
1691 makedir(char *name)
1694 LOGCMD("mkdir", name);
1695 if(guest && filename_check(name))
1696 return;
1697 if (mkdir(name, 0777) < 0)
1698 perror_reply(550, name);
1699 else{
1700 if(guest)
1701 chmod(name, 0700); /* guest has umask 777 */
1702 reply(257, "MKD command successful.");
1706 void
1707 removedir(char *name)
1710 LOGCMD("rmdir", name);
1711 if (rmdir(name) < 0)
1712 perror_reply(550, name);
1713 else
1714 ack("RMD");
1717 void
1718 pwd(void)
1720 char path[MaxPathLen + 1];
1721 char *ret;
1723 /* SunOS has a broken getcwd that does popen(pwd) (!!!), this
1724 * failes miserably when running chroot
1726 ret = getcwd(path, sizeof(path));
1727 if (ret == NULL)
1728 reply(550, "%s.", strerror(errno));
1729 else
1730 reply(257, "\"%s\" is current directory.", path);
1733 char *
1734 renamefrom(char *name)
1736 struct stat st;
1738 if (stat(name, &st) < 0) {
1739 perror_reply(550, name);
1740 return NULL;
1742 reply(350, "File exists, ready for destination name");
1743 return (name);
1746 void
1747 renamecmd(char *from, char *to)
1750 LOGCMD2("rename", from, to);
1751 if(guest && filename_check(to))
1752 return;
1753 if (rename(from, to) < 0)
1754 perror_reply(550, "rename");
1755 else
1756 ack("RNTO");
1759 static void
1760 dolog(struct sockaddr_in *sin)
1762 inaddr2str (sin->sin_addr, remotehost, sizeof(remotehost));
1763 #ifdef HAVE_SETPROCTITLE
1764 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1765 setproctitle(proctitle);
1766 #endif /* HAVE_SETPROCTITLE */
1768 if (logging)
1769 syslog(LOG_INFO, "connection from %s(%s)",
1770 remotehost,
1771 inet_ntoa(his_addr.sin_addr));
1775 * Record logout in wtmp file
1776 * and exit with supplied status.
1778 void
1779 dologout(int status)
1781 transflag = 0;
1782 if (logged_in) {
1783 seteuid((uid_t)0);
1784 logwtmp(ttyline, "", "");
1785 cond_kdestroy();
1787 /* beware of flushing buffers after a SIGPIPE */
1788 #ifdef XXX
1789 exit(status);
1790 #else
1791 _exit(status);
1792 #endif
1795 void abor(void)
1799 static void
1800 myoob(int signo)
1802 #if 0
1803 char *cp;
1804 #endif
1806 /* only process if transfer occurring */
1807 if (!transflag)
1808 return;
1810 /* This is all XXX */
1811 oobflag = 1;
1812 /* if the command resulted in a new command,
1813 parse that as well */
1815 yyparse();
1816 } while(ftp_command);
1817 oobflag = 0;
1819 #if 0
1820 cp = tmpline;
1821 if (getline(cp, 7) == NULL) {
1822 reply(221, "You could at least say goodbye.");
1823 dologout(0);
1825 upper(cp);
1826 if (strcmp(cp, "ABOR\r\n") == 0) {
1827 tmpline[0] = '\0';
1828 reply(426, "Transfer aborted. Data connection closed.");
1829 reply(226, "Abort successful");
1830 longjmp(urgcatch, 1);
1832 if (strcmp(cp, "STAT\r\n") == 0) {
1833 if (file_size != (off_t) -1)
1834 reply(213, "Status: %ld of %ld bytes transferred",
1835 (long)byte_count,
1836 (long)file_size);
1837 else
1838 reply(213, "Status: %ld bytes transferred"
1839 (long)byte_count);
1841 #endif
1845 * Note: a response of 425 is not mentioned as a possible response to
1846 * the PASV command in RFC959. However, it has been blessed as
1847 * a legitimate response by Jon Postel in a telephone conversation
1848 * with Rick Adams on 25 Jan 89.
1850 void
1851 passive(void)
1853 int len;
1854 char *p, *a;
1856 pdata = socket(AF_INET, SOCK_STREAM, 0);
1857 if (pdata < 0) {
1858 perror_reply(425, "Can't open passive connection");
1859 return;
1861 pasv_addr = ctrl_addr;
1862 pasv_addr.sin_port = 0;
1863 seteuid((uid_t)0);
1864 if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
1865 seteuid((uid_t)pw->pw_uid);
1866 goto pasv_error;
1868 seteuid((uid_t)pw->pw_uid);
1869 len = sizeof(pasv_addr);
1870 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1871 goto pasv_error;
1872 if (listen(pdata, 1) < 0)
1873 goto pasv_error;
1874 a = (char *) &pasv_addr.sin_addr;
1875 p = (char *) &pasv_addr.sin_port;
1877 #define UC(b) (((int) b) & 0xff)
1879 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1880 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1881 return;
1883 pasv_error:
1884 close(pdata);
1885 pdata = -1;
1886 perror_reply(425, "Can't open passive connection");
1887 return;
1891 * Generate unique name for file with basename "local".
1892 * The file named "local" is already known to exist.
1893 * Generates failure reply on error.
1895 static char *
1896 gunique(char *local)
1898 static char new[MaxPathLen];
1899 struct stat st;
1900 int count;
1901 char *cp;
1903 cp = strrchr(local, '/');
1904 if (cp)
1905 *cp = '\0';
1906 if (stat(cp ? local : ".", &st) < 0) {
1907 perror_reply(553, cp ? local : ".");
1908 return NULL;
1910 if (cp)
1911 *cp = '/';
1912 for (count = 1; count < 100; count++) {
1913 snprintf (new, sizeof(new), "%s.%d", local, count);
1914 if (stat(new, &st) < 0)
1915 return (new);
1917 reply(452, "Unique file name cannot be created.");
1918 return (NULL);
1922 * Format and send reply containing system error number.
1924 void
1925 perror_reply(int code, char *string)
1927 reply(code, "%s: %s.", string, strerror(errno));
1930 static char *onefile[] = {
1935 void
1936 send_file_list(char *whichf)
1938 struct stat st;
1939 DIR *dirp = NULL;
1940 struct dirent *dir;
1941 FILE *dout = NULL;
1942 char **dirlist, *dirname;
1943 int simple = 0;
1944 int freeglob = 0;
1945 glob_t gl;
1946 char buf[MaxPathLen];
1948 if (strpbrk(whichf, "~{[*?") != NULL) {
1949 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1951 memset(&gl, 0, sizeof(gl));
1952 freeglob = 1;
1953 if (glob(whichf, flags, 0, &gl)) {
1954 reply(550, "not found");
1955 goto out;
1956 } else if (gl.gl_pathc == 0) {
1957 errno = ENOENT;
1958 perror_reply(550, whichf);
1959 goto out;
1961 dirlist = gl.gl_pathv;
1962 } else {
1963 onefile[0] = whichf;
1964 dirlist = onefile;
1965 simple = 1;
1968 if (setjmp(urgcatch)) {
1969 transflag = 0;
1970 goto out;
1972 while ((dirname = *dirlist++)) {
1973 if (stat(dirname, &st) < 0) {
1975 * If user typed "ls -l", etc, and the client
1976 * used NLST, do what the user meant.
1978 if (dirname[0] == '-' && *dirlist == NULL &&
1979 transflag == 0) {
1980 retrieve("/bin/ls %s", dirname);
1981 goto out;
1983 perror_reply(550, whichf);
1984 if (dout != NULL) {
1985 fclose(dout);
1986 transflag = 0;
1987 data = -1;
1988 pdata = -1;
1990 goto out;
1993 if (S_ISREG(st.st_mode)) {
1994 if (dout == NULL) {
1995 dout = dataconn("file list", (off_t)-1, "w");
1996 if (dout == NULL)
1997 goto out;
1998 transflag++;
2000 snprintf(buf, sizeof(buf), "%s%s\n", dirname,
2001 type == TYPE_A ? "\r" : "");
2002 auth_write(fileno(dout), buf, strlen(buf));
2003 byte_count += strlen(dirname) + 1;
2004 continue;
2005 } else if (!S_ISDIR(st.st_mode))
2006 continue;
2008 if ((dirp = opendir(dirname)) == NULL)
2009 continue;
2011 while ((dir = readdir(dirp)) != NULL) {
2012 char nbuf[MaxPathLen];
2014 if (!strcmp(dir->d_name, "."))
2015 continue;
2016 if (!strcmp(dir->d_name, ".."))
2017 continue;
2019 snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
2022 * We have to do a stat to insure it's
2023 * not a directory or special file.
2025 if (simple || (stat(nbuf, &st) == 0 &&
2026 S_ISREG(st.st_mode))) {
2027 if (dout == NULL) {
2028 dout = dataconn("file list", (off_t)-1, "w");
2029 if (dout == NULL)
2030 goto out;
2031 transflag++;
2033 if(strncmp(nbuf, "./", 2) == 0)
2034 snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
2035 type == TYPE_A ? "\r" : "");
2036 else
2037 snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
2038 type == TYPE_A ? "\r" : "");
2039 auth_write(fileno(dout), buf, strlen(buf));
2040 byte_count += strlen(nbuf) + 1;
2043 closedir(dirp);
2045 if (dout == NULL)
2046 reply(550, "No files found.");
2047 else if (ferror(dout) != 0)
2048 perror_reply(550, "Data connection");
2049 else
2050 reply(226, "Transfer complete.");
2052 transflag = 0;
2053 if (dout != NULL){
2054 auth_write(fileno(dout), buf, 0); /* XXX flush */
2056 fclose(dout);
2058 data = -1;
2059 pdata = -1;
2060 out:
2061 if (freeglob) {
2062 freeglob = 0;
2063 globfree(&gl);
2069 find(char *pattern)
2071 char line[1024];
2072 FILE *f;
2074 snprintf(line, sizeof(line),
2075 "/bin/locate -d %s %s",
2076 ftp_rooted("/etc/locatedb"),
2077 pattern);
2078 f = ftpd_popen(line, "r", 1, 1);
2079 if(f == NULL){
2080 perror_reply(550, "/bin/locate");
2081 return 1;
2083 lreply(200, "Output from find.");
2084 while(fgets(line, sizeof(line), f)){
2085 if(line[strlen(line)-1] == '\n')
2086 line[strlen(line)-1] = 0;
2087 nreply("%s", line);
2089 reply(200, "Done");
2090 ftpd_pclose(f);
2091 return 0;