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