This commit was manufactured by cvs2svn to create tag
[heimdal.git] / appl / ftp / ftpd / ftpd.c
blob609bb81a82f654d8579ffbc8cb2a6670b9016747
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];
95 #define AUTH_PLAIN (1 << 0) /* allow sending passwords */
96 #define AUTH_OTP (1 << 1) /* passwords are one-time */
97 #define AUTH_FTP (1 << 2) /* allow anonymous login */
99 static int auth_level = 0; /* Only allow kerberos login by default */
102 * Timeout intervals for retrying connections
103 * to hosts that don't accept PORT cmds. This
104 * is a kludge, but given the problems with TCP...
106 #define SWAITMAX 90 /* wait at most 90 seconds */
107 #define SWAITINT 5 /* interval between retries */
109 int swaitmax = SWAITMAX;
110 int swaitint = SWAITINT;
112 #ifdef HAVE_SETPROCTITLE
113 char proctitle[BUFSIZ]; /* initial part of title */
114 #endif /* HAVE_SETPROCTITLE */
116 #define LOGCMD(cmd, file) \
117 if (logging > 1) \
118 syslog(LOG_INFO,"%s %s%s", cmd, \
119 *(file) == '/' ? "" : curdir(), file);
120 #define LOGCMD2(cmd, file1, file2) \
121 if (logging > 1) \
122 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
123 *(file1) == '/' ? "" : curdir(), file1, \
124 *(file2) == '/' ? "" : curdir(), file2);
125 #define LOGBYTES(cmd, file, cnt) \
126 if (logging > 1) { \
127 if (cnt == (off_t)-1) \
128 syslog(LOG_INFO,"%s %s%s", cmd, \
129 *(file) == '/' ? "" : curdir(), file); \
130 else \
131 syslog(LOG_INFO, "%s %s%s = %ld bytes", \
132 cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \
135 static void ack (char *);
136 static void myoob (int);
137 static int handleoobcmd(void);
138 static int checkuser (char *, char *);
139 static int checkaccess (char *);
140 static FILE *dataconn (const char *, off_t, const char *);
141 static void dolog (struct sockaddr *sa, int len);
142 static void end_login (void);
143 static FILE *getdatasock (const char *);
144 static char *gunique (char *);
145 static RETSIGTYPE lostconn (int);
146 static int receive_data (FILE *, FILE *);
147 static void send_data (FILE *, FILE *);
148 static struct passwd * sgetpwnam (char *);
150 static char *
151 curdir(void)
153 static char path[MaxPathLen+1]; /* path + '/' + '\0' */
155 if (getcwd(path, sizeof(path)-1) == NULL)
156 return ("");
157 if (path[1] != '\0') /* special case for root dir. */
158 strlcat(path, "/", sizeof(path));
159 /* For guest account, skip / since it's chrooted */
160 return (guest ? path+1 : path);
163 #ifndef LINE_MAX
164 #define LINE_MAX 1024
165 #endif
167 static int
168 parse_auth_level(char *str)
170 char *p;
171 int ret = 0;
172 char *foo = NULL;
174 for(p = strtok_r(str, ",", &foo);
176 p = strtok_r(NULL, ",", &foo)) {
177 if(strcmp(p, "user") == 0)
179 #ifdef OTP
180 else if(strcmp(p, "otp") == 0)
181 ret |= AUTH_PLAIN|AUTH_OTP;
182 #endif
183 else if(strcmp(p, "ftp") == 0 ||
184 strcmp(p, "safe") == 0)
185 ret |= AUTH_FTP;
186 else if(strcmp(p, "plain") == 0)
187 ret |= AUTH_PLAIN;
188 else if(strcmp(p, "none") == 0)
189 ret |= AUTH_PLAIN|AUTH_FTP;
190 else
191 warnx("bad value for -a: `%s'", p);
193 return ret;
197 * Print usage and die.
200 static int interactive_flag;
201 static char *guest_umask_string;
202 static char *port_string;
203 static char *umask_string;
204 static char *auth_string;
206 int use_builtin_ls = -1;
208 static int help_flag;
209 static int version_flag;
211 static const char *good_chars = "+-=_,.";
213 struct getargs args[] = {
214 { NULL, 'a', arg_string, &auth_string, "required authentication" },
215 { NULL, 'i', arg_flag, &interactive_flag, "don't assume stdin is a socket" },
216 { NULL, 'p', arg_string, &port_string, "what port to listen to" },
217 { NULL, 'g', arg_string, &guest_umask_string, "umask for guest logins" },
218 { NULL, 'l', arg_counter, &logging, "log more stuff", "" },
219 { NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" },
220 { NULL, 'T', arg_integer, &maxtimeout, "max timeout" },
221 { NULL, 'u', arg_string, &umask_string, "umask for user logins" },
222 { NULL, 'U', arg_negative_flag, &restricted_data_ports, "don't use high data ports" },
223 { NULL, 'd', arg_flag, &debug, "enable debugging" },
224 { NULL, 'v', arg_flag, &debug, "enable debugging" },
225 { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" },
226 { "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" },
227 { "insecure-oob", 'I', arg_negative_flag, &allow_insecure_oob, "don't allow insecure OOB ABOR/STAT" },
228 #ifdef KRB5
229 { "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL},
230 #endif
231 { "version", 0, arg_flag, &version_flag },
232 { "help", 'h', arg_flag, &help_flag }
235 static int num_args = sizeof(args) / sizeof(args[0]);
237 static void
238 usage (int code)
240 arg_printusage(args, num_args, NULL, "");
241 exit (code);
244 /* output contents of a file */
245 static int
246 show_file(const char *file, int code)
248 FILE *f;
249 char buf[128];
251 f = fopen(file, "r");
252 if(f == NULL)
253 return -1;
254 while(fgets(buf, sizeof(buf), f)){
255 buf[strcspn(buf, "\r\n")] = '\0';
256 lreply(code, "%s", buf);
258 fclose(f);
259 return 0;
263 main(int argc, char **argv)
265 socklen_t his_addr_len, ctrl_addr_len;
266 int on = 1;
267 int port;
268 struct servent *sp;
270 int optind = 0;
272 setprogname (argv[0]);
274 /* detach from any tickets and tokens */
276 #ifdef KRB4
277 char tkfile[1024];
278 snprintf(tkfile, sizeof(tkfile),
279 "/tmp/ftp_%u", (unsigned)getpid());
280 krb_set_tkt_string(tkfile);
281 #endif
283 #if defined(KRB4) || defined(KRB5)
284 if(k_hasafs())
285 k_setpag();
286 #endif
288 if(getarg(args, num_args, argc, argv, &optind))
289 usage(1);
291 if(help_flag)
292 usage(0);
294 if(version_flag) {
295 print_version(NULL);
296 exit(0);
299 if(auth_string)
300 auth_level = parse_auth_level(auth_string);
302 char *p;
303 long val = 0;
305 if(guest_umask_string) {
306 val = strtol(guest_umask_string, &p, 8);
307 if (*p != '\0' || val < 0)
308 warnx("bad value for -g");
309 else
310 guest_umask = val;
312 if(umask_string) {
313 val = strtol(umask_string, &p, 8);
314 if (*p != '\0' || val < 0)
315 warnx("bad value for -u");
316 else
317 defumask = val;
320 sp = getservbyname("ftp", "tcp");
321 if(sp)
322 port = sp->s_port;
323 else
324 port = htons(21);
325 if(port_string) {
326 sp = getservbyname(port_string, "tcp");
327 if(sp)
328 port = sp->s_port;
329 else
330 if(isdigit((unsigned char)port_string[0]))
331 port = htons(atoi(port_string));
332 else
333 warnx("bad value for -p");
336 if (maxtimeout < ftpd_timeout)
337 maxtimeout = ftpd_timeout;
339 #if 0
340 if (ftpd_timeout > maxtimeout)
341 ftpd_timeout = maxtimeout;
342 #endif
344 if(interactive_flag)
345 mini_inetd (port);
348 * LOG_NDELAY sets up the logging connection immediately,
349 * necessary for anonymous ftp's that chroot and can't do it later.
351 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
352 his_addr_len = sizeof(his_addr_ss);
353 if (getpeername(STDIN_FILENO, his_addr, &his_addr_len) < 0) {
354 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
355 exit(1);
357 ctrl_addr_len = sizeof(ctrl_addr_ss);
358 if (getsockname(STDIN_FILENO, ctrl_addr, &ctrl_addr_len) < 0) {
359 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
360 exit(1);
362 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
364 int tos = IPTOS_LOWDELAY;
366 if (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS,
367 (void *)&tos, sizeof(int)) < 0)
368 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
370 #endif
371 data_source->sa_family = ctrl_addr->sa_family;
372 socket_set_port (data_source,
373 htons(ntohs(socket_get_port(ctrl_addr)) - 1));
375 /* set this here so it can be put in wtmp */
376 snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
379 /* freopen(_PATH_DEVNULL, "w", stderr); */
380 signal(SIGPIPE, lostconn);
381 signal(SIGCHLD, SIG_IGN);
382 #ifdef SIGURG
383 if (signal(SIGURG, myoob) == SIG_ERR)
384 syslog(LOG_ERR, "signal: %m");
385 #endif
387 /* Try to handle urgent data inline */
388 #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
389 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on,
390 sizeof(on)) < 0)
391 syslog(LOG_ERR, "setsockopt: %m");
392 #endif
394 #ifdef F_SETOWN
395 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
396 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
397 #endif
398 dolog(his_addr, his_addr_len);
400 * Set up default state
402 data = -1;
403 type = TYPE_A;
404 form = FORM_N;
405 stru = STRU_F;
406 mode = MODE_S;
407 tmpline[0] = '\0';
409 /* If logins are disabled, print out the message. */
410 if(show_file(_PATH_NOLOGIN, 530) == 0) {
411 reply(530, "System not available.");
412 exit(0);
414 show_file(_PATH_FTPWELCOME, 220);
415 /* reply(220,) must follow */
416 gethostname(hostname, sizeof(hostname));
418 reply(220, "%s FTP server (%s"
419 #ifdef KRB5
420 "+%s"
421 #endif
422 #ifdef KRB4
423 "+%s"
424 #endif
425 ") ready.", hostname, version
426 #ifdef KRB5
427 ,heimdal_version
428 #endif
429 #ifdef KRB4
430 ,krb4_version
431 #endif
434 for (;;)
435 yyparse();
436 /* NOTREACHED */
439 static RETSIGTYPE
440 lostconn(int signo)
443 if (debug)
444 syslog(LOG_DEBUG, "lost connection");
445 dologout(-1);
449 * Helper function for sgetpwnam().
451 static char *
452 sgetsave(char *s)
454 char *new = strdup(s);
456 if (new == NULL) {
457 perror_reply(421, "Local resource failure: malloc");
458 dologout(1);
459 /* NOTREACHED */
461 return new;
465 * Save the result of a getpwnam. Used for USER command, since
466 * the data returned must not be clobbered by any other command
467 * (e.g., globbing).
469 static struct passwd *
470 sgetpwnam(char *name)
472 static struct passwd save;
473 struct passwd *p;
475 if ((p = k_getpwnam(name)) == NULL)
476 return (p);
477 if (save.pw_name) {
478 free(save.pw_name);
479 free(save.pw_passwd);
480 free(save.pw_gecos);
481 free(save.pw_dir);
482 free(save.pw_shell);
484 save = *p;
485 save.pw_name = sgetsave(p->pw_name);
486 save.pw_passwd = sgetsave(p->pw_passwd);
487 save.pw_gecos = sgetsave(p->pw_gecos);
488 save.pw_dir = sgetsave(p->pw_dir);
489 save.pw_shell = sgetsave(p->pw_shell);
490 return (&save);
493 static int login_attempts; /* number of failed login attempts */
494 static int askpasswd; /* had user command, ask for passwd */
495 static char curname[10]; /* current USER name */
496 #ifdef OTP
497 OtpContext otp_ctx;
498 #endif
501 * USER command.
502 * Sets global passwd pointer pw if named account exists and is acceptable;
503 * sets askpasswd if a PASS command is expected. If logged in previously,
504 * need to reset state. If name is "ftp" or "anonymous", the name is not in
505 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
506 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
507 * requesting login privileges. Disallow anyone who does not have a standard
508 * shell as returned by getusershell(). Disallow anyone mentioned in the file
509 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
511 void
512 user(char *name)
514 char *cp, *shell;
516 if(auth_level == 0 && !sec_complete){
517 reply(530, "No login allowed without authorization.");
518 return;
521 if (logged_in) {
522 if (guest) {
523 reply(530, "Can't change user from guest login.");
524 return;
525 } else if (dochroot) {
526 reply(530, "Can't change user from chroot user.");
527 return;
529 end_login();
532 guest = 0;
533 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
534 if ((auth_level & AUTH_FTP) == 0 ||
535 checkaccess("ftp") ||
536 checkaccess("anonymous"))
537 reply(530, "User %s access denied.", name);
538 else if ((pw = sgetpwnam("ftp")) != NULL) {
539 guest = 1;
540 defumask = guest_umask; /* paranoia for incoming */
541 askpasswd = 1;
542 reply(331, "Guest login ok, type your name as password.");
543 } else
544 reply(530, "User %s unknown.", name);
545 if (!askpasswd && logging) {
546 char data_addr[256];
548 if (inet_ntop (his_addr->sa_family,
549 socket_get_address(his_addr),
550 data_addr, sizeof(data_addr)) == NULL)
551 strlcpy (data_addr, "unknown address",
552 sizeof(data_addr));
554 syslog(LOG_NOTICE,
555 "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
556 remotehost, data_addr);
558 return;
560 if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
561 reply(530, "Only authorized and anonymous login allowed.");
562 return;
564 if ((pw = sgetpwnam(name))) {
565 if ((shell = pw->pw_shell) == NULL || *shell == 0)
566 shell = _PATH_BSHELL;
567 while ((cp = getusershell()) != NULL)
568 if (strcmp(cp, shell) == 0)
569 break;
570 endusershell();
572 if (cp == NULL || checkaccess(name)) {
573 reply(530, "User %s access denied.", name);
574 if (logging) {
575 char data_addr[256];
577 if (inet_ntop (his_addr->sa_family,
578 socket_get_address(his_addr),
579 data_addr,
580 sizeof(data_addr)) == NULL)
581 strlcpy (data_addr,
582 "unknown address",
583 sizeof(data_addr));
585 syslog(LOG_NOTICE,
586 "FTP LOGIN REFUSED FROM %s(%s), %s",
587 remotehost,
588 data_addr,
589 name);
591 pw = (struct passwd *) NULL;
592 return;
595 if (logging)
596 strlcpy(curname, name, sizeof(curname));
597 if(sec_complete) {
598 if(sec_userok(name) == 0)
599 do_login(232, name);
600 else
601 reply(530, "User %s access denied.", name);
602 } else {
603 char ss[256];
605 #ifdef OTP
606 if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) {
607 reply(331, "Password %s for %s required.",
608 ss, name);
609 askpasswd = 1;
610 } else
611 #endif
612 if ((auth_level & AUTH_OTP) == 0) {
613 reply(331, "Password required for %s.", name);
614 askpasswd = 1;
615 } else {
616 char *s;
618 #ifdef OTP
619 if ((s = otp_error (&otp_ctx)) != NULL)
620 lreply(530, "OTP: %s", s);
621 #endif
622 reply(530,
623 "Only authorized, anonymous"
624 #ifdef OTP
625 " and OTP "
626 #endif
627 "login allowed.");
632 * Delay before reading passwd after first failed
633 * attempt to slow down passwd-guessing programs.
635 if (login_attempts)
636 sleep(login_attempts);
640 * Check if a user is in the file "fname"
642 static int
643 checkuser(char *fname, char *name)
645 FILE *fd;
646 int found = 0;
647 char *p, line[BUFSIZ];
649 if ((fd = fopen(fname, "r")) != NULL) {
650 while (fgets(line, sizeof(line), fd) != NULL)
651 if ((p = strchr(line, '\n')) != NULL) {
652 *p = '\0';
653 if (line[0] == '#')
654 continue;
655 if (strcmp(line, name) == 0) {
656 found = 1;
657 break;
660 fclose(fd);
662 return (found);
667 * Determine whether a user has access, based on information in
668 * _PATH_FTPUSERS. The users are listed one per line, with `allow'
669 * or `deny' after the username. If anything other than `allow', or
670 * just nothing, is given after the username, `deny' is assumed.
672 * If the user is not found in the file, but the pseudo-user `*' is,
673 * the permission is taken from that line.
675 * This preserves the old semantics where if a user was listed in the
676 * file he was denied, otherwise he was allowed.
678 * Return 1 if the user is denied, or 0 if he is allowed. */
680 static int
681 match(const char *pattern, const char *string)
683 return fnmatch(pattern, string, FNM_NOESCAPE);
686 static int
687 checkaccess(char *name)
689 #define ALLOWED 0
690 #define NOT_ALLOWED 1
691 FILE *fd;
692 int allowed = ALLOWED;
693 char *user, *perm, line[BUFSIZ];
694 char *foo;
696 fd = fopen(_PATH_FTPUSERS, "r");
698 if(fd == NULL)
699 return allowed;
701 while (fgets(line, sizeof(line), fd) != NULL) {
702 foo = NULL;
703 user = strtok_r(line, " \t\n", &foo);
704 if (user == NULL || user[0] == '#')
705 continue;
706 perm = strtok_r(NULL, " \t\n", &foo);
707 if (match(user, name) == 0){
708 if(perm && strcmp(perm, "allow") == 0)
709 allowed = ALLOWED;
710 else
711 allowed = NOT_ALLOWED;
712 break;
715 fclose(fd);
716 return allowed;
718 #undef ALLOWED
719 #undef NOT_ALLOWED
722 int do_login(int code, char *passwd)
724 login_attempts = 0; /* this time successful */
725 if (setegid((gid_t)pw->pw_gid) < 0) {
726 reply(550, "Can't set gid.");
727 return -1;
729 initgroups(pw->pw_name, pw->pw_gid);
731 /* open wtmp before chroot */
732 ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
733 logged_in = 1;
735 dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
736 if (guest) {
738 * We MUST do a chdir() after the chroot. Otherwise
739 * the old current directory will be accessible as "."
740 * outside the new root!
742 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
743 reply(550, "Can't set guest privileges.");
744 return -1;
746 } else if (dochroot) {
747 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
748 reply(550, "Can't change root.");
749 return -1;
751 } else if (chdir(pw->pw_dir) < 0) {
752 if (chdir("/") < 0) {
753 reply(530, "User %s: can't change directory to %s.",
754 pw->pw_name, pw->pw_dir);
755 return -1;
756 } else
757 lreply(code, "No directory! Logging in with home=/");
759 if (seteuid((uid_t)pw->pw_uid) < 0) {
760 reply(550, "Can't set uid.");
761 return -1;
764 if(use_builtin_ls == -1) {
765 struct stat st;
766 /* if /bin/ls exist and is a regular file, use it, otherwise
767 use built-in ls */
768 if(stat("/bin/ls", &st) == 0 &&
769 S_ISREG(st.st_mode))
770 use_builtin_ls = 0;
771 else
772 use_builtin_ls = 1;
776 * Display a login message, if it exists.
777 * N.B. reply(code,) must follow the message.
779 show_file(_PATH_FTPLOGINMESG, code);
780 if(show_file(_PATH_ISSUE_NET, code) != 0)
781 show_file(_PATH_ISSUE, code);
782 if (guest) {
783 reply(code, "Guest login ok, access restrictions apply.");
784 #ifdef HAVE_SETPROCTITLE
785 snprintf (proctitle, sizeof(proctitle),
786 "%s: anonymous/%s",
787 remotehost,
788 passwd);
789 setproctitle("%s", proctitle);
790 #endif /* HAVE_SETPROCTITLE */
791 if (logging) {
792 char data_addr[256];
794 if (inet_ntop (his_addr->sa_family,
795 socket_get_address(his_addr),
796 data_addr, sizeof(data_addr)) == NULL)
797 strlcpy (data_addr, "unknown address",
798 sizeof(data_addr));
800 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
801 remotehost,
802 data_addr,
803 passwd);
805 } else {
806 reply(code, "User %s logged in.", pw->pw_name);
807 #ifdef HAVE_SETPROCTITLE
808 snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
809 setproctitle("%s", proctitle);
810 #endif /* HAVE_SETPROCTITLE */
811 if (logging) {
812 char data_addr[256];
814 if (inet_ntop (his_addr->sa_family,
815 socket_get_address(his_addr),
816 data_addr, sizeof(data_addr)) == NULL)
817 strlcpy (data_addr, "unknown address",
818 sizeof(data_addr));
820 syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
821 remotehost,
822 data_addr,
823 pw->pw_name);
826 umask(defumask);
827 return 0;
831 * Terminate login as previous user, if any, resetting state;
832 * used when USER command is given or login fails.
834 static void
835 end_login(void)
838 seteuid((uid_t)0);
839 if (logged_in)
840 ftpd_logwtmp(ttyline, "", "");
841 pw = NULL;
842 logged_in = 0;
843 guest = 0;
844 dochroot = 0;
847 #ifdef KRB5
848 static int
849 krb5_verify(struct passwd *pwd, char *passwd)
851 krb5_context context;
852 krb5_ccache id;
853 krb5_principal princ;
854 krb5_error_code ret;
856 ret = krb5_init_context(&context);
857 if(ret)
858 return ret;
860 ret = krb5_parse_name(context, pwd->pw_name, &princ);
861 if(ret){
862 krb5_free_context(context);
863 return ret;
865 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id);
866 if(ret){
867 krb5_free_principal(context, princ);
868 krb5_free_context(context);
869 return ret;
871 ret = krb5_verify_user(context,
872 princ,
874 passwd,
876 NULL);
877 krb5_free_principal(context, princ);
878 if (k_hasafs()) {
879 krb5_afslog_uid_home(context, id,NULL, NULL,pwd->pw_uid, pwd->pw_dir);
881 krb5_cc_destroy(context, id);
882 krb5_free_context (context);
883 if(ret)
884 return ret;
885 return 0;
887 #endif /* KRB5 */
889 void
890 pass(char *passwd)
892 int rval;
894 /* some clients insists on sending a password */
895 if (logged_in && askpasswd == 0){
896 reply(230, "Password not necessary");
897 return;
900 if (logged_in || askpasswd == 0) {
901 reply(503, "Login with USER first.");
902 return;
904 askpasswd = 0;
905 rval = 1;
906 if (!guest) { /* "ftp" is only account allowed no password */
907 if (pw == NULL)
908 rval = 1; /* failure below */
909 #ifdef OTP
910 else if (otp_verify_user (&otp_ctx, passwd) == 0) {
911 rval = 0;
913 #endif
914 else if((auth_level & AUTH_OTP) == 0) {
915 #ifdef KRB5
916 rval = krb5_verify(pw, passwd);
917 #endif
918 #ifdef KRB4
919 if (rval) {
920 char realm[REALM_SZ];
921 if((rval = krb_get_lrealm(realm, 1)) == KSUCCESS)
922 rval = krb_verify_user(pw->pw_name,
923 "", realm,
924 passwd,
925 KRB_VERIFY_SECURE, NULL);
926 if (rval == KSUCCESS ) {
927 chown (tkt_string(), pw->pw_uid, pw->pw_gid);
928 if(k_hasafs())
929 krb_afslog(0, 0);
932 #endif
933 if (rval)
934 rval = unix_verify_user(pw->pw_name, passwd);
935 } else {
936 char *s;
938 #ifdef OTP
939 if ((s = otp_error(&otp_ctx)) != NULL)
940 lreply(530, "OTP: %s", s);
941 #endif
943 memset (passwd, 0, strlen(passwd));
946 * If rval == 1, the user failed the authentication
947 * check above. If rval == 0, either Kerberos or
948 * local authentication succeeded.
950 if (rval) {
951 char data_addr[256];
953 if (inet_ntop (his_addr->sa_family,
954 socket_get_address(his_addr),
955 data_addr, sizeof(data_addr)) == NULL)
956 strlcpy (data_addr, "unknown address",
957 sizeof(data_addr));
959 reply(530, "Login incorrect.");
960 if (logging)
961 syslog(LOG_NOTICE,
962 "FTP LOGIN FAILED FROM %s(%s), %s",
963 remotehost,
964 data_addr,
965 curname);
966 pw = NULL;
967 if (login_attempts++ >= 5) {
968 syslog(LOG_NOTICE,
969 "repeated login failures from %s(%s)",
970 remotehost,
971 data_addr);
972 exit(0);
974 return;
977 if(!do_login(230, passwd))
978 return;
980 /* Forget all about it... */
981 end_login();
984 void
985 retrieve(const char *cmd, char *name)
987 FILE *fin = NULL, *dout;
988 struct stat st;
989 int (*closefunc) (FILE *);
990 char line[BUFSIZ];
993 if (cmd == 0) {
994 fin = fopen(name, "r");
995 closefunc = fclose;
996 st.st_size = 0;
997 if(fin == NULL){
998 int save_errno = errno;
999 struct cmds {
1000 const char *ext;
1001 const char *cmd;
1002 const char *rev_cmd;
1003 } cmds[] = {
1004 {".tar", "/bin/gtar cPf - %s", NULL},
1005 {".tar.gz", "/bin/gtar zcPf - %s", NULL},
1006 {".tar.Z", "/bin/gtar ZcPf - %s", NULL},
1007 {".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"},
1008 {".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"},
1009 {NULL, NULL}
1011 struct cmds *p;
1012 for(p = cmds; p->ext; p++){
1013 char *tail = name + strlen(name) - strlen(p->ext);
1014 char c = *tail;
1016 if(strcmp(tail, p->ext) == 0 &&
1017 (*tail = 0) == 0 &&
1018 access(name, R_OK) == 0){
1019 snprintf (line, sizeof(line), p->cmd, name);
1020 *tail = c;
1021 break;
1023 *tail = c;
1024 if (p->rev_cmd != NULL) {
1025 char *ext;
1027 asprintf(&ext, "%s%s", name, p->ext);
1028 if (ext != NULL) {
1029 if (access(ext, R_OK) == 0) {
1030 snprintf (line, sizeof(line),
1031 p->rev_cmd, ext);
1032 free(ext);
1033 break;
1035 free(ext);
1040 if(p->ext){
1041 fin = ftpd_popen(line, "r", 0, 0);
1042 closefunc = ftpd_pclose;
1043 st.st_size = -1;
1044 cmd = line;
1045 } else
1046 errno = save_errno;
1048 } else {
1049 snprintf(line, sizeof(line), cmd, name);
1050 name = line;
1051 fin = ftpd_popen(line, "r", 1, 0);
1052 closefunc = ftpd_pclose;
1053 st.st_size = -1;
1055 if (fin == NULL) {
1056 if (errno != 0) {
1057 perror_reply(550, name);
1058 if (cmd == 0) {
1059 LOGCMD("get", name);
1062 return;
1064 byte_count = -1;
1065 if (cmd == 0){
1066 if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
1067 reply(550, "%s: not a plain file.", name);
1068 goto done;
1071 if (restart_point) {
1072 if (type == TYPE_A) {
1073 off_t i, n;
1074 int c;
1076 n = restart_point;
1077 i = 0;
1078 while (i++ < n) {
1079 if ((c=getc(fin)) == EOF) {
1080 perror_reply(550, name);
1081 goto done;
1083 if (c == '\n')
1084 i++;
1086 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1087 perror_reply(550, name);
1088 goto done;
1091 dout = dataconn(name, st.st_size, "w");
1092 if (dout == NULL)
1093 goto done;
1094 set_buffer_size(fileno(dout), 0);
1095 send_data(fin, dout);
1096 fclose(dout);
1097 data = -1;
1098 pdata = -1;
1099 done:
1100 if (cmd == 0)
1101 LOGBYTES("get", name, byte_count);
1102 (*closefunc)(fin);
1105 /* filename sanity check */
1107 int
1108 filename_check(char *filename)
1110 unsigned char *p;
1112 p = (unsigned char *)strrchr(filename, '/');
1113 if(p)
1114 filename = p + 1;
1116 p = filename;
1118 if(isalnum(*p)){
1119 p++;
1120 while(*p && (isalnum(*p) || strchr(good_chars, *p)))
1121 p++;
1122 if(*p == '\0')
1123 return 0;
1125 lreply(553, "\"%s\" is not an acceptable filename.", filename);
1126 lreply(553, "The filename must start with an alphanumeric "
1127 "character and must only");
1128 reply(553, "consist of alphanumeric characters or any of the following: %s",
1129 good_chars);
1130 return 1;
1133 void
1134 do_store(char *name, char *mode, int unique)
1136 FILE *fout, *din;
1137 struct stat st;
1138 int (*closefunc) (FILE *);
1140 if(guest && filename_check(name))
1141 return;
1142 if (unique && stat(name, &st) == 0 &&
1143 (name = gunique(name)) == NULL) {
1144 LOGCMD(*mode == 'w' ? "put" : "append", name);
1145 return;
1148 if (restart_point)
1149 mode = "r+";
1150 fout = fopen(name, mode);
1151 closefunc = fclose;
1152 if (fout == NULL) {
1153 perror_reply(553, name);
1154 LOGCMD(*mode == 'w' ? "put" : "append", name);
1155 return;
1157 byte_count = -1;
1158 if (restart_point) {
1159 if (type == TYPE_A) {
1160 off_t i, n;
1161 int c;
1163 n = restart_point;
1164 i = 0;
1165 while (i++ < n) {
1166 if ((c=getc(fout)) == EOF) {
1167 perror_reply(550, name);
1168 goto done;
1170 if (c == '\n')
1171 i++;
1174 * We must do this seek to "current" position
1175 * because we are changing from reading to
1176 * writing.
1178 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1179 perror_reply(550, name);
1180 goto done;
1182 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1183 perror_reply(550, name);
1184 goto done;
1187 din = dataconn(name, (off_t)-1, "r");
1188 if (din == NULL)
1189 goto done;
1190 set_buffer_size(fileno(din), 1);
1191 if (receive_data(din, fout) == 0) {
1192 if((*closefunc)(fout) < 0)
1193 perror_reply(552, name);
1194 else {
1195 if (unique)
1196 reply(226, "Transfer complete (unique file name:%s).",
1197 name);
1198 else
1199 reply(226, "Transfer complete.");
1201 } else
1202 (*closefunc)(fout);
1203 fclose(din);
1204 data = -1;
1205 pdata = -1;
1206 done:
1207 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1210 static FILE *
1211 getdatasock(const char *mode)
1213 int s, t, tries;
1215 if (data >= 0)
1216 return (fdopen(data, mode));
1217 seteuid(0);
1218 s = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
1219 if (s < 0)
1220 goto bad;
1221 socket_set_reuseaddr (s, 1);
1222 /* anchor socket to avoid multi-homing problems */
1223 socket_set_address_and_port (data_source,
1224 socket_get_address (ctrl_addr),
1225 socket_get_port (data_source));
1227 for (tries = 1; ; tries++) {
1228 if (bind(s, data_source,
1229 socket_sockaddr_size (data_source)) >= 0)
1230 break;
1231 if (errno != EADDRINUSE || tries > 10)
1232 goto bad;
1233 sleep(tries);
1235 seteuid(pw->pw_uid);
1236 #ifdef IPTOS_THROUGHPUT
1237 socket_set_tos (s, IPTOS_THROUGHPUT);
1238 #endif
1239 return (fdopen(s, mode));
1240 bad:
1241 /* Return the real value of errno (close may change it) */
1242 t = errno;
1243 seteuid((uid_t)pw->pw_uid);
1244 close(s);
1245 errno = t;
1246 return (NULL);
1249 static int
1250 accept_with_timeout(int socket,
1251 struct sockaddr *address,
1252 socklen_t *address_len,
1253 struct timeval *timeout)
1255 int ret;
1256 fd_set rfd;
1257 FD_ZERO(&rfd);
1258 FD_SET(socket, &rfd);
1259 ret = select(socket + 1, &rfd, NULL, NULL, timeout);
1260 if(ret < 0)
1261 return ret;
1262 if(ret == 0) {
1263 errno = ETIMEDOUT;
1264 return -1;
1266 return accept(socket, address, address_len);
1269 static FILE *
1270 dataconn(const char *name, off_t size, const char *mode)
1272 char sizebuf[32];
1273 FILE *file;
1274 int retry = 0;
1276 file_size = size;
1277 byte_count = 0;
1278 if (size >= 0)
1279 snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", (long)size);
1280 else
1281 *sizebuf = '\0';
1282 if (pdata >= 0) {
1283 struct sockaddr_storage from_ss;
1284 struct sockaddr *from = (struct sockaddr *)&from_ss;
1285 struct timeval timeout;
1286 int s;
1287 socklen_t fromlen = sizeof(from_ss);
1289 timeout.tv_sec = 15;
1290 timeout.tv_usec = 0;
1291 s = accept_with_timeout(pdata, from, &fromlen, &timeout);
1292 if (s < 0) {
1293 reply(425, "Can't open data connection.");
1294 close(pdata);
1295 pdata = -1;
1296 return (NULL);
1298 close(pdata);
1299 pdata = s;
1300 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
1302 int tos = IPTOS_THROUGHPUT;
1304 setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&tos,
1305 sizeof(tos));
1307 #endif
1308 reply(150, "Opening %s mode data connection for '%s'%s.",
1309 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1310 return (fdopen(pdata, mode));
1312 if (data >= 0) {
1313 reply(125, "Using existing data connection for '%s'%s.",
1314 name, sizebuf);
1315 usedefault = 1;
1316 return (fdopen(data, mode));
1318 if (usedefault)
1319 data_dest = his_addr;
1320 usedefault = 1;
1321 file = getdatasock(mode);
1322 if (file == NULL) {
1323 char data_addr[256];
1325 if (inet_ntop (data_source->sa_family,
1326 socket_get_address(data_source),
1327 data_addr, sizeof(data_addr)) == NULL)
1328 strlcpy (data_addr, "unknown address",
1329 sizeof(data_addr));
1331 reply(425, "Can't create data socket (%s,%d): %s.",
1332 data_addr,
1333 socket_get_port (data_source),
1334 strerror(errno));
1335 return (NULL);
1337 data = fileno(file);
1338 while (connect(data, data_dest,
1339 socket_sockaddr_size(data_dest)) < 0) {
1340 if (errno == EADDRINUSE && retry < swaitmax) {
1341 sleep(swaitint);
1342 retry += swaitint;
1343 continue;
1345 perror_reply(425, "Can't build data connection");
1346 fclose(file);
1347 data = -1;
1348 return (NULL);
1350 reply(150, "Opening %s mode data connection for '%s'%s.",
1351 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1352 return (file);
1356 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1357 * encapsulation of the data subject * to Mode, Structure, and Type.
1359 * NB: Form isn't handled.
1361 static void
1362 send_data(FILE *instr, FILE *outstr)
1364 int c, cnt, filefd, netfd;
1365 static char *buf;
1366 static size_t bufsize;
1368 transflag = 1;
1369 switch (type) {
1371 case TYPE_A:
1372 while ((c = getc(instr)) != EOF) {
1373 if (urgflag && handleoobcmd())
1374 return;
1375 byte_count++;
1376 if(c == '\n')
1377 sec_putc('\r', outstr);
1378 sec_putc(c, outstr);
1380 sec_fflush(outstr);
1381 transflag = 0;
1382 urgflag = 0;
1383 if (ferror(instr))
1384 goto file_err;
1385 if (ferror(outstr))
1386 goto data_err;
1387 reply(226, "Transfer complete.");
1388 return;
1390 case TYPE_I:
1391 case TYPE_L:
1392 #if 0 /* XXX handle urg flag */
1393 #if defined(HAVE_MMAP) && !defined(NO_MMAP)
1394 #ifndef MAP_FAILED
1395 #define MAP_FAILED (-1)
1396 #endif
1398 struct stat st;
1399 char *chunk;
1400 int in = fileno(instr);
1401 if(fstat(in, &st) == 0 && S_ISREG(st.st_mode)
1402 && st.st_size > 0) {
1404 * mmap zero bytes has potential of loosing, don't do it.
1406 chunk = mmap(0, st.st_size, PROT_READ,
1407 MAP_SHARED, in, 0);
1408 if((void *)chunk != (void *)MAP_FAILED) {
1409 cnt = st.st_size - restart_point;
1410 sec_write(fileno(outstr), chunk + restart_point, cnt);
1411 if (munmap(chunk, st.st_size) < 0)
1412 warn ("munmap");
1413 sec_fflush(outstr);
1414 byte_count = cnt;
1415 transflag = 0;
1416 urgflag = 0;
1420 #endif
1421 #endif
1422 if(transflag) {
1423 struct stat st;
1425 netfd = fileno(outstr);
1426 filefd = fileno(instr);
1427 buf = alloc_buffer (buf, &bufsize,
1428 fstat(filefd, &st) >= 0 ? &st : NULL);
1429 if (buf == NULL) {
1430 transflag = 0;
1431 urgflag = 0;
1432 perror_reply(451, "Local resource failure: malloc");
1433 return;
1435 while ((cnt = read(filefd, buf, bufsize)) > 0 &&
1436 sec_write(netfd, buf, cnt) == cnt) {
1437 byte_count += cnt;
1438 if (urgflag && handleoobcmd())
1439 return;
1441 sec_fflush(outstr); /* to end an encrypted stream */
1442 transflag = 0;
1443 urgflag = 0;
1444 if (cnt != 0) {
1445 if (cnt < 0)
1446 goto file_err;
1447 goto data_err;
1450 reply(226, "Transfer complete.");
1451 return;
1452 default:
1453 transflag = 0;
1454 urgflag = 0;
1455 reply(550, "Unimplemented TYPE %d in send_data", type);
1456 return;
1459 data_err:
1460 transflag = 0;
1461 urgflag = 0;
1462 perror_reply(426, "Data connection");
1463 return;
1465 file_err:
1466 transflag = 0;
1467 urgflag = 0;
1468 perror_reply(551, "Error on input file");
1472 * Transfer data from peer to "outstr" using the appropriate encapulation of
1473 * the data subject to Mode, Structure, and Type.
1475 * N.B.: Form isn't handled.
1477 static int
1478 receive_data(FILE *instr, FILE *outstr)
1480 int cnt, bare_lfs = 0;
1481 static char *buf;
1482 static size_t bufsize;
1483 struct stat st;
1485 transflag = 1;
1487 buf = alloc_buffer (buf, &bufsize,
1488 fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
1489 if (buf == NULL) {
1490 transflag = 0;
1491 urgflag = 0;
1492 perror_reply(451, "Local resource failure: malloc");
1493 return -1;
1496 switch (type) {
1498 case TYPE_I:
1499 case TYPE_L:
1500 while ((cnt = sec_read(fileno(instr), buf, bufsize)) > 0) {
1501 if (write(fileno(outstr), buf, cnt) != cnt)
1502 goto file_err;
1503 byte_count += cnt;
1504 if (urgflag && handleoobcmd())
1505 return (-1);
1507 if (cnt < 0)
1508 goto data_err;
1509 transflag = 0;
1510 urgflag = 0;
1511 return (0);
1513 case TYPE_E:
1514 reply(553, "TYPE E not implemented.");
1515 transflag = 0;
1516 urgflag = 0;
1517 return (-1);
1519 case TYPE_A:
1521 char *p, *q;
1522 int cr_flag = 0;
1523 while ((cnt = sec_read(fileno(instr),
1524 buf + cr_flag,
1525 bufsize - cr_flag)) > 0){
1526 if (urgflag && handleoobcmd())
1527 return (-1);
1528 byte_count += cnt;
1529 cnt += cr_flag;
1530 cr_flag = 0;
1531 for(p = buf, q = buf; p < buf + cnt;) {
1532 if(*p == '\n')
1533 bare_lfs++;
1534 if(*p == '\r') {
1535 if(p == buf + cnt - 1){
1536 cr_flag = 1;
1537 p++;
1538 continue;
1539 }else if(p[1] == '\n'){
1540 *q++ = '\n';
1541 p += 2;
1542 continue;
1545 *q++ = *p++;
1547 fwrite(buf, q - buf, 1, outstr);
1548 if(cr_flag)
1549 buf[0] = '\r';
1551 if(cr_flag)
1552 putc('\r', outstr);
1553 fflush(outstr);
1554 if (ferror(instr))
1555 goto data_err;
1556 if (ferror(outstr))
1557 goto file_err;
1558 transflag = 0;
1559 urgflag = 0;
1560 if (bare_lfs) {
1561 lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
1562 " File may not have transferred correctly.\r\n",
1563 bare_lfs);
1565 return (0);
1567 default:
1568 reply(550, "Unimplemented TYPE %d in receive_data", type);
1569 transflag = 0;
1570 urgflag = 0;
1571 return (-1);
1574 data_err:
1575 transflag = 0;
1576 urgflag = 0;
1577 perror_reply(426, "Data Connection");
1578 return (-1);
1580 file_err:
1581 transflag = 0;
1582 urgflag = 0;
1583 perror_reply(452, "Error writing file");
1584 return (-1);
1587 void
1588 statfilecmd(char *filename)
1590 FILE *fin;
1591 int c;
1592 char line[LINE_MAX];
1594 snprintf(line, sizeof(line), "/bin/ls -la -- %s", filename);
1595 fin = ftpd_popen(line, "r", 1, 0);
1596 lreply(211, "status of %s:", filename);
1597 while ((c = getc(fin)) != EOF) {
1598 if (c == '\n') {
1599 if (ferror(stdout)){
1600 perror_reply(421, "control connection");
1601 ftpd_pclose(fin);
1602 dologout(1);
1603 /* NOTREACHED */
1605 if (ferror(fin)) {
1606 perror_reply(551, filename);
1607 ftpd_pclose(fin);
1608 return;
1610 putc('\r', stdout);
1612 putc(c, stdout);
1614 ftpd_pclose(fin);
1615 reply(211, "End of Status");
1618 void
1619 statcmd(void)
1621 #if 0
1622 struct sockaddr_in *sin;
1623 u_char *a, *p;
1625 lreply(211, "%s FTP server (%s) status:", hostname, version);
1626 printf(" %s\r\n", version);
1627 printf(" Connected to %s", remotehost);
1628 if (!isdigit(remotehost[0]))
1629 printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1630 printf("\r\n");
1631 if (logged_in) {
1632 if (guest)
1633 printf(" Logged in anonymously\r\n");
1634 else
1635 printf(" Logged in as %s\r\n", pw->pw_name);
1636 } else if (askpasswd)
1637 printf(" Waiting for password\r\n");
1638 else
1639 printf(" Waiting for user name\r\n");
1640 printf(" TYPE: %s", typenames[type]);
1641 if (type == TYPE_A || type == TYPE_E)
1642 printf(", FORM: %s", formnames[form]);
1643 if (type == TYPE_L)
1644 #if NBBY == 8
1645 printf(" %d", NBBY);
1646 #else
1647 printf(" %d", bytesize); /* need definition! */
1648 #endif
1649 printf("; STRUcture: %s; transfer MODE: %s\r\n",
1650 strunames[stru], modenames[mode]);
1651 if (data != -1)
1652 printf(" Data connection open\r\n");
1653 else if (pdata != -1) {
1654 printf(" in Passive mode");
1655 sin = &pasv_addr;
1656 goto printaddr;
1657 } else if (usedefault == 0) {
1658 printf(" PORT");
1659 sin = &data_dest;
1660 printaddr:
1661 a = (u_char *) &sin->sin_addr;
1662 p = (u_char *) &sin->sin_port;
1663 #define UC(b) (((int) b) & 0xff)
1664 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1665 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1666 #undef UC
1667 } else
1668 printf(" No data connection\r\n");
1669 #endif
1670 reply(211, "End of status");
1673 void
1674 fatal(char *s)
1677 reply(451, "Error in server: %s\n", s);
1678 reply(221, "Closing connection due to server error.");
1679 dologout(0);
1680 /* NOTREACHED */
1683 static void
1684 int_reply(int, char *, const char *, va_list)
1685 #ifdef __GNUC__
1686 __attribute__ ((format (printf, 3, 0)))
1687 #endif
1690 static void
1691 int_reply(int n, char *c, const char *fmt, va_list ap)
1693 char buf[10240];
1694 char *p;
1695 p=buf;
1696 if(n){
1697 snprintf(p, sizeof(buf), "%d%s", n, c);
1698 p+=strlen(p);
1700 vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap);
1701 p+=strlen(p);
1702 snprintf(p, sizeof(buf) - strlen(p), "\r\n");
1703 p+=strlen(p);
1704 sec_fprintf(stdout, "%s", buf);
1705 fflush(stdout);
1706 if (debug)
1707 syslog(LOG_DEBUG, "<--- %s- ", buf);
1710 void
1711 reply(int n, const char *fmt, ...)
1713 va_list ap;
1714 va_start(ap, fmt);
1715 int_reply(n, " ", fmt, ap);
1716 delete_ftp_command();
1717 va_end(ap);
1720 void
1721 lreply(int n, const char *fmt, ...)
1723 va_list ap;
1724 va_start(ap, fmt);
1725 int_reply(n, "-", fmt, ap);
1726 va_end(ap);
1729 void
1730 nreply(const char *fmt, ...)
1732 va_list ap;
1733 va_start(ap, fmt);
1734 int_reply(0, NULL, fmt, ap);
1735 va_end(ap);
1738 static void
1739 ack(char *s)
1742 reply(250, "%s command successful.", s);
1745 void
1746 nack(char *s)
1749 reply(502, "%s command not implemented.", s);
1752 void
1753 do_delete(char *name)
1755 struct stat st;
1757 LOGCMD("delete", name);
1758 if (stat(name, &st) < 0) {
1759 perror_reply(550, name);
1760 return;
1762 if ((st.st_mode&S_IFMT) == S_IFDIR) {
1763 if (rmdir(name) < 0) {
1764 perror_reply(550, name);
1765 return;
1767 goto done;
1769 if (unlink(name) < 0) {
1770 perror_reply(550, name);
1771 return;
1773 done:
1774 ack("DELE");
1777 void
1778 cwd(char *path)
1781 if (chdir(path) < 0)
1782 perror_reply(550, path);
1783 else
1784 ack("CWD");
1787 void
1788 makedir(char *name)
1791 LOGCMD("mkdir", name);
1792 if(guest && filename_check(name))
1793 return;
1794 if (mkdir(name, 0777) < 0)
1795 perror_reply(550, name);
1796 else{
1797 if(guest)
1798 chmod(name, 0700); /* guest has umask 777 */
1799 reply(257, "MKD command successful.");
1803 void
1804 removedir(char *name)
1807 LOGCMD("rmdir", name);
1808 if (rmdir(name) < 0)
1809 perror_reply(550, name);
1810 else
1811 ack("RMD");
1814 void
1815 pwd(void)
1817 char path[MaxPathLen];
1818 char *ret;
1820 /* SunOS has a broken getcwd that does popen(pwd) (!!!), this
1821 * failes miserably when running chroot
1823 ret = getcwd(path, sizeof(path));
1824 if (ret == NULL)
1825 reply(550, "%s.", strerror(errno));
1826 else
1827 reply(257, "\"%s\" is current directory.", path);
1830 char *
1831 renamefrom(char *name)
1833 struct stat st;
1835 if (stat(name, &st) < 0) {
1836 perror_reply(550, name);
1837 return NULL;
1839 reply(350, "File exists, ready for destination name");
1840 return (name);
1843 void
1844 renamecmd(char *from, char *to)
1847 LOGCMD2("rename", from, to);
1848 if(guest && filename_check(to))
1849 return;
1850 if (rename(from, to) < 0)
1851 perror_reply(550, "rename");
1852 else
1853 ack("RNTO");
1856 static void
1857 dolog(struct sockaddr *sa, int len)
1859 getnameinfo_verified (sa, len, remotehost, sizeof(remotehost),
1860 NULL, 0, 0);
1861 #ifdef HAVE_SETPROCTITLE
1862 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1863 setproctitle("%s", proctitle);
1864 #endif /* HAVE_SETPROCTITLE */
1866 if (logging) {
1867 char data_addr[256];
1869 if (inet_ntop (his_addr->sa_family,
1870 socket_get_address(his_addr),
1871 data_addr, sizeof(data_addr)) == NULL)
1872 strlcpy (data_addr, "unknown address",
1873 sizeof(data_addr));
1876 syslog(LOG_INFO, "connection from %s(%s)",
1877 remotehost,
1878 data_addr);
1883 * Record logout in wtmp file
1884 * and exit with supplied status.
1886 void
1887 dologout(int status)
1889 transflag = 0;
1890 urgflag = 0;
1891 if (logged_in) {
1892 seteuid((uid_t)0);
1893 ftpd_logwtmp(ttyline, "", "");
1894 #ifdef KRB4
1895 cond_kdestroy();
1896 #endif
1898 /* beware of flushing buffers after a SIGPIPE */
1899 #ifdef XXX
1900 exit(status);
1901 #else
1902 _exit(status);
1903 #endif
1906 void abor(void)
1908 if (!transflag)
1909 return;
1910 reply(426, "Transfer aborted. Data connection closed.");
1911 reply(226, "Abort successful");
1912 transflag = 0;
1915 static void
1916 myoob(int signo)
1918 urgflag = 1;
1921 static char *
1922 mec_space(char *p)
1924 while(isspace(*(unsigned char *)p))
1925 p++;
1926 return p;
1929 static int
1930 handleoobcmd(void)
1932 char *cp;
1934 /* only process if transfer occurring */
1935 if (!transflag)
1936 return 0;
1938 urgflag = 0;
1940 cp = tmpline;
1941 if (ftpd_getline(cp, sizeof(tmpline)) == NULL) {
1942 reply(221, "You could at least say goodbye.");
1943 dologout(0);
1946 if (strncasecmp("MIC", cp, 3) == 0) {
1947 mec(mec_space(cp + 3), prot_safe);
1948 } else if (strncasecmp("CONF", cp, 4) == 0) {
1949 mec(mec_space(cp + 4), prot_confidential);
1950 } else if (strncasecmp("ENC", cp, 3) == 0) {
1951 mec(mec_space(cp + 3), prot_private);
1952 } else if (!allow_insecure_oob) {
1953 reply(533, "Command protection level denied "
1954 "for paranoid reasons.");
1955 goto out;
1958 if (secure_command())
1959 cp = ftp_command;
1961 if (strcasecmp(cp, "ABOR\r\n") == 0) {
1962 abor();
1963 } else if (strcasecmp(cp, "STAT\r\n") == 0) {
1964 if (file_size != (off_t) -1)
1965 reply(213, "Status: %ld of %ld bytes transferred",
1966 (long)byte_count,
1967 (long)file_size);
1968 else
1969 reply(213, "Status: %ld bytes transferred",
1970 (long)byte_count);
1972 out:
1973 return (transflag == 0);
1977 * Note: a response of 425 is not mentioned as a possible response to
1978 * the PASV command in RFC959. However, it has been blessed as
1979 * a legitimate response by Jon Postel in a telephone conversation
1980 * with Rick Adams on 25 Jan 89.
1982 void
1983 pasv(void)
1985 socklen_t len;
1986 char *p, *a;
1987 struct sockaddr_in *sin;
1989 if (ctrl_addr->sa_family != AF_INET) {
1990 reply(425,
1991 "You cannot do PASV with something that's not IPv4");
1992 return;
1995 if(pdata != -1)
1996 close(pdata);
1998 pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
1999 if (pdata < 0) {
2000 perror_reply(425, "Can't open passive connection");
2001 return;
2003 pasv_addr->sa_family = ctrl_addr->sa_family;
2004 socket_set_address_and_port (pasv_addr,
2005 socket_get_address (ctrl_addr),
2007 socket_set_portrange(pdata, restricted_data_ports,
2008 pasv_addr->sa_family);
2009 seteuid(0);
2010 if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
2011 seteuid(pw->pw_uid);
2012 goto pasv_error;
2014 seteuid(pw->pw_uid);
2015 len = sizeof(pasv_addr_ss);
2016 if (getsockname(pdata, pasv_addr, &len) < 0)
2017 goto pasv_error;
2018 if (listen(pdata, 1) < 0)
2019 goto pasv_error;
2020 sin = (struct sockaddr_in *)pasv_addr;
2021 a = (char *) &sin->sin_addr;
2022 p = (char *) &sin->sin_port;
2024 #define UC(b) (((int) b) & 0xff)
2026 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2027 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2028 return;
2030 pasv_error:
2031 close(pdata);
2032 pdata = -1;
2033 perror_reply(425, "Can't open passive connection");
2034 return;
2037 void
2038 epsv(char *proto)
2040 socklen_t len;
2042 pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
2043 if (pdata < 0) {
2044 perror_reply(425, "Can't open passive connection");
2045 return;
2047 pasv_addr->sa_family = ctrl_addr->sa_family;
2048 socket_set_address_and_port (pasv_addr,
2049 socket_get_address (ctrl_addr),
2051 socket_set_portrange(pdata, restricted_data_ports,
2052 pasv_addr->sa_family);
2053 seteuid(0);
2054 if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
2055 seteuid(pw->pw_uid);
2056 goto pasv_error;
2058 seteuid(pw->pw_uid);
2059 len = sizeof(pasv_addr_ss);
2060 if (getsockname(pdata, pasv_addr, &len) < 0)
2061 goto pasv_error;
2062 if (listen(pdata, 1) < 0)
2063 goto pasv_error;
2065 reply(229, "Entering Extended Passive Mode (|||%d|)",
2066 ntohs(socket_get_port (pasv_addr)));
2067 return;
2069 pasv_error:
2070 close(pdata);
2071 pdata = -1;
2072 perror_reply(425, "Can't open passive connection");
2073 return;
2076 void
2077 eprt(char *str)
2079 char *end;
2080 char sep;
2081 int af;
2082 int ret;
2083 int port;
2085 usedefault = 0;
2086 if (pdata >= 0) {
2087 close(pdata);
2088 pdata = -1;
2091 sep = *str++;
2092 if (sep == '\0') {
2093 reply(500, "Bad syntax in EPRT");
2094 return;
2096 af = strtol (str, &end, 0);
2097 if (af == 0 || *end != sep) {
2098 reply(500, "Bad syntax in EPRT");
2099 return;
2101 str = end + 1;
2102 switch (af) {
2103 #ifdef HAVE_IPV6
2104 case 2 :
2105 data_dest->sa_family = AF_INET6;
2106 break;
2107 #endif
2108 case 1 :
2109 data_dest->sa_family = AF_INET;
2110 break;
2111 default :
2112 reply(522, "Network protocol %d not supported, use (1"
2113 #ifdef HAVE_IPV6
2114 ",2"
2115 #endif
2116 ")", af);
2117 return;
2119 end = strchr (str, sep);
2120 if (end == NULL) {
2121 reply(500, "Bad syntax in EPRT");
2122 return;
2124 *end = '\0';
2125 ret = inet_pton (data_dest->sa_family, str,
2126 socket_get_address (data_dest));
2128 if (ret != 1) {
2129 reply(500, "Bad address syntax in EPRT");
2130 return;
2132 str = end + 1;
2133 port = strtol (str, &end, 0);
2134 if (port == 0 || *end != sep) {
2135 reply(500, "Bad port syntax in EPRT");
2136 return;
2138 socket_set_port (data_dest, htons(port));
2139 reply(200, "EPRT command successful.");
2143 * Generate unique name for file with basename "local".
2144 * The file named "local" is already known to exist.
2145 * Generates failure reply on error.
2147 static char *
2148 gunique(char *local)
2150 static char new[MaxPathLen];
2151 struct stat st;
2152 int count;
2153 char *cp;
2155 cp = strrchr(local, '/');
2156 if (cp)
2157 *cp = '\0';
2158 if (stat(cp ? local : ".", &st) < 0) {
2159 perror_reply(553, cp ? local : ".");
2160 return NULL;
2162 if (cp)
2163 *cp = '/';
2164 for (count = 1; count < 100; count++) {
2165 snprintf (new, sizeof(new), "%s.%d", local, count);
2166 if (stat(new, &st) < 0)
2167 return (new);
2169 reply(452, "Unique file name cannot be created.");
2170 return (NULL);
2174 * Format and send reply containing system error number.
2176 void
2177 perror_reply(int code, const char *string)
2179 reply(code, "%s: %s.", string, strerror(errno));
2182 static char *onefile[] = {
2187 void
2188 list_file(char *file)
2190 if(use_builtin_ls) {
2191 FILE *dout;
2192 dout = dataconn(file, -1, "w");
2193 if (dout == NULL)
2194 return;
2195 set_buffer_size(fileno(dout), 0);
2196 if(builtin_ls(dout, file) == 0)
2197 reply(226, "Transfer complete.");
2198 else
2199 reply(451, "Requested action aborted. Local error in processing.");
2200 fclose(dout);
2201 data = -1;
2202 pdata = -1;
2203 } else {
2204 #ifdef HAVE_LS_A
2205 const char *cmd = "/bin/ls -lA %s";
2206 #else
2207 const char *cmd = "/bin/ls -la %s";
2208 #endif
2209 retrieve(cmd, file);
2213 void
2214 send_file_list(char *whichf)
2216 struct stat st;
2217 DIR *dirp = NULL;
2218 struct dirent *dir;
2219 FILE *dout = NULL;
2220 char **dirlist, *dirname;
2221 int simple = 0;
2222 int freeglob = 0;
2223 glob_t gl;
2224 char buf[MaxPathLen];
2226 if (strpbrk(whichf, "~{[*?") != NULL) {
2227 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
2228 #ifdef GLOB_MAXPATH
2229 GLOB_MAXPATH
2230 #else
2231 GLOB_LIMIT
2232 #endif
2235 memset(&gl, 0, sizeof(gl));
2236 freeglob = 1;
2237 if (glob(whichf, flags, 0, &gl)) {
2238 reply(550, "not found");
2239 goto out;
2240 } else if (gl.gl_pathc == 0) {
2241 errno = ENOENT;
2242 perror_reply(550, whichf);
2243 goto out;
2245 dirlist = gl.gl_pathv;
2246 } else {
2247 onefile[0] = whichf;
2248 dirlist = onefile;
2249 simple = 1;
2252 while ((dirname = *dirlist++)) {
2254 if (urgflag && handleoobcmd())
2255 goto out;
2257 if (stat(dirname, &st) < 0) {
2259 * If user typed "ls -l", etc, and the client
2260 * used NLST, do what the user meant.
2262 if (dirname[0] == '-' && *dirlist == NULL &&
2263 transflag == 0) {
2264 list_file(dirname);
2265 goto out;
2267 perror_reply(550, whichf);
2268 goto out;
2271 if (S_ISREG(st.st_mode)) {
2272 if (dout == NULL) {
2273 dout = dataconn("file list", (off_t)-1, "w");
2274 if (dout == NULL)
2275 goto out;
2276 transflag = 1;
2278 snprintf(buf, sizeof(buf), "%s%s\n", dirname,
2279 type == TYPE_A ? "\r" : "");
2280 sec_write(fileno(dout), buf, strlen(buf));
2281 byte_count += strlen(dirname) + 1;
2282 continue;
2283 } else if (!S_ISDIR(st.st_mode))
2284 continue;
2286 if ((dirp = opendir(dirname)) == NULL)
2287 continue;
2289 while ((dir = readdir(dirp)) != NULL) {
2290 char nbuf[MaxPathLen];
2292 if (urgflag && handleoobcmd())
2293 goto out;
2295 if (!strcmp(dir->d_name, "."))
2296 continue;
2297 if (!strcmp(dir->d_name, ".."))
2298 continue;
2300 snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
2303 * We have to do a stat to insure it's
2304 * not a directory or special file.
2306 if (simple || (stat(nbuf, &st) == 0 &&
2307 S_ISREG(st.st_mode))) {
2308 if (dout == NULL) {
2309 dout = dataconn("file list", (off_t)-1, "w");
2310 if (dout == NULL)
2311 goto out;
2312 transflag = 1;
2314 if(strncmp(nbuf, "./", 2) == 0)
2315 snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
2316 type == TYPE_A ? "\r" : "");
2317 else
2318 snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
2319 type == TYPE_A ? "\r" : "");
2320 sec_write(fileno(dout), buf, strlen(buf));
2321 byte_count += strlen(nbuf) + 1;
2324 closedir(dirp);
2326 if (dout == NULL)
2327 reply(550, "No files found.");
2328 else if (ferror(dout) != 0)
2329 perror_reply(550, "Data connection");
2330 else
2331 reply(226, "Transfer complete.");
2333 out:
2334 transflag = 0;
2335 if (dout != NULL){
2336 sec_write(fileno(dout), buf, 0); /* XXX flush */
2338 fclose(dout);
2340 data = -1;
2341 pdata = -1;
2342 if (freeglob) {
2343 freeglob = 0;
2344 globfree(&gl);
2350 find(char *pattern)
2352 char line[1024];
2353 FILE *f;
2355 snprintf(line, sizeof(line),
2356 "/bin/locate -d %s -- %s",
2357 ftp_rooted("/etc/locatedb"),
2358 pattern);
2359 f = ftpd_popen(line, "r", 1, 1);
2360 if(f == NULL){
2361 perror_reply(550, "/bin/locate");
2362 return 1;
2364 lreply(200, "Output from find.");
2365 while(fgets(line, sizeof(line), f)){
2366 if(line[strlen(line)-1] == '\n')
2367 line[strlen(line)-1] = 0;
2368 nreply("%s", line);
2370 reply(200, "Done");
2371 ftpd_pclose(f);
2372 return 0;