only set IP_TOS on IPv4 sockets
[heimdal.git] / appl / ftp / ftpd / ftpd.c
blobddfed2129f09cc5da45f67a4a86e40dbc93230ff
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 #define FTP_NAMES
35 #include "ftpd_locl.h"
36 #ifdef KRB5
37 #include <krb5.h>
38 #endif
39 #include "getarg.h"
41 RCSID("$Id$");
43 static char version[] = "Version 6.00";
45 extern off_t restart_point;
46 extern char cbuf[];
48 struct sockaddr_storage ctrl_addr_ss;
49 struct sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss;
51 struct sockaddr_storage data_source_ss;
52 struct sockaddr *data_source = (struct sockaddr *)&data_source_ss;
54 struct sockaddr_storage data_dest_ss;
55 struct sockaddr *data_dest = (struct sockaddr *)&data_dest_ss;
57 struct sockaddr_storage his_addr_ss;
58 struct sockaddr *his_addr = (struct sockaddr *)&his_addr_ss;
60 struct sockaddr_storage pasv_addr_ss;
61 struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
63 int data;
64 int logged_in;
65 struct passwd *pw;
66 int debug = 0;
67 int ftpd_timeout = 900; /* timeout after 15 minutes of inactivity */
68 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
69 int restricted_data_ports = 1;
70 int logging;
71 int guest;
72 int dochroot;
73 int type;
74 int form;
75 int stru; /* avoid C keyword */
76 int mode;
77 int usedefault = 1; /* for data transfers */
78 int pdata = -1; /* for passive mode */
79 int allow_insecure_oob = 1;
80 static int transflag;
81 static int urgflag;
82 off_t file_size;
83 off_t byte_count;
84 #if !defined(CMASK) || CMASK == 0
85 #undef CMASK
86 #define CMASK 027
87 #endif
88 int defumask = CMASK; /* default umask value */
89 int guest_umask = 0777; /* Paranoia for anonymous users */
90 char tmpline[10240];
91 char hostname[MaxHostNameLen];
92 char remotehost[MaxHostNameLen];
93 static char ttyline[20];
94 int paranoid = 1;
96 #define AUTH_PLAIN (1 << 0) /* allow sending passwords */
97 #define AUTH_OTP (1 << 1) /* passwords are one-time */
98 #define AUTH_FTP (1 << 2) /* allow anonymous login */
100 static int auth_level = 0; /* Only allow kerberos login by default */
103 * Timeout intervals for retrying connections
104 * to hosts that don't accept PORT cmds. This
105 * is a kludge, but given the problems with TCP...
107 #define SWAITMAX 90 /* wait at most 90 seconds */
108 #define SWAITINT 5 /* interval between retries */
110 int swaitmax = SWAITMAX;
111 int swaitint = SWAITINT;
113 #ifdef HAVE_SETPROCTITLE
114 char proctitle[BUFSIZ]; /* initial part of title */
115 #endif /* HAVE_SETPROCTITLE */
117 #define LOGCMD(cmd, file) \
118 if (logging > 1) \
119 syslog(LOG_INFO,"%s %s%s", cmd, \
120 *(file) == '/' ? "" : curdir(), file);
121 #define LOGCMD2(cmd, file1, file2) \
122 if (logging > 1) \
123 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
124 *(file1) == '/' ? "" : curdir(), file1, \
125 *(file2) == '/' ? "" : curdir(), file2);
126 #define LOGBYTES(cmd, file, cnt) \
127 if (logging > 1) { \
128 if (cnt == (off_t)-1) \
129 syslog(LOG_INFO,"%s %s%s", cmd, \
130 *(file) == '/' ? "" : curdir(), file); \
131 else \
132 syslog(LOG_INFO, "%s %s%s = %ld bytes", \
133 cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \
136 static void ack (char *);
137 static void myoob (int);
138 static int handleoobcmd(void);
139 static int checkuser (char *, char *);
140 static int checkaccess (char *);
141 static FILE *dataconn (const char *, off_t, const char *);
142 static void dolog (struct sockaddr *, int);
143 static void end_login (void);
144 static FILE *getdatasock (const char *, int);
145 static char *gunique (char *);
146 static RETSIGTYPE lostconn (int);
147 static int receive_data (FILE *, FILE *);
148 static void send_data (FILE *, FILE *);
149 static struct passwd * sgetpwnam (char *);
151 static char *
152 curdir(void)
154 static char path[MaxPathLen+1]; /* path + '/' + '\0' */
156 if (getcwd(path, sizeof(path)-1) == NULL)
157 return ("");
158 if (path[1] != '\0') /* special case for root dir. */
159 strlcat(path, "/", sizeof(path));
160 /* For guest account, skip / since it's chrooted */
161 return (guest ? path+1 : path);
164 #ifndef LINE_MAX
165 #define LINE_MAX 1024
166 #endif
168 static int
169 parse_auth_level(char *str)
171 char *p;
172 int ret = 0;
173 char *foo = NULL;
175 for(p = strtok_r(str, ",", &foo);
177 p = strtok_r(NULL, ",", &foo)) {
178 if(strcmp(p, "user") == 0)
180 #ifdef OTP
181 else if(strcmp(p, "otp") == 0)
182 ret |= AUTH_PLAIN|AUTH_OTP;
183 #endif
184 else if(strcmp(p, "ftp") == 0 ||
185 strcmp(p, "safe") == 0)
186 ret |= AUTH_FTP;
187 else if(strcmp(p, "plain") == 0)
188 ret |= AUTH_PLAIN;
189 else if(strcmp(p, "none") == 0)
190 ret |= AUTH_PLAIN|AUTH_FTP;
191 else
192 warnx("bad value for -a: `%s'", p);
194 return ret;
198 * Print usage and die.
201 static int interactive_flag;
202 static char *guest_umask_string;
203 static char *port_string;
204 static char *umask_string;
205 static char *auth_string;
207 int use_builtin_ls = -1;
209 static int help_flag;
210 static int version_flag;
212 static const char *good_chars = "+-=_,.";
214 struct getargs args[] = {
215 { NULL, 'a', arg_string, &auth_string, "required authentication" },
216 { NULL, 'i', arg_flag, &interactive_flag, "don't assume stdin is a socket" },
217 { NULL, 'p', arg_string, &port_string, "what port to listen to" },
218 { NULL, 'g', arg_string, &guest_umask_string, "umask for guest logins" },
219 { NULL, 'l', arg_counter, &logging, "log more stuff", "" },
220 { NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" },
221 { NULL, 'T', arg_integer, &maxtimeout, "max timeout" },
222 { NULL, 'u', arg_string, &umask_string, "umask for user logins" },
223 { NULL, 'U', arg_negative_flag, &restricted_data_ports, "don't use high data ports" },
224 { NULL, 'd', arg_flag, &debug, "enable debugging" },
225 { NULL, 'v', arg_flag, &debug, "enable debugging" },
226 { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" },
227 { "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" },
228 { "insecure-oob", 'I', arg_negative_flag, &allow_insecure_oob, "don't allow insecure OOB ABOR/STAT" },
229 #ifdef KRB5
230 { "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL},
231 #endif
232 { "version", 0, arg_flag, &version_flag },
233 { "help", 'h', arg_flag, &help_flag }
236 static int num_args = sizeof(args) / sizeof(args[0]);
238 static void
239 usage (int code)
241 arg_printusage(args, num_args, NULL, "");
242 exit (code);
245 /* output contents of a file */
246 static int
247 show_file(const char *file, int code)
249 FILE *f;
250 char buf[128];
252 f = fopen(file, "r");
253 if(f == NULL)
254 return -1;
255 while(fgets(buf, sizeof(buf), f)){
256 buf[strcspn(buf, "\r\n")] = '\0';
257 lreply(code, "%s", buf);
259 fclose(f);
260 return 0;
264 main(int argc, char **argv)
266 socklen_t his_addr_len, ctrl_addr_len;
267 int on = 1;
268 int port;
269 struct servent *sp;
271 int optind = 0;
273 setprogname (argv[0]);
275 if(getarg(args, num_args, argc, argv, &optind))
276 usage(1);
278 if(help_flag)
279 usage(0);
281 if(version_flag) {
282 print_version(NULL);
283 exit(0);
286 if(auth_string)
287 auth_level = parse_auth_level(auth_string);
289 char *p;
290 long val = 0;
292 if(guest_umask_string) {
293 val = strtol(guest_umask_string, &p, 8);
294 if (*p != '\0' || val < 0)
295 warnx("bad value for -g");
296 else
297 guest_umask = val;
299 if(umask_string) {
300 val = strtol(umask_string, &p, 8);
301 if (*p != '\0' || val < 0)
302 warnx("bad value for -u");
303 else
304 defumask = val;
307 sp = getservbyname("ftp", "tcp");
308 if(sp)
309 port = sp->s_port;
310 else
311 port = htons(21);
312 if(port_string) {
313 sp = getservbyname(port_string, "tcp");
314 if(sp)
315 port = sp->s_port;
316 else
317 if(isdigit((unsigned char)port_string[0]))
318 port = htons(atoi(port_string));
319 else
320 warnx("bad value for -p");
323 if (maxtimeout < ftpd_timeout)
324 maxtimeout = ftpd_timeout;
326 #if 0
327 if (ftpd_timeout > maxtimeout)
328 ftpd_timeout = maxtimeout;
329 #endif
331 if(interactive_flag)
332 mini_inetd(port, NULL);
335 * LOG_NDELAY sets up the logging connection immediately,
336 * necessary for anonymous ftp's that chroot and can't do it later.
338 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
339 his_addr_len = sizeof(his_addr_ss);
340 if (getpeername(STDIN_FILENO, his_addr, &his_addr_len) < 0) {
341 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
342 exit(1);
344 ctrl_addr_len = sizeof(ctrl_addr_ss);
345 if (getsockname(STDIN_FILENO, ctrl_addr, &ctrl_addr_len) < 0) {
346 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
347 exit(1);
349 #if defined(IP_TOS)
350 if (ctrl_addr->sa_family == AF_INET)
351 socket_set_tos(STDIN_FILENO, IP_TOS);
352 #endif
353 data_source->sa_family = ctrl_addr->sa_family;
354 socket_set_port (data_source,
355 htons(ntohs(socket_get_port(ctrl_addr)) - 1));
357 /* set this here so it can be put in wtmp */
358 snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
361 /* freopen(_PATH_DEVNULL, "w", stderr); */
362 signal(SIGPIPE, lostconn);
363 signal(SIGCHLD, SIG_IGN);
364 #ifdef SIGURG
365 if (signal(SIGURG, myoob) == SIG_ERR)
366 syslog(LOG_ERR, "signal: %m");
367 #endif
369 /* Try to handle urgent data inline */
370 #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
371 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on,
372 sizeof(on)) < 0)
373 syslog(LOG_ERR, "setsockopt: %m");
374 #endif
376 #ifdef F_SETOWN
377 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
378 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
379 #endif
380 dolog(his_addr, his_addr_len);
382 * Set up default state
384 data = -1;
385 type = TYPE_A;
386 form = FORM_N;
387 stru = STRU_F;
388 mode = MODE_S;
389 tmpline[0] = '\0';
391 /* If logins are disabled, print out the message. */
392 if(show_file(_PATH_NOLOGIN, 530) == 0) {
393 reply(530, "System not available.");
394 exit(0);
396 show_file(_PATH_FTPWELCOME, 220);
397 /* reply(220,) must follow */
398 gethostname(hostname, sizeof(hostname));
400 reply(220, "%s FTP server (%s"
401 #ifdef KRB5
402 "+%s"
403 #endif
404 ") ready.", hostname, version
405 #ifdef KRB5
406 ,heimdal_version
407 #endif
410 for (;;)
411 yyparse();
412 /* NOTREACHED */
415 static RETSIGTYPE
416 lostconn(int signo)
419 if (debug)
420 syslog(LOG_DEBUG, "lost connection");
421 dologout(-1);
425 * Helper function for sgetpwnam().
427 static char *
428 sgetsave(char *s)
430 char *new = strdup(s);
432 if (new == NULL) {
433 perror_reply(421, "Local resource failure: malloc");
434 dologout(1);
435 /* NOTREACHED */
437 return new;
441 * Save the result of a getpwnam. Used for USER command, since
442 * the data returned must not be clobbered by any other command
443 * (e.g., globbing).
445 static struct passwd *
446 sgetpwnam(char *name)
448 static struct passwd save;
449 struct passwd *p;
451 if ((p = k_getpwnam(name)) == NULL)
452 return (p);
453 if (save.pw_name) {
454 free(save.pw_name);
455 free(save.pw_passwd);
456 free(save.pw_gecos);
457 free(save.pw_dir);
458 free(save.pw_shell);
460 save = *p;
461 save.pw_name = sgetsave(p->pw_name);
462 save.pw_passwd = sgetsave(p->pw_passwd);
463 save.pw_gecos = sgetsave(p->pw_gecos);
464 save.pw_dir = sgetsave(p->pw_dir);
465 save.pw_shell = sgetsave(p->pw_shell);
466 return (&save);
469 static int login_attempts; /* number of failed login attempts */
470 static int askpasswd; /* had user command, ask for passwd */
471 static char curname[10]; /* current USER name */
472 #ifdef OTP
473 OtpContext otp_ctx;
474 #endif
477 * USER command.
478 * Sets global passwd pointer pw if named account exists and is acceptable;
479 * sets askpasswd if a PASS command is expected. If logged in previously,
480 * need to reset state. If name is "ftp" or "anonymous", the name is not in
481 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
482 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
483 * requesting login privileges. Disallow anyone who does not have a standard
484 * shell as returned by getusershell(). Disallow anyone mentioned in the file
485 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
487 void
488 user(char *name)
490 char *cp, *shell;
492 if(auth_level == 0 && !sec_complete){
493 reply(530, "No login allowed without authorization.");
494 return;
497 if (logged_in) {
498 if (guest) {
499 reply(530, "Can't change user from guest login.");
500 return;
501 } else if (dochroot) {
502 reply(530, "Can't change user from chroot user.");
503 return;
505 end_login();
508 guest = 0;
509 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
510 if ((auth_level & AUTH_FTP) == 0 ||
511 checkaccess("ftp") ||
512 checkaccess("anonymous"))
513 reply(530, "User %s access denied.", name);
514 else if ((pw = sgetpwnam("ftp")) != NULL) {
515 guest = 1;
516 defumask = guest_umask; /* paranoia for incoming */
517 askpasswd = 1;
518 reply(331, "Guest login ok, type your name as password.");
519 } else
520 reply(530, "User %s unknown.", name);
521 if (!askpasswd && logging) {
522 char data_addr[256];
524 if (inet_ntop (his_addr->sa_family,
525 socket_get_address(his_addr),
526 data_addr, sizeof(data_addr)) == NULL)
527 strlcpy (data_addr, "unknown address",
528 sizeof(data_addr));
530 syslog(LOG_NOTICE,
531 "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
532 remotehost, data_addr);
534 return;
536 if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
537 reply(530, "Only authorized and anonymous login allowed.");
538 return;
540 if ((pw = sgetpwnam(name))) {
541 if ((shell = pw->pw_shell) == NULL || *shell == 0)
542 shell = _PATH_BSHELL;
543 while ((cp = getusershell()) != NULL)
544 if (strcmp(cp, shell) == 0)
545 break;
546 endusershell();
548 if (cp == NULL || checkaccess(name)) {
549 reply(530, "User %s access denied.", name);
550 if (logging) {
551 char data_addr[256];
553 if (inet_ntop (his_addr->sa_family,
554 socket_get_address(his_addr),
555 data_addr,
556 sizeof(data_addr)) == NULL)
557 strlcpy (data_addr,
558 "unknown address",
559 sizeof(data_addr));
561 syslog(LOG_NOTICE,
562 "FTP LOGIN REFUSED FROM %s(%s), %s",
563 remotehost,
564 data_addr,
565 name);
567 pw = (struct passwd *) NULL;
568 return;
571 if (logging)
572 strlcpy(curname, name, sizeof(curname));
573 if(sec_complete) {
574 if(sec_userok(name) == 0) {
575 do_login(232, name);
576 sec_session(name);
577 } else
578 reply(530, "User %s access denied.", name);
579 } else {
580 #ifdef OTP
581 char ss[256];
583 if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) {
584 reply(331, "Password %s for %s required.",
585 ss, name);
586 askpasswd = 1;
587 } else
588 #endif
589 if ((auth_level & AUTH_OTP) == 0) {
590 reply(331, "Password required for %s.", name);
591 askpasswd = 1;
592 } else {
593 #ifdef OTP
594 char *s;
596 if ((s = otp_error (&otp_ctx)) != NULL)
597 lreply(530, "OTP: %s", s);
598 #endif
599 reply(530,
600 "Only authorized, anonymous"
601 #ifdef OTP
602 " and OTP "
603 #endif
604 "login allowed.");
609 * Delay before reading passwd after first failed
610 * attempt to slow down passwd-guessing programs.
612 if (login_attempts)
613 sleep(login_attempts);
617 * Check if a user is in the file "fname"
619 static int
620 checkuser(char *fname, char *name)
622 FILE *fd;
623 int found = 0;
624 char *p, line[BUFSIZ];
626 if ((fd = fopen(fname, "r")) != NULL) {
627 while (fgets(line, sizeof(line), fd) != NULL)
628 if ((p = strchr(line, '\n')) != NULL) {
629 *p = '\0';
630 if (line[0] == '#')
631 continue;
632 if (strcmp(line, name) == 0) {
633 found = 1;
634 break;
637 fclose(fd);
639 return (found);
644 * Determine whether a user has access, based on information in
645 * _PATH_FTPUSERS. The users are listed one per line, with `allow'
646 * or `deny' after the username. If anything other than `allow', or
647 * just nothing, is given after the username, `deny' is assumed.
649 * If the user is not found in the file, but the pseudo-user `*' is,
650 * the permission is taken from that line.
652 * This preserves the old semantics where if a user was listed in the
653 * file he was denied, otherwise he was allowed.
655 * Return 1 if the user is denied, or 0 if he is allowed. */
657 static int
658 match(const char *pattern, const char *string)
660 return fnmatch(pattern, string, FNM_NOESCAPE);
663 static int
664 checkaccess(char *name)
666 #define ALLOWED 0
667 #define NOT_ALLOWED 1
668 FILE *fd;
669 int allowed = ALLOWED;
670 char *user, *perm, line[BUFSIZ];
671 char *foo;
673 fd = fopen(_PATH_FTPUSERS, "r");
675 if(fd == NULL)
676 return allowed;
678 while (fgets(line, sizeof(line), fd) != NULL) {
679 foo = NULL;
680 user = strtok_r(line, " \t\n", &foo);
681 if (user == NULL || user[0] == '#')
682 continue;
683 perm = strtok_r(NULL, " \t\n", &foo);
684 if (match(user, name) == 0){
685 if(perm && strcmp(perm, "allow") == 0)
686 allowed = ALLOWED;
687 else
688 allowed = NOT_ALLOWED;
689 break;
692 fclose(fd);
693 return allowed;
695 #undef ALLOWED
696 #undef NOT_ALLOWED
699 int do_login(int code, char *passwd)
701 login_attempts = 0; /* this time successful */
702 if (setegid((gid_t)pw->pw_gid) < 0) {
703 reply(550, "Can't set gid.");
704 return -1;
706 initgroups(pw->pw_name, pw->pw_gid);
707 #if defined(KRB5)
708 if(k_hasafs())
709 k_setpag();
710 #endif
712 /* open wtmp before chroot */
713 ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
714 logged_in = 1;
716 dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
717 if (guest) {
719 * We MUST do a chdir() after the chroot. Otherwise
720 * the old current directory will be accessible as "."
721 * outside the new root!
723 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
724 reply(550, "Can't set guest privileges.");
725 return -1;
727 } else if (dochroot) {
728 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
729 reply(550, "Can't change root.");
730 return -1;
732 } else if (chdir(pw->pw_dir) < 0) {
733 if (chdir("/") < 0) {
734 reply(530, "User %s: can't change directory to %s.",
735 pw->pw_name, pw->pw_dir);
736 return -1;
737 } else
738 lreply(code, "No directory! Logging in with home=/");
740 if (seteuid((uid_t)pw->pw_uid) < 0) {
741 reply(550, "Can't set uid.");
742 return -1;
745 if(use_builtin_ls == -1) {
746 struct stat st;
747 /* if /bin/ls exist and is a regular file, use it, otherwise
748 use built-in ls */
749 if(stat("/bin/ls", &st) == 0 &&
750 S_ISREG(st.st_mode))
751 use_builtin_ls = 0;
752 else
753 use_builtin_ls = 1;
757 * Display a login message, if it exists.
758 * N.B. reply(code,) must follow the message.
760 show_file(_PATH_FTPLOGINMESG, code);
761 if(show_file(_PATH_ISSUE_NET, code) != 0)
762 show_file(_PATH_ISSUE, code);
763 if (guest) {
764 reply(code, "Guest login ok, access restrictions apply.");
765 #ifdef HAVE_SETPROCTITLE
766 snprintf (proctitle, sizeof(proctitle),
767 "%s: anonymous/%s",
768 remotehost,
769 passwd);
770 setproctitle("%s", proctitle);
771 #endif /* HAVE_SETPROCTITLE */
772 if (logging) {
773 char data_addr[256];
775 if (inet_ntop (his_addr->sa_family,
776 socket_get_address(his_addr),
777 data_addr, sizeof(data_addr)) == NULL)
778 strlcpy (data_addr, "unknown address",
779 sizeof(data_addr));
781 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
782 remotehost,
783 data_addr,
784 passwd);
786 } else {
787 reply(code, "User %s logged in.", pw->pw_name);
788 #ifdef HAVE_SETPROCTITLE
789 snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
790 setproctitle("%s", proctitle);
791 #endif /* HAVE_SETPROCTITLE */
792 if (logging) {
793 char data_addr[256];
795 if (inet_ntop (his_addr->sa_family,
796 socket_get_address(his_addr),
797 data_addr, sizeof(data_addr)) == NULL)
798 strlcpy (data_addr, "unknown address",
799 sizeof(data_addr));
801 syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
802 remotehost,
803 data_addr,
804 pw->pw_name);
807 umask(defumask);
808 return 0;
812 * Terminate login as previous user, if any, resetting state;
813 * used when USER command is given or login fails.
815 static void
816 end_login(void)
819 if (seteuid((uid_t)0) < 0)
820 fatal("Failed to seteuid");
821 if (logged_in)
822 ftpd_logwtmp(ttyline, "", "");
823 pw = NULL;
824 logged_in = 0;
825 guest = 0;
826 dochroot = 0;
829 #ifdef KRB5
830 static int
831 krb5_verify(struct passwd *pwd, char *passwd)
833 krb5_context context;
834 krb5_ccache id;
835 krb5_principal princ;
836 krb5_error_code ret;
838 ret = krb5_init_context(&context);
839 if(ret)
840 return ret;
842 ret = krb5_parse_name(context, pwd->pw_name, &princ);
843 if(ret){
844 krb5_free_context(context);
845 return ret;
847 ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
848 if(ret){
849 krb5_free_principal(context, princ);
850 krb5_free_context(context);
851 return ret;
853 ret = krb5_verify_user(context,
854 princ,
856 passwd,
858 NULL);
859 krb5_free_principal(context, princ);
860 if (k_hasafs()) {
861 krb5_afslog_uid_home(context, id,NULL, NULL,pwd->pw_uid, pwd->pw_dir);
863 krb5_cc_destroy(context, id);
864 krb5_free_context (context);
865 if(ret)
866 return ret;
867 return 0;
869 #endif /* KRB5 */
871 void
872 pass(char *passwd)
874 int rval;
876 /* some clients insists on sending a password */
877 if (logged_in && askpasswd == 0){
878 reply(230, "Password not necessary");
879 return;
882 if (logged_in || askpasswd == 0) {
883 reply(503, "Login with USER first.");
884 return;
886 askpasswd = 0;
887 rval = 1;
888 if (!guest) { /* "ftp" is only account allowed no password */
889 if (pw == NULL)
890 rval = 1; /* failure below */
891 #ifdef OTP
892 else if (otp_verify_user (&otp_ctx, passwd) == 0) {
893 rval = 0;
895 #endif
896 else if((auth_level & AUTH_OTP) == 0) {
897 #ifdef KRB5
898 rval = krb5_verify(pw, passwd);
899 #endif
900 if (rval)
901 rval = unix_verify_user(pw->pw_name, passwd);
902 } else {
903 #ifdef OTP
904 char *s;
905 if ((s = otp_error(&otp_ctx)) != NULL)
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 char data_addr[256];
919 if (inet_ntop (his_addr->sa_family,
920 socket_get_address(his_addr),
921 data_addr, sizeof(data_addr)) == NULL)
922 strlcpy (data_addr, "unknown address",
923 sizeof(data_addr));
925 reply(530, "Login incorrect.");
926 if (logging)
927 syslog(LOG_NOTICE,
928 "FTP LOGIN FAILED FROM %s(%s), %s",
929 remotehost,
930 data_addr,
931 curname);
932 pw = NULL;
933 if (login_attempts++ >= 5) {
934 syslog(LOG_NOTICE,
935 "repeated login failures from %s(%s)",
936 remotehost,
937 data_addr);
938 exit(0);
940 return;
943 if(!do_login(230, passwd))
944 return;
946 /* Forget all about it... */
947 end_login();
950 void
951 retrieve(const char *cmd, char *name)
953 FILE *fin = NULL, *dout;
954 struct stat st;
955 int (*closefunc) (FILE *);
956 char line[BUFSIZ];
959 if (cmd == 0) {
960 fin = fopen(name, "r");
961 closefunc = fclose;
962 st.st_size = 0;
963 if(fin == NULL){
964 int save_errno = errno;
965 struct cmds {
966 const char *ext;
967 const char *cmd;
968 const char *rev_cmd;
969 } cmds[] = {
970 {".tar", "/bin/gtar cPf - %s", NULL},
971 {".tar.gz", "/bin/gtar zcPf - %s", NULL},
972 {".tar.Z", "/bin/gtar ZcPf - %s", NULL},
973 {".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"},
974 {".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"},
975 {NULL, NULL}
977 struct cmds *p;
978 for(p = cmds; p->ext; p++){
979 char *tail = name + strlen(name) - strlen(p->ext);
980 char c = *tail;
982 if(strcmp(tail, p->ext) == 0 &&
983 (*tail = 0) == 0 &&
984 access(name, R_OK) == 0){
985 snprintf (line, sizeof(line), p->cmd, name);
986 *tail = c;
987 break;
989 *tail = c;
990 if (p->rev_cmd != NULL) {
991 char *ext;
992 int ret;
994 ret = asprintf(&ext, "%s%s", name, p->ext);
995 if (ret != -1) {
996 if (access(ext, R_OK) == 0) {
997 snprintf (line, sizeof(line),
998 p->rev_cmd, ext);
999 free(ext);
1000 break;
1002 free(ext);
1007 if(p->ext){
1008 fin = ftpd_popen(line, "r", 0, 0);
1009 closefunc = ftpd_pclose;
1010 st.st_size = -1;
1011 cmd = line;
1012 } else
1013 errno = save_errno;
1015 } else {
1016 snprintf(line, sizeof(line), cmd, name);
1017 name = line;
1018 fin = ftpd_popen(line, "r", 1, 0);
1019 closefunc = ftpd_pclose;
1020 st.st_size = -1;
1022 if (fin == NULL) {
1023 if (errno != 0) {
1024 perror_reply(550, name);
1025 if (cmd == 0) {
1026 LOGCMD("get", name);
1029 return;
1031 byte_count = -1;
1032 if (cmd == 0){
1033 if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
1034 reply(550, "%s: not a plain file.", name);
1035 goto done;
1038 if (restart_point) {
1039 if (type == TYPE_A) {
1040 off_t i, n;
1041 int c;
1043 n = restart_point;
1044 i = 0;
1045 while (i++ < n) {
1046 if ((c=getc(fin)) == EOF) {
1047 perror_reply(550, name);
1048 goto done;
1050 if (c == '\n')
1051 i++;
1053 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1054 perror_reply(550, name);
1055 goto done;
1058 dout = dataconn(name, st.st_size, "w");
1059 if (dout == NULL)
1060 goto done;
1061 set_buffer_size(fileno(dout), 0);
1062 send_data(fin, dout);
1063 fclose(dout);
1064 data = -1;
1065 pdata = -1;
1066 done:
1067 if (cmd == 0)
1068 LOGBYTES("get", name, byte_count);
1069 (*closefunc)(fin);
1072 /* filename sanity check */
1075 filename_check(char *filename)
1077 char *p;
1079 p = strrchr(filename, '/');
1080 if(p)
1081 filename = p + 1;
1083 p = filename;
1085 if(isalnum((unsigned char)*p)){
1086 p++;
1087 while(*p && (isalnum((unsigned char)*p) || strchr(good_chars, (unsigned char)*p)))
1088 p++;
1089 if(*p == '\0')
1090 return 0;
1092 lreply(553, "\"%s\" is not an acceptable filename.", filename);
1093 lreply(553, "The filename must start with an alphanumeric "
1094 "character and must only");
1095 reply(553, "consist of alphanumeric characters or any of the following: %s",
1096 good_chars);
1097 return 1;
1100 void
1101 do_store(char *name, char *mode, int unique)
1103 FILE *fout, *din;
1104 struct stat st;
1105 int (*closefunc) (FILE *);
1107 if(guest && filename_check(name))
1108 return;
1109 if (unique) {
1110 char *uname;
1111 if (stat(name, &st) == 0) {
1112 if ((uname = gunique(name)) == NULL)
1113 return;
1114 name = uname;
1116 LOGCMD(*mode == 'w' ? "put" : "append", name);
1119 if (restart_point)
1120 mode = "r+";
1121 fout = fopen(name, mode);
1122 closefunc = fclose;
1123 if (fout == NULL) {
1124 perror_reply(553, name);
1125 LOGCMD(*mode == 'w' ? "put" : "append", name);
1126 return;
1128 byte_count = -1;
1129 if (restart_point) {
1130 if (type == TYPE_A) {
1131 off_t i, n;
1132 int c;
1134 n = restart_point;
1135 i = 0;
1136 while (i++ < n) {
1137 if ((c=getc(fout)) == EOF) {
1138 perror_reply(550, name);
1139 goto done;
1141 if (c == '\n')
1142 i++;
1145 * We must do this seek to "current" position
1146 * because we are changing from reading to
1147 * writing.
1149 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1150 perror_reply(550, name);
1151 goto done;
1153 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1154 perror_reply(550, name);
1155 goto done;
1158 din = dataconn(name, (off_t)-1, "r");
1159 if (din == NULL)
1160 goto done;
1161 set_buffer_size(fileno(din), 1);
1162 if (receive_data(din, fout) == 0) {
1163 if((*closefunc)(fout) < 0)
1164 perror_reply(552, name);
1165 else {
1166 if (unique)
1167 reply(226, "Transfer complete (unique file name:%s).",
1168 name);
1169 else
1170 reply(226, "Transfer complete.");
1172 } else
1173 (*closefunc)(fout);
1174 fclose(din);
1175 data = -1;
1176 pdata = -1;
1177 done:
1178 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1181 static FILE *
1182 getdatasock(const char *mode, int domain)
1184 int s, t, tries;
1186 if (data >= 0)
1187 return (fdopen(data, mode));
1188 if (seteuid(0) < 0)
1189 fatal("Failed to seteuid");
1190 s = socket(domain, SOCK_STREAM, 0);
1191 if (s < 0)
1192 goto bad;
1193 socket_set_reuseaddr (s, 1);
1194 /* anchor socket to avoid multi-homing problems */
1195 socket_set_address_and_port (data_source,
1196 socket_get_address (ctrl_addr),
1197 socket_get_port (data_source));
1199 for (tries = 1; ; tries++) {
1200 if (bind(s, data_source,
1201 socket_sockaddr_size (data_source)) >= 0)
1202 break;
1203 if (errno != EADDRINUSE || tries > 10)
1204 goto bad;
1205 sleep(tries);
1207 if (seteuid(pw->pw_uid) < 0)
1208 fatal("Failed to seteuid");
1209 #ifdef IPTOS_THROUGHPUT
1210 socket_set_tos (s, IPTOS_THROUGHPUT);
1211 #endif
1212 return (fdopen(s, mode));
1213 bad:
1214 /* Return the real value of errno (close may change it) */
1215 t = errno;
1216 if (seteuid((uid_t)pw->pw_uid) < 0)
1217 fatal("Failed to seteuid");
1218 close(s);
1219 errno = t;
1220 return (NULL);
1223 static int
1224 accept_with_timeout(int socket,
1225 struct sockaddr *address,
1226 socklen_t *address_len,
1227 struct timeval *timeout)
1229 int ret;
1230 fd_set rfd;
1231 FD_ZERO(&rfd);
1232 FD_SET(socket, &rfd);
1233 ret = select(socket + 1, &rfd, NULL, NULL, timeout);
1234 if(ret < 0)
1235 return ret;
1236 if(ret == 0) {
1237 errno = ETIMEDOUT;
1238 return -1;
1240 return accept(socket, address, address_len);
1243 static FILE *
1244 dataconn(const char *name, off_t size, const char *mode)
1246 char sizebuf[32];
1247 FILE *file;
1248 int domain, retry = 0;
1250 file_size = size;
1251 byte_count = 0;
1252 if (size >= 0)
1253 snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", (long)size);
1254 else
1255 *sizebuf = '\0';
1256 if (pdata >= 0) {
1257 struct sockaddr_storage from_ss;
1258 struct sockaddr *from = (struct sockaddr *)&from_ss;
1259 struct timeval timeout;
1260 int s;
1261 socklen_t fromlen = sizeof(from_ss);
1263 timeout.tv_sec = 15;
1264 timeout.tv_usec = 0;
1265 s = accept_with_timeout(pdata, from, &fromlen, &timeout);
1266 if (s < 0) {
1267 reply(425, "Can't open data connection.");
1268 close(pdata);
1269 pdata = -1;
1270 return (NULL);
1272 close(pdata);
1273 pdata = s;
1274 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
1275 if (from->sa_family == AF_INET)
1276 socket_set_tos(s, IPTOS_THROUGHPUT);
1277 #endif
1278 reply(150, "Opening %s mode data connection for '%s'%s.",
1279 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1280 return (fdopen(pdata, mode));
1282 if (data >= 0) {
1283 reply(125, "Using existing data connection for '%s'%s.",
1284 name, sizebuf);
1285 usedefault = 1;
1286 return (fdopen(data, mode));
1288 if (usedefault)
1289 data_dest = his_addr;
1290 usedefault = 1;
1292 * Default to using the same socket type as the ctrl address,
1293 * unless we know the type of the data address.
1295 domain = data_dest->sa_family;
1296 if (domain == PF_UNSPEC)
1297 domain = ctrl_addr->sa_family;
1299 file = getdatasock(mode, domain);
1300 if (file == NULL) {
1301 char data_addr[256];
1303 if (inet_ntop (data_source->sa_family,
1304 socket_get_address(data_source),
1305 data_addr, sizeof(data_addr)) == NULL)
1306 strlcpy (data_addr, "unknown address",
1307 sizeof(data_addr));
1309 reply(425, "Can't create data socket (%s,%d): %s.",
1310 data_addr,
1311 socket_get_port (data_source),
1312 strerror(errno));
1313 return (NULL);
1315 data = fileno(file);
1316 while (connect(data, data_dest,
1317 socket_sockaddr_size(data_dest)) < 0) {
1318 if (errno == EADDRINUSE && retry < swaitmax) {
1319 sleep(swaitint);
1320 retry += swaitint;
1321 continue;
1323 perror_reply(425, "Can't build data connection");
1324 fclose(file);
1325 data = -1;
1326 return (NULL);
1328 reply(150, "Opening %s mode data connection for '%s'%s.",
1329 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1330 return (file);
1334 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1335 * encapsulation of the data subject * to Mode, Structure, and Type.
1337 * NB: Form isn't handled.
1339 static void
1340 send_data(FILE *instr, FILE *outstr)
1342 int c, cnt, filefd, netfd;
1343 static char *buf;
1344 static size_t bufsize;
1346 transflag = 1;
1347 switch (type) {
1349 case TYPE_A:
1350 while ((c = getc(instr)) != EOF) {
1351 if (urgflag && handleoobcmd())
1352 return;
1353 byte_count++;
1354 if(c == '\n')
1355 sec_putc('\r', outstr);
1356 sec_putc(c, outstr);
1358 sec_fflush(outstr);
1359 transflag = 0;
1360 urgflag = 0;
1361 if (ferror(instr))
1362 goto file_err;
1363 if (ferror(outstr))
1364 goto data_err;
1365 reply(226, "Transfer complete.");
1366 return;
1368 case TYPE_I:
1369 case TYPE_L:
1370 #if 0 /* XXX handle urg flag */
1371 #if defined(HAVE_MMAP) && !defined(NO_MMAP)
1372 #ifndef MAP_FAILED
1373 #define MAP_FAILED (-1)
1374 #endif
1376 struct stat st;
1377 char *chunk;
1378 int in = fileno(instr);
1379 if(fstat(in, &st) == 0 && S_ISREG(st.st_mode)
1380 && st.st_size > 0) {
1382 * mmap zero bytes has potential of loosing, don't do it.
1384 chunk = mmap(0, st.st_size, PROT_READ,
1385 MAP_SHARED, in, 0);
1386 if((void *)chunk != (void *)MAP_FAILED) {
1387 cnt = st.st_size - restart_point;
1388 sec_write(fileno(outstr), chunk + restart_point, cnt);
1389 if (munmap(chunk, st.st_size) < 0)
1390 warn ("munmap");
1391 sec_fflush(outstr);
1392 byte_count = cnt;
1393 transflag = 0;
1394 urgflag = 0;
1398 #endif
1399 #endif
1400 if(transflag) {
1401 struct stat st;
1403 netfd = fileno(outstr);
1404 filefd = fileno(instr);
1405 buf = alloc_buffer (buf, &bufsize,
1406 fstat(filefd, &st) >= 0 ? &st : NULL);
1407 if (buf == NULL) {
1408 transflag = 0;
1409 urgflag = 0;
1410 perror_reply(451, "Local resource failure: malloc");
1411 return;
1413 while ((cnt = read(filefd, buf, bufsize)) > 0 &&
1414 sec_write(netfd, buf, cnt) == cnt) {
1415 byte_count += cnt;
1416 if (urgflag && handleoobcmd())
1417 return;
1419 sec_fflush(outstr); /* to end an encrypted stream */
1420 transflag = 0;
1421 urgflag = 0;
1422 if (cnt != 0) {
1423 if (cnt < 0)
1424 goto file_err;
1425 goto data_err;
1428 reply(226, "Transfer complete.");
1429 return;
1430 default:
1431 transflag = 0;
1432 urgflag = 0;
1433 reply(550, "Unimplemented TYPE %d in send_data", type);
1434 return;
1437 data_err:
1438 transflag = 0;
1439 urgflag = 0;
1440 perror_reply(426, "Data connection");
1441 return;
1443 file_err:
1444 transflag = 0;
1445 urgflag = 0;
1446 perror_reply(551, "Error on input file");
1450 * Transfer data from peer to "outstr" using the appropriate encapulation of
1451 * the data subject to Mode, Structure, and Type.
1453 * N.B.: Form isn't handled.
1455 static int
1456 receive_data(FILE *instr, FILE *outstr)
1458 int cnt, bare_lfs = 0;
1459 static char *buf;
1460 static size_t bufsize;
1461 struct stat st;
1463 transflag = 1;
1465 buf = alloc_buffer (buf, &bufsize,
1466 fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
1467 if (buf == NULL) {
1468 transflag = 0;
1469 urgflag = 0;
1470 perror_reply(451, "Local resource failure: malloc");
1471 return -1;
1474 switch (type) {
1476 case TYPE_I:
1477 case TYPE_L:
1478 while ((cnt = sec_read(fileno(instr), buf, bufsize)) > 0) {
1479 if (write(fileno(outstr), buf, cnt) != cnt)
1480 goto file_err;
1481 byte_count += cnt;
1482 if (urgflag && handleoobcmd())
1483 return (-1);
1485 if (cnt < 0)
1486 goto data_err;
1487 transflag = 0;
1488 urgflag = 0;
1489 return (0);
1491 case TYPE_E:
1492 reply(553, "TYPE E not implemented.");
1493 transflag = 0;
1494 urgflag = 0;
1495 return (-1);
1497 case TYPE_A:
1499 char *p, *q;
1500 int cr_flag = 0;
1501 while ((cnt = sec_read(fileno(instr),
1502 buf + cr_flag,
1503 bufsize - cr_flag)) > 0){
1504 if (urgflag && handleoobcmd())
1505 return (-1);
1506 byte_count += cnt;
1507 cnt += cr_flag;
1508 cr_flag = 0;
1509 for(p = buf, q = buf; p < buf + cnt;) {
1510 if(*p == '\n')
1511 bare_lfs++;
1512 if(*p == '\r') {
1513 if(p == buf + cnt - 1){
1514 cr_flag = 1;
1515 p++;
1516 continue;
1517 }else if(p[1] == '\n'){
1518 *q++ = '\n';
1519 p += 2;
1520 continue;
1523 *q++ = *p++;
1525 fwrite(buf, q - buf, 1, outstr);
1526 if(cr_flag)
1527 buf[0] = '\r';
1529 if(cr_flag)
1530 putc('\r', outstr);
1531 fflush(outstr);
1532 if (ferror(instr))
1533 goto data_err;
1534 if (ferror(outstr))
1535 goto file_err;
1536 transflag = 0;
1537 urgflag = 0;
1538 if (bare_lfs) {
1539 lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
1540 " File may not have transferred correctly.\r\n",
1541 bare_lfs);
1543 return (0);
1545 default:
1546 reply(550, "Unimplemented TYPE %d in receive_data", type);
1547 transflag = 0;
1548 urgflag = 0;
1549 return (-1);
1552 data_err:
1553 transflag = 0;
1554 urgflag = 0;
1555 perror_reply(426, "Data Connection");
1556 return (-1);
1558 file_err:
1559 transflag = 0;
1560 urgflag = 0;
1561 perror_reply(452, "Error writing file");
1562 return (-1);
1565 void
1566 statfilecmd(char *filename)
1568 FILE *fin;
1569 int c;
1570 char line[LINE_MAX];
1572 snprintf(line, sizeof(line), "/bin/ls -la -- %s", filename);
1573 fin = ftpd_popen(line, "r", 1, 0);
1574 lreply(211, "status of %s:", filename);
1575 while ((c = getc(fin)) != EOF) {
1576 if (c == '\n') {
1577 if (ferror(stdout)){
1578 perror_reply(421, "control connection");
1579 ftpd_pclose(fin);
1580 dologout(1);
1581 /* NOTREACHED */
1583 if (ferror(fin)) {
1584 perror_reply(551, filename);
1585 ftpd_pclose(fin);
1586 return;
1588 putc('\r', stdout);
1590 putc(c, stdout);
1592 ftpd_pclose(fin);
1593 reply(211, "End of Status");
1596 void
1597 statcmd(void)
1599 #if 0
1600 struct sockaddr_in *sin;
1601 u_char *a, *p;
1603 lreply(211, "%s FTP server (%s) status:", hostname, version);
1604 printf(" %s\r\n", version);
1605 printf(" Connected to %s", remotehost);
1606 if (!isdigit((unsigned char)remotehost[0]))
1607 printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1608 printf("\r\n");
1609 if (logged_in) {
1610 if (guest)
1611 printf(" Logged in anonymously\r\n");
1612 else
1613 printf(" Logged in as %s\r\n", pw->pw_name);
1614 } else if (askpasswd)
1615 printf(" Waiting for password\r\n");
1616 else
1617 printf(" Waiting for user name\r\n");
1618 printf(" TYPE: %s", typenames[type]);
1619 if (type == TYPE_A || type == TYPE_E)
1620 printf(", FORM: %s", formnames[form]);
1621 if (type == TYPE_L)
1622 #if NBBY == 8
1623 printf(" %d", NBBY);
1624 #else
1625 printf(" %d", bytesize); /* need definition! */
1626 #endif
1627 printf("; STRUcture: %s; transfer MODE: %s\r\n",
1628 strunames[stru], modenames[mode]);
1629 if (data != -1)
1630 printf(" Data connection open\r\n");
1631 else if (pdata != -1) {
1632 printf(" in Passive mode");
1633 sin = &pasv_addr;
1634 goto printaddr;
1635 } else if (usedefault == 0) {
1636 printf(" PORT");
1637 sin = &data_dest;
1638 printaddr:
1639 a = (u_char *) &sin->sin_addr;
1640 p = (u_char *) &sin->sin_port;
1641 #define UC(b) (((int) b) & 0xff)
1642 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1643 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1644 #undef UC
1645 } else
1646 printf(" No data connection\r\n");
1647 #endif
1648 reply(211, "End of status");
1651 void
1652 fatal(char *s)
1655 reply(451, "Error in server: %s\n", s);
1656 reply(221, "Closing connection due to server error.");
1657 dologout(0);
1658 /* NOTREACHED */
1661 static void
1662 int_reply(int, char *, const char *, va_list)
1663 #ifdef __GNUC__
1664 __attribute__ ((format (printf, 3, 0)))
1665 #endif
1668 static void
1669 int_reply(int n, char *c, const char *fmt, va_list ap)
1671 char buf[10240];
1672 char *p;
1673 p=buf;
1674 if(n){
1675 snprintf(p, sizeof(buf), "%d%s", n, c);
1676 p+=strlen(p);
1678 vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap);
1679 p+=strlen(p);
1680 snprintf(p, sizeof(buf) - strlen(p), "\r\n");
1681 p+=strlen(p);
1682 sec_fprintf(stdout, "%s", buf);
1683 fflush(stdout);
1684 if (debug)
1685 syslog(LOG_DEBUG, "<--- %s- ", buf);
1688 void
1689 reply(int n, const char *fmt, ...)
1691 va_list ap;
1692 va_start(ap, fmt);
1693 int_reply(n, " ", fmt, ap);
1694 delete_ftp_command();
1695 va_end(ap);
1698 void
1699 lreply(int n, const char *fmt, ...)
1701 va_list ap;
1702 va_start(ap, fmt);
1703 int_reply(n, "-", fmt, ap);
1704 va_end(ap);
1707 void
1708 nreply(const char *fmt, ...)
1710 va_list ap;
1711 va_start(ap, fmt);
1712 int_reply(0, NULL, fmt, ap);
1713 va_end(ap);
1716 static void
1717 ack(char *s)
1720 reply(250, "%s command successful.", s);
1723 void
1724 nack(char *s)
1727 reply(502, "%s command not implemented.", s);
1730 void
1731 do_delete(char *name)
1733 struct stat st;
1735 LOGCMD("delete", name);
1736 if (stat(name, &st) < 0) {
1737 perror_reply(550, name);
1738 return;
1740 if (S_ISDIR(st.st_mode)) {
1741 if (rmdir(name) < 0) {
1742 perror_reply(550, name);
1743 return;
1745 goto done;
1747 if (unlink(name) < 0) {
1748 perror_reply(550, name);
1749 return;
1751 done:
1752 ack("DELE");
1755 void
1756 cwd(const char *path)
1759 if (chdir(path) < 0)
1760 perror_reply(550, path);
1761 else
1762 ack("CWD");
1765 void
1766 makedir(char *name)
1769 LOGCMD("mkdir", name);
1770 if(guest && filename_check(name))
1771 return;
1772 if (mkdir(name, 0777) < 0)
1773 perror_reply(550, name);
1774 else{
1775 if(guest)
1776 chmod(name, 0700); /* guest has umask 777 */
1777 reply(257, "MKD command successful.");
1781 void
1782 removedir(char *name)
1785 LOGCMD("rmdir", name);
1786 if (rmdir(name) < 0)
1787 perror_reply(550, name);
1788 else
1789 ack("RMD");
1792 void
1793 pwd(void)
1795 char path[MaxPathLen];
1796 char *ret;
1798 /* SunOS has a broken getcwd that does popen(pwd) (!!!), this
1799 * failes miserably when running chroot
1801 ret = getcwd(path, sizeof(path));
1802 if (ret == NULL)
1803 reply(550, "%s.", strerror(errno));
1804 else
1805 reply(257, "\"%s\" is current directory.", path);
1808 char *
1809 renamefrom(char *name)
1811 struct stat st;
1813 if (stat(name, &st) < 0) {
1814 perror_reply(550, name);
1815 return NULL;
1817 reply(350, "File exists, ready for destination name");
1818 return (name);
1821 void
1822 renamecmd(char *from, char *to)
1825 LOGCMD2("rename", from, to);
1826 if(guest && filename_check(to))
1827 return;
1828 if (rename(from, to) < 0)
1829 perror_reply(550, "rename");
1830 else
1831 ack("RNTO");
1834 static void
1835 dolog(struct sockaddr *sa, int len)
1837 getnameinfo_verified (sa, len, remotehost, sizeof(remotehost),
1838 NULL, 0, 0);
1839 #ifdef HAVE_SETPROCTITLE
1840 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1841 setproctitle("%s", proctitle);
1842 #endif /* HAVE_SETPROCTITLE */
1844 if (logging) {
1845 char data_addr[256];
1847 if (inet_ntop (his_addr->sa_family,
1848 socket_get_address(his_addr),
1849 data_addr, sizeof(data_addr)) == NULL)
1850 strlcpy (data_addr, "unknown address",
1851 sizeof(data_addr));
1854 syslog(LOG_INFO, "connection from %s(%s)",
1855 remotehost,
1856 data_addr);
1861 * Record logout in wtmp file
1862 * and exit with supplied status.
1864 void
1865 dologout(int status)
1867 transflag = 0;
1868 urgflag = 0;
1869 if (logged_in) {
1870 #if KRB5
1871 cond_kdestroy();
1872 #endif
1873 seteuid((uid_t)0); /* No need to check, we call exit() below */
1874 ftpd_logwtmp(ttyline, "", "");
1876 /* beware of flushing buffers after a SIGPIPE */
1877 #ifdef XXX
1878 exit(status);
1879 #else
1880 _exit(status);
1881 #endif
1884 void abor(void)
1886 if (!transflag)
1887 return;
1888 reply(426, "Transfer aborted. Data connection closed.");
1889 reply(226, "Abort successful");
1890 transflag = 0;
1893 static void
1894 myoob(int signo)
1896 urgflag = 1;
1899 static char *
1900 mec_space(char *p)
1902 while(isspace(*(unsigned char *)p))
1903 p++;
1904 return p;
1907 static int
1908 handleoobcmd(void)
1910 char *cp;
1912 /* only process if transfer occurring */
1913 if (!transflag)
1914 return 0;
1916 urgflag = 0;
1918 cp = tmpline;
1919 if (ftpd_getline(cp, sizeof(tmpline)) == NULL) {
1920 reply(221, "You could at least say goodbye.");
1921 dologout(0);
1924 if (strncasecmp("MIC", cp, 3) == 0) {
1925 mec(mec_space(cp + 3), prot_safe);
1926 } else if (strncasecmp("CONF", cp, 4) == 0) {
1927 mec(mec_space(cp + 4), prot_confidential);
1928 } else if (strncasecmp("ENC", cp, 3) == 0) {
1929 mec(mec_space(cp + 3), prot_private);
1930 } else if (!allow_insecure_oob) {
1931 reply(533, "Command protection level denied "
1932 "for paranoid reasons.");
1933 goto out;
1936 if (secure_command())
1937 cp = ftp_command;
1939 if (strcasecmp(cp, "ABOR\r\n") == 0) {
1940 abor();
1941 } else if (strcasecmp(cp, "STAT\r\n") == 0) {
1942 if (file_size != (off_t) -1)
1943 reply(213, "Status: %ld of %ld bytes transferred",
1944 (long)byte_count,
1945 (long)file_size);
1946 else
1947 reply(213, "Status: %ld bytes transferred",
1948 (long)byte_count);
1950 out:
1951 return (transflag == 0);
1955 * Note: a response of 425 is not mentioned as a possible response to
1956 * the PASV command in RFC959. However, it has been blessed as
1957 * a legitimate response by Jon Postel in a telephone conversation
1958 * with Rick Adams on 25 Jan 89.
1960 void
1961 pasv(void)
1963 socklen_t len;
1964 char *p, *a;
1965 struct sockaddr_in *sin;
1967 if (ctrl_addr->sa_family != AF_INET) {
1968 reply(425,
1969 "You cannot do PASV with something that's not IPv4");
1970 return;
1973 if(pdata != -1)
1974 close(pdata);
1976 pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
1977 if (pdata < 0) {
1978 perror_reply(425, "Can't open passive connection");
1979 return;
1981 pasv_addr->sa_family = ctrl_addr->sa_family;
1982 socket_set_address_and_port (pasv_addr,
1983 socket_get_address (ctrl_addr),
1985 socket_set_portrange(pdata, restricted_data_ports,
1986 pasv_addr->sa_family);
1987 if (seteuid(0) < 0)
1988 fatal("Failed to seteuid");
1989 if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
1990 if (seteuid(pw->pw_uid) < 0)
1991 fatal("Failed to seteuid");
1992 goto pasv_error;
1994 if (seteuid(pw->pw_uid) < 0)
1995 fatal("Failed to seteuid");
1996 len = sizeof(pasv_addr_ss);
1997 if (getsockname(pdata, pasv_addr, &len) < 0)
1998 goto pasv_error;
1999 if (listen(pdata, 1) < 0)
2000 goto pasv_error;
2001 sin = (struct sockaddr_in *)pasv_addr;
2002 a = (char *) &sin->sin_addr;
2003 p = (char *) &sin->sin_port;
2005 #define UC(b) (((int) b) & 0xff)
2007 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2008 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2009 return;
2011 pasv_error:
2012 close(pdata);
2013 pdata = -1;
2014 perror_reply(425, "Can't open passive connection");
2015 return;
2018 void
2019 epsv(char *proto)
2021 socklen_t len;
2023 pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
2024 if (pdata < 0) {
2025 perror_reply(425, "Can't open passive connection");
2026 return;
2028 pasv_addr->sa_family = ctrl_addr->sa_family;
2029 socket_set_address_and_port (pasv_addr,
2030 socket_get_address (ctrl_addr),
2032 socket_set_portrange(pdata, restricted_data_ports,
2033 pasv_addr->sa_family);
2034 if (seteuid(0) < 0)
2035 fatal("Failed to seteuid");
2036 if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
2037 if (seteuid(pw->pw_uid))
2038 fatal("Failed to seteuid");
2039 goto pasv_error;
2041 if (seteuid(pw->pw_uid) < 0)
2042 fatal("Failed to seteuid");
2043 len = sizeof(pasv_addr_ss);
2044 if (getsockname(pdata, pasv_addr, &len) < 0)
2045 goto pasv_error;
2046 if (listen(pdata, 1) < 0)
2047 goto pasv_error;
2049 reply(229, "Entering Extended Passive Mode (|||%d|)",
2050 ntohs(socket_get_port (pasv_addr)));
2051 return;
2053 pasv_error:
2054 close(pdata);
2055 pdata = -1;
2056 perror_reply(425, "Can't open passive connection");
2057 return;
2060 void
2061 eprt(char *str)
2063 char *end;
2064 char sep;
2065 int af;
2066 int ret;
2067 int port;
2069 usedefault = 0;
2070 if (pdata >= 0) {
2071 close(pdata);
2072 pdata = -1;
2075 sep = *str++;
2076 if (sep == '\0') {
2077 reply(500, "Bad syntax in EPRT");
2078 return;
2080 af = strtol (str, &end, 0);
2081 if (af == 0 || *end != sep) {
2082 reply(500, "Bad syntax in EPRT");
2083 return;
2085 str = end + 1;
2086 switch (af) {
2087 #ifdef HAVE_IPV6
2088 case 2 :
2089 data_dest->sa_family = AF_INET6;
2090 break;
2091 #endif
2092 case 1 :
2093 data_dest->sa_family = AF_INET;
2094 break;
2095 default :
2096 reply(522, "Network protocol %d not supported, use (1"
2097 #ifdef HAVE_IPV6
2098 ",2"
2099 #endif
2100 ")", af);
2101 return;
2103 end = strchr (str, sep);
2104 if (end == NULL) {
2105 reply(500, "Bad syntax in EPRT");
2106 return;
2108 *end = '\0';
2109 ret = inet_pton (data_dest->sa_family, str,
2110 socket_get_address (data_dest));
2112 if (ret != 1) {
2113 reply(500, "Bad address syntax in EPRT");
2114 return;
2116 str = end + 1;
2117 port = strtol (str, &end, 0);
2118 if (port == 0 || *end != sep) {
2119 reply(500, "Bad port syntax in EPRT");
2120 return;
2122 if (port < IPPORT_RESERVED) {
2123 reply(500, "Bad port in invalid range in EPRT");
2124 return;
2126 socket_set_port (data_dest, htons(port));
2128 if (paranoid &&
2129 (data_dest->sa_family != his_addr->sa_family ||
2130 memcmp(socket_get_address(data_dest), socket_get_address(his_addr), socket_sockaddr_size(data_dest)) != 0))
2132 reply(500, "Bad address in EPRT");
2134 reply(200, "EPRT command successful.");
2138 * Generate unique name for file with basename "local".
2139 * The file named "local" is already known to exist.
2140 * Generates failure reply on error.
2142 static char *
2143 gunique(char *local)
2145 static char new[MaxPathLen];
2146 struct stat st;
2147 int count;
2148 char *cp;
2150 cp = strrchr(local, '/');
2151 if (cp)
2152 *cp = '\0';
2153 if (stat(cp ? local : ".", &st) < 0) {
2154 perror_reply(553, cp ? local : ".");
2155 return NULL;
2157 if (cp)
2158 *cp = '/';
2159 for (count = 1; count < 100; count++) {
2160 snprintf (new, sizeof(new), "%s.%d", local, count);
2161 if (stat(new, &st) < 0)
2162 return (new);
2164 reply(452, "Unique file name cannot be created.");
2165 return (NULL);
2169 * Format and send reply containing system error number.
2171 void
2172 perror_reply(int code, const char *string)
2174 reply(code, "%s: %s.", string, strerror(errno));
2177 static char *onefile[] = {
2182 void
2183 list_file(char *file)
2185 if(use_builtin_ls) {
2186 FILE *dout;
2187 dout = dataconn(file, -1, "w");
2188 if (dout == NULL)
2189 return;
2190 set_buffer_size(fileno(dout), 0);
2191 if(builtin_ls(dout, file) == 0)
2192 reply(226, "Transfer complete.");
2193 else
2194 reply(451, "Requested action aborted. Local error in processing.");
2195 fclose(dout);
2196 data = -1;
2197 pdata = -1;
2198 } else {
2199 #ifdef HAVE_LS_A
2200 const char *cmd = "/bin/ls -lA %s";
2201 #else
2202 const char *cmd = "/bin/ls -la %s";
2203 #endif
2204 retrieve(cmd, file);
2208 void
2209 send_file_list(char *whichf)
2211 struct stat st;
2212 DIR *dirp = NULL;
2213 struct dirent *dir;
2214 FILE *dout = NULL;
2215 char **dirlist, *dirname;
2216 int simple = 0;
2217 int freeglob = 0;
2218 glob_t gl;
2219 char buf[MaxPathLen];
2221 if (strpbrk(whichf, "~{[*?") != NULL) {
2222 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
2223 #ifdef GLOB_MAXPATH
2224 GLOB_MAXPATH
2225 #else
2226 GLOB_LIMIT
2227 #endif
2230 memset(&gl, 0, sizeof(gl));
2231 freeglob = 1;
2232 if (glob(whichf, flags, 0, &gl)) {
2233 reply(550, "not found");
2234 goto out;
2235 } else if (gl.gl_pathc == 0) {
2236 errno = ENOENT;
2237 perror_reply(550, whichf);
2238 goto out;
2240 dirlist = gl.gl_pathv;
2241 } else {
2242 onefile[0] = whichf;
2243 dirlist = onefile;
2244 simple = 1;
2247 while ((dirname = *dirlist++)) {
2249 if (urgflag && handleoobcmd())
2250 goto out;
2252 if (stat(dirname, &st) < 0) {
2254 * If user typed "ls -l", etc, and the client
2255 * used NLST, do what the user meant.
2257 if (dirname[0] == '-' && *dirlist == NULL &&
2258 transflag == 0) {
2259 list_file(dirname);
2260 goto out;
2262 perror_reply(550, whichf);
2263 goto out;
2266 if (S_ISREG(st.st_mode)) {
2267 if (dout == NULL) {
2268 dout = dataconn("file list", (off_t)-1, "w");
2269 if (dout == NULL)
2270 goto out;
2271 transflag = 1;
2273 snprintf(buf, sizeof(buf), "%s%s\n", dirname,
2274 type == TYPE_A ? "\r" : "");
2275 sec_write(fileno(dout), buf, strlen(buf));
2276 byte_count += strlen(dirname) + 1;
2277 continue;
2278 } else if (!S_ISDIR(st.st_mode))
2279 continue;
2281 if ((dirp = opendir(dirname)) == NULL)
2282 continue;
2284 while ((dir = readdir(dirp)) != NULL) {
2285 char nbuf[MaxPathLen];
2287 if (urgflag && handleoobcmd())
2288 goto out;
2290 if (!strcmp(dir->d_name, "."))
2291 continue;
2292 if (!strcmp(dir->d_name, ".."))
2293 continue;
2295 snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
2298 * We have to do a stat to insure it's
2299 * not a directory or special file.
2301 if (simple || (stat(nbuf, &st) == 0 &&
2302 S_ISREG(st.st_mode))) {
2303 if (dout == NULL) {
2304 dout = dataconn("file list", (off_t)-1, "w");
2305 if (dout == NULL)
2306 goto out;
2307 transflag = 1;
2309 if(strncmp(nbuf, "./", 2) == 0)
2310 snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
2311 type == TYPE_A ? "\r" : "");
2312 else
2313 snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
2314 type == TYPE_A ? "\r" : "");
2315 sec_write(fileno(dout), buf, strlen(buf));
2316 byte_count += strlen(nbuf) + 1;
2319 closedir(dirp);
2321 if (dout == NULL)
2322 reply(550, "No files found.");
2323 else if (ferror(dout) != 0)
2324 perror_reply(550, "Data connection");
2325 else
2326 reply(226, "Transfer complete.");
2328 out:
2329 transflag = 0;
2330 if (dout != NULL){
2331 sec_write(fileno(dout), buf, 0); /* XXX flush */
2333 fclose(dout);
2335 data = -1;
2336 pdata = -1;
2337 if (freeglob)
2338 globfree(&gl);
2343 find(char *pattern)
2345 char line[1024];
2346 FILE *f;
2348 snprintf(line, sizeof(line),
2349 "/bin/locate -d %s -- %s",
2350 ftp_rooted("/etc/locatedb"),
2351 pattern);
2352 f = ftpd_popen(line, "r", 1, 1);
2353 if(f == NULL){
2354 perror_reply(550, "/bin/locate");
2355 return 1;
2357 lreply(200, "Output from find.");
2358 while(fgets(line, sizeof(line), f)){
2359 if(line[strlen(line)-1] == '\n')
2360 line[strlen(line)-1] = 0;
2361 nreply("%s", line);
2363 reply(200, "Done");
2364 ftpd_pclose(f);
2365 return 0;