Add heimdal-0.6.3
[dragonfly.git] / crypto / heimdal-0.6.3 / 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
34 #define FTP_NAMES
35 #include "ftpd_locl.h"
36 #ifdef KRB5
37 #include <krb5.h>
38 #endif
39 #include "getarg.h"
40
41 RCSID("$Id: ftpd.c,v 1.166.2.3 2004/08/20 15:16:37 lha Exp $");
42
43 static char version[] = "Version 6.00";
44
45 extern  off_t restart_point;
46 extern  char cbuf[];
47
48 struct  sockaddr_storage ctrl_addr_ss;
49 struct  sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss;
50
51 struct  sockaddr_storage data_source_ss;
52 struct  sockaddr *data_source = (struct sockaddr *)&data_source_ss;
53
54 struct  sockaddr_storage data_dest_ss;
55 struct  sockaddr *data_dest = (struct sockaddr *)&data_dest_ss;
56
57 struct  sockaddr_storage his_addr_ss;
58 struct  sockaddr *his_addr = (struct sockaddr *)&his_addr_ss;
59
60 struct  sockaddr_storage pasv_addr_ss;
61 struct  sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
62
63 int     data;
64 int     logged_in;
65 struct  passwd *pw;
66 int     debug = 0;
67 int     ftpd_timeout = 900;    /* timeout after 15 minutes of inactivity */
68 int     maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
69 int     restricted_data_ports = 1;
70 int     logging;
71 int     guest;
72 int     dochroot;
73 int     type;
74 int     form;
75 int     stru;                   /* avoid C keyword */
76 int     mode;
77 int     usedefault = 1;         /* for data transfers */
78 int     pdata = -1;             /* for passive mode */
79 int     allow_insecure_oob = 1;
80 static int transflag;
81 static int urgflag;
82 off_t   file_size;
83 off_t   byte_count;
84 #if !defined(CMASK) || CMASK == 0
85 #undef CMASK
86 #define CMASK 027
87 #endif
88 int     defumask = CMASK;               /* default umask value */
89 int     guest_umask = 0777;     /* Paranoia for anonymous users */
90 char    tmpline[10240];
91 char    hostname[MaxHostNameLen];
92 char    remotehost[MaxHostNameLen];
93 static char ttyline[20];
94
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 */
98
99 static int auth_level = 0; /* Only allow kerberos login by default */
100
101 /*
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...
105  */
106 #define SWAITMAX        90      /* wait at most 90 seconds */
107 #define SWAITINT        5       /* interval between retries */
108
109 int     swaitmax = SWAITMAX;
110 int     swaitint = SWAITINT;
111
112 #ifdef HAVE_SETPROCTITLE
113 char    proctitle[BUFSIZ];      /* initial part of title */
114 #endif /* HAVE_SETPROCTITLE */
115
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); \
133         }
134
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 *);
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 static const char *good_chars = "+-=_,.";
212
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 }
233 };
234
235 static int num_args = sizeof(args) / sizeof(args[0]);
236
237 static void
238 usage (int code)
239 {
240     arg_printusage(args, num_args, NULL, "");
241     exit (code);
242 }
243
244 /* output contents of a file */
245 static int
246 show_file(const char *file, int code)
247 {
248     FILE *f;
249     char buf[128];
250
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);
257     }
258     fclose(f);
259     return 0;
260 }
261
262 int
263 main(int argc, char **argv)
264 {
265     socklen_t his_addr_len, ctrl_addr_len;
266     int on = 1;
267     int port;
268     struct servent *sp;
269
270     int optind = 0;
271
272     setprogname (argv[0]);
273
274     /* detach from any tickets and tokens */
275     {
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
282     }
283 #if defined(KRB4) || defined(KRB5)
284     if(k_hasafs())
285         k_setpag();
286 #endif
287
288     if(getarg(args, num_args, argc, argv, &optind))
289         usage(1);
290
291     if(help_flag)
292         usage(0);
293         
294     if(version_flag) {
295         print_version(NULL);
296         exit(0);
297     }
298
299     if(auth_string)
300         auth_level = parse_auth_level(auth_string);
301     {
302         char *p;
303         long val = 0;
304             
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;
311         }
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;
318         }
319     }
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");
334     }
335                     
336     if (maxtimeout < ftpd_timeout)
337         maxtimeout = ftpd_timeout;
338
339 #if 0
340     if (ftpd_timeout > maxtimeout)
341         ftpd_timeout = maxtimeout;
342 #endif
343
344     if(interactive_flag)
345         mini_inetd (port);
346
347     /*
348      * LOG_NDELAY sets up the logging connection immediately,
349      * necessary for anonymous ftp's that chroot and can't do it later.
350      */
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);
356     }
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);
361     }
362 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
363     {
364         int tos = IPTOS_LOWDELAY;
365
366         if (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS,
367                        (void *)&tos, sizeof(int)) < 0)
368             syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
369     }
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));
374
375     /* set this here so it can be put in wtmp */
376     snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
377
378
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
386
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
393
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);
399     /*
400      * Set up default state
401      */
402     data = -1;
403     type = TYPE_A;
404     form = FORM_N;
405     stru = STRU_F;
406     mode = MODE_S;
407     tmpline[0] = '\0';
408
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);
413     }
414     show_file(_PATH_FTPWELCOME, 220);
415     /* reply(220,) must follow */
416     gethostname(hostname, sizeof(hostname));
417         
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
432           );
433
434     for (;;)
435         yyparse();
436     /* NOTREACHED */
437 }
438
439 static RETSIGTYPE
440 lostconn(int signo)
441 {
442
443         if (debug)
444                 syslog(LOG_DEBUG, "lost connection");
445         dologout(-1);
446 }
447
448 /*
449  * Helper function for sgetpwnam().
450  */
451 static char *
452 sgetsave(char *s)
453 {
454         char *new = strdup(s);
455
456         if (new == NULL) {
457                 perror_reply(421, "Local resource failure: malloc");
458                 dologout(1);
459                 /* NOTREACHED */
460         }
461         return new;
462 }
463
464 /*
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).
468  */
469 static struct passwd *
470 sgetpwnam(char *name)
471 {
472         static struct passwd save;
473         struct passwd *p;
474
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);
483         }
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);
491 }
492
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
499
500 /*
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.
510  */
511 void
512 user(char *name)
513 {
514         char *cp, *shell;
515
516         if(auth_level == 0 && !sec_complete){
517             reply(530, "No login allowed without authorization.");
518             return;
519         }
520
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;
528                 }
529                 end_login();
530         }
531
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];
547
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));
553
554                 syslog(LOG_NOTICE,
555                        "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
556                        remotehost, data_addr);
557             }
558             return;
559         }
560         if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
561             reply(530, "Only authorized and anonymous login allowed.");
562             return;
563         }
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();
571
572                 if (cp == NULL || checkaccess(name)) {
573                         reply(530, "User %s access denied.", name);
574                         if (logging) {
575                                 char data_addr[256];
576
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));
584
585                                 syslog(LOG_NOTICE,
586                                        "FTP LOGIN REFUSED FROM %s(%s), %s",
587                                        remotehost,
588                                        data_addr,
589                                        name);
590                         }
591                         pw = (struct passwd *) NULL;
592                         return;
593                 }
594         }
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];
604
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;
617                     
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.");
628                 }
629
630         }
631         /*
632          * Delay before reading passwd after first failed
633          * attempt to slow down passwd-guessing programs.
634          */
635         if (login_attempts)
636                 sleep(login_attempts);
637 }
638
639 /*
640  * Check if a user is in the file "fname"
641  */
642 static int
643 checkuser(char *fname, char *name)
644 {
645         FILE *fd;
646         int found = 0;
647         char *p, line[BUFSIZ];
648
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;
658                                 }
659                         }
660                 fclose(fd);
661         }
662         return (found);
663 }
664
665
666 /*
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.
671  *
672  * If the user is not found in the file, but the pseudo-user `*' is,
673  * the permission is taken from that line.
674  *
675  * This preserves the old semantics where if a user was listed in the
676  * file he was denied, otherwise he was allowed.
677  *
678  * Return 1 if the user is denied, or 0 if he is allowed.  */
679
680 static int
681 match(const char *pattern, const char *string)
682 {
683     return fnmatch(pattern, string, FNM_NOESCAPE);
684 }
685
686 static int
687 checkaccess(char *name)
688 {
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;
695     
696     fd = fopen(_PATH_FTPUSERS, "r");
697     
698     if(fd == NULL)
699         return allowed;
700
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;
713         }
714     }
715     fclose(fd);
716     return allowed;
717 }
718 #undef  ALLOWED
719 #undef  NOT_ALLOWED
720
721
722 int do_login(int code, char *passwd)
723 {
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;
728     }
729     initgroups(pw->pw_name, pw->pw_gid);
730
731     /* open wtmp before chroot */
732     ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
733     logged_in = 1;
734
735     dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
736     if (guest) {
737         /*
738          * We MUST do a chdir() after the chroot. Otherwise
739          * the old current directory will be accessible as "."
740          * outside the new root!
741          */
742         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
743             reply(550, "Can't set guest privileges.");
744             return -1;
745         }
746     } else if (dochroot) {
747         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
748             reply(550, "Can't change root.");
749             return -1;
750         }
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=/");
758     }
759     if (seteuid((uid_t)pw->pw_uid) < 0) {
760         reply(550, "Can't set uid.");
761         return -1;
762     }
763
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;
773     }
774
775     /*
776      * Display a login message, if it exists.
777      * N.B. reply(code,) must follow the message.
778      */
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];
793
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));
799
800             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
801                    remotehost, 
802                    data_addr,
803                    passwd);
804         }
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];
813
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));
819
820             syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
821                    remotehost,
822                    data_addr,
823                    pw->pw_name);
824         }
825     }
826     umask(defumask);
827     return 0;
828 }
829
830 /*
831  * Terminate login as previous user, if any, resetting state;
832  * used when USER command is given or login fails.
833  */
834 static void
835 end_login(void)
836 {
837
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;
845 }
846
847 #ifdef KRB5
848 static int
849 krb5_verify(struct passwd *pwd, char *passwd)
850 {
851    krb5_context context;  
852    krb5_ccache  id;
853    krb5_principal princ;
854    krb5_error_code ret;
855   
856    ret = krb5_init_context(&context);
857    if(ret)
858         return ret;
859
860   ret = krb5_parse_name(context, pwd->pw_name, &princ);
861   if(ret){
862         krb5_free_context(context);
863         return ret;
864   }
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;
870   }
871   ret = krb5_verify_user(context,
872                          princ,
873                          id,
874                          passwd,
875                          1,
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);
880   }
881   krb5_cc_destroy(context, id);
882   krb5_free_context (context);
883   if(ret) 
884       return ret;
885   return 0;
886 }
887 #endif /* KRB5 */
888
889 void
890 pass(char *passwd)
891 {
892         int rval;
893
894         /* some clients insists on sending a password */
895         if (logged_in && askpasswd == 0){
896             reply(230, "Password not necessary");
897             return;
898         }
899
900         if (logged_in || askpasswd == 0) {
901                 reply(503, "Login with USER first.");
902                 return;
903         }
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;
912                 }
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);
930                         }
931                     }
932 #endif
933                     if (rval)
934                         rval = unix_verify_user(pw->pw_name, passwd);
935                 } else {
936                     char *s;
937                     
938 #ifdef OTP
939                     if ((s = otp_error(&otp_ctx)) != NULL)
940                         lreply(530, "OTP: %s", s);
941 #endif
942                 }
943                 memset (passwd, 0, strlen(passwd));
944
945                 /*
946                  * If rval == 1, the user failed the authentication
947                  * check above.  If rval == 0, either Kerberos or
948                  * local authentication succeeded.
949                  */
950                 if (rval) {
951                         char data_addr[256];
952
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));
958
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);
973                         }
974                         return;
975                 }
976         }
977         if(!do_login(230, passwd))
978           return;
979         
980         /* Forget all about it... */
981         end_login();
982 }
983
984 void
985 retrieve(const char *cmd, char *name)
986 {
987         FILE *fin = NULL, *dout;
988         struct stat st;
989         int (*closefunc) (FILE *);
990         char line[BUFSIZ];
991
992
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}
1010                     };
1011                     struct cmds *p;
1012                     for(p = cmds; p->ext; p++){
1013                         char *tail = name + strlen(name) - strlen(p->ext);
1014                         char c = *tail;
1015                         
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;
1022                         }
1023                         *tail = c;
1024                         if (p->rev_cmd != NULL) {
1025                             char *ext;
1026
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;
1034                                 }
1035                                 free(ext);
1036                             }
1037                         }
1038                         
1039                     }
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;
1047                 }
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;
1054         }
1055         if (fin == NULL) {
1056                 if (errno != 0) {
1057                         perror_reply(550, name);
1058                         if (cmd == 0) {
1059                                 LOGCMD("get", name);
1060                         }
1061                 }
1062                 return;
1063         }
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;
1069             }
1070         }
1071         if (restart_point) {
1072                 if (type == TYPE_A) {
1073                         off_t i, n;
1074                         int c;
1075
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;
1082                                 }
1083                                 if (c == '\n')
1084                                         i++;
1085                         }
1086                 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1087                         perror_reply(550, name);
1088                         goto done;
1089                 }
1090         }
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);
1103 }
1104
1105 /* filename sanity check */
1106
1107 int 
1108 filename_check(char *filename)
1109 {
1110     unsigned char *p;
1111
1112     p = (unsigned char *)strrchr(filename, '/');
1113     if(p)
1114         filename = p + 1;
1115
1116     p = filename;
1117
1118     if(isalnum(*p)){
1119         p++;
1120         while(*p && (isalnum(*p) || strchr(good_chars, *p)))
1121             p++;
1122         if(*p == '\0')
1123             return 0;
1124     }
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;
1131 }
1132
1133 void
1134 do_store(char *name, char *mode, int unique)
1135 {
1136         FILE *fout, *din;
1137         struct stat st;
1138         int (*closefunc) (FILE *);
1139
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;
1146         }
1147
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;
1156         }
1157         byte_count = -1;
1158         if (restart_point) {
1159                 if (type == TYPE_A) {
1160                         off_t i, n;
1161                         int c;
1162
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;
1169                                 }
1170                                 if (c == '\n')
1171                                         i++;
1172                         }
1173                         /*
1174                          * We must do this seek to "current" position
1175                          * because we are changing from reading to
1176                          * writing.
1177                          */
1178                         if (fseek(fout, 0L, SEEK_CUR) < 0) {
1179                                 perror_reply(550, name);
1180                                 goto done;
1181                         }
1182                 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1183                         perror_reply(550, name);
1184                         goto done;
1185                 }
1186         }
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.");
1200             }
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);
1208 }
1209
1210 static FILE *
1211 getdatasock(const char *mode)
1212 {
1213         int s, t, tries;
1214
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));
1226
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);
1234         }
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);
1247 }
1248
1249 static int
1250 accept_with_timeout(int socket, 
1251                     struct sockaddr *address,
1252                     socklen_t *address_len,
1253                     struct timeval *timeout)
1254 {
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;
1265     }
1266     return accept(socket, address, address_len);
1267 }
1268
1269 static FILE *
1270 dataconn(const char *name, off_t size, const char *mode)
1271 {
1272         char sizebuf[32];
1273         FILE *file;
1274         int retry = 0;
1275
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);
1288
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);
1297                 }
1298                 close(pdata);
1299                 pdata = s;
1300 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
1301                 {
1302                     int tos = IPTOS_THROUGHPUT;
1303                     
1304                     setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&tos,
1305                                sizeof(tos));
1306                 }
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));
1311         }
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));
1317         }
1318         if (usedefault)
1319                 data_dest = his_addr;
1320         usedefault = 1;
1321         file = getdatasock(mode);
1322         if (file == NULL) {
1323                 char data_addr[256];
1324
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));
1330
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);
1336         }
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;
1344                 }
1345                 perror_reply(425, "Can't build data connection");
1346                 fclose(file);
1347                 data = -1;
1348                 return (NULL);
1349         }
1350         reply(150, "Opening %s mode data connection for '%s'%s.",
1351              type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1352         return (file);
1353 }
1354
1355 /*
1356  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1357  * encapsulation of the data subject * to Mode, Structure, and Type.
1358  *
1359  * NB: Form isn't handled.
1360  */
1361 static void
1362 send_data(FILE *instr, FILE *outstr)
1363 {
1364         int c, cnt, filefd, netfd;
1365         static char *buf;
1366         static size_t bufsize;
1367
1368         transflag = 1;
1369         switch (type) {
1370
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);
1379             }
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;
1389                 
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
1397             {
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) {
1403                     /*
1404                      * mmap zero bytes has potential of loosing, don't do it.
1405                      */
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;
1417                     }
1418                 }
1419             }
1420 #endif
1421 #endif
1422         if(transflag) {
1423             struct stat st;
1424
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;
1434             }
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;
1440             }
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;
1448             }
1449         }
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;
1457         }
1458
1459 data_err:
1460         transflag = 0;
1461         urgflag = 0;
1462         perror_reply(426, "Data connection");
1463         return;
1464
1465 file_err:
1466         transflag = 0;
1467         urgflag = 0;
1468         perror_reply(551, "Error on input file");
1469 }
1470
1471 /*
1472  * Transfer data from peer to "outstr" using the appropriate encapulation of
1473  * the data subject to Mode, Structure, and Type.
1474  *
1475  * N.B.: Form isn't handled.
1476  */
1477 static int
1478 receive_data(FILE *instr, FILE *outstr)
1479 {
1480     int cnt, bare_lfs = 0;
1481     static char *buf;
1482     static size_t bufsize;
1483     struct stat st;
1484
1485     transflag = 1;
1486
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;
1494     }
1495     
1496     switch (type) {
1497
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);
1506         }
1507         if (cnt < 0)
1508             goto data_err;
1509         transflag = 0;
1510         urgflag = 0;
1511         return (0);
1512
1513     case TYPE_E:
1514         reply(553, "TYPE E not implemented.");
1515         transflag = 0;
1516         urgflag = 0;
1517         return (-1);
1518
1519     case TYPE_A:
1520     {
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;
1543                     }
1544                 }
1545                 *q++ = *p++;
1546             }
1547             fwrite(buf, q - buf, 1, outstr);
1548             if(cr_flag)
1549                 buf[0] = '\r';
1550         }
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);
1564         }
1565         return (0);
1566     }
1567     default:
1568         reply(550, "Unimplemented TYPE %d in receive_data", type);
1569         transflag = 0;
1570         urgflag = 0;
1571         return (-1);
1572     }
1573         
1574 data_err:
1575     transflag = 0;
1576     urgflag = 0;
1577     perror_reply(426, "Data Connection");
1578     return (-1);
1579         
1580 file_err:
1581     transflag = 0;
1582     urgflag = 0;
1583     perror_reply(452, "Error writing file");
1584     return (-1);
1585 }
1586
1587 void
1588 statfilecmd(char *filename)
1589 {
1590         FILE *fin;
1591         int c;
1592         char line[LINE_MAX];
1593
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 */
1604                         }
1605                         if (ferror(fin)) {
1606                                 perror_reply(551, filename);
1607                                 ftpd_pclose(fin);
1608                                 return;
1609                         }
1610                         putc('\r', stdout);
1611                 }
1612                 putc(c, stdout);
1613         }
1614         ftpd_pclose(fin);
1615         reply(211, "End of Status");
1616 }
1617
1618 void
1619 statcmd(void)
1620 {
1621 #if 0
1622         struct sockaddr_in *sin;
1623         u_char *a, *p;
1624
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");
1671 }
1672
1673 void
1674 fatal(char *s)
1675 {
1676
1677         reply(451, "Error in server: %s\n", s);
1678         reply(221, "Closing connection due to server error.");
1679         dologout(0);
1680         /* NOTREACHED */
1681 }
1682
1683 static void
1684 int_reply(int, char *, const char *, va_list)
1685 #ifdef __GNUC__
1686 __attribute__ ((format (printf, 3, 0)))
1687 #endif
1688 ;
1689
1690 static void
1691 int_reply(int n, char *c, const char *fmt, va_list ap)
1692 {
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);
1699     }
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);
1708 }
1709
1710 void
1711 reply(int n, const char *fmt, ...)
1712 {
1713   va_list ap;
1714   va_start(ap, fmt);
1715   int_reply(n, " ", fmt, ap);
1716   delete_ftp_command();
1717   va_end(ap);
1718 }
1719
1720 void
1721 lreply(int n, const char *fmt, ...)
1722 {
1723   va_list ap;
1724   va_start(ap, fmt);
1725   int_reply(n, "-", fmt, ap);
1726   va_end(ap);
1727 }
1728
1729 void
1730 nreply(const char *fmt, ...)
1731 {
1732   va_list ap;
1733   va_start(ap, fmt);
1734   int_reply(0, NULL, fmt, ap);
1735   va_end(ap);
1736 }
1737
1738 static void
1739 ack(char *s)
1740 {
1741
1742         reply(250, "%s command successful.", s);
1743 }
1744
1745 void
1746 nack(char *s)
1747 {
1748
1749         reply(502, "%s command not implemented.", s);
1750 }
1751
1752 void
1753 do_delete(char *name)
1754 {
1755         struct stat st;
1756
1757         LOGCMD("delete", name);
1758         if (stat(name, &st) < 0) {
1759                 perror_reply(550, name);
1760                 return;
1761         }
1762         if ((st.st_mode&S_IFMT) == S_IFDIR) {
1763                 if (rmdir(name) < 0) {
1764                         perror_reply(550, name);
1765                         return;
1766                 }
1767                 goto done;
1768         }
1769         if (unlink(name) < 0) {
1770                 perror_reply(550, name);
1771                 return;
1772         }
1773 done:
1774         ack("DELE");
1775 }
1776
1777 void
1778 cwd(char *path)
1779 {
1780
1781         if (chdir(path) < 0)
1782                 perror_reply(550, path);
1783         else
1784                 ack("CWD");
1785 }
1786
1787 void
1788 makedir(char *name)
1789 {
1790
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.");
1800         }
1801 }
1802
1803 void
1804 removedir(char *name)
1805 {
1806
1807         LOGCMD("rmdir", name);
1808         if (rmdir(name) < 0)
1809                 perror_reply(550, name);
1810         else
1811                 ack("RMD");
1812 }
1813
1814 void
1815 pwd(void)
1816 {
1817     char path[MaxPathLen];
1818     char *ret;
1819
1820     /* SunOS has a broken getcwd that does popen(pwd) (!!!), this
1821      * failes miserably when running chroot 
1822      */
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);
1828 }
1829
1830 char *
1831 renamefrom(char *name)
1832 {
1833         struct stat st;
1834
1835         if (stat(name, &st) < 0) {
1836                 perror_reply(550, name);
1837                 return NULL;
1838         }
1839         reply(350, "File exists, ready for destination name");
1840         return (name);
1841 }
1842
1843 void
1844 renamecmd(char *from, char *to)
1845 {
1846
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");
1854 }
1855
1856 static void
1857 dolog(struct sockaddr *sa, int len)
1858 {
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 */
1865
1866         if (logging) {
1867                 char data_addr[256];
1868
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));
1874
1875
1876                 syslog(LOG_INFO, "connection from %s(%s)",
1877                        remotehost,
1878                        data_addr);
1879         }
1880 }
1881
1882 /*
1883  * Record logout in wtmp file
1884  * and exit with supplied status.
1885  */
1886 void
1887 dologout(int status)
1888 {
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
1897     }
1898     /* beware of flushing buffers after a SIGPIPE */
1899 #ifdef XXX
1900     exit(status);
1901 #else
1902     _exit(status);
1903 #endif  
1904 }
1905
1906 void abor(void)
1907 {
1908     if (!transflag)
1909         return;
1910     reply(426, "Transfer aborted. Data connection closed.");
1911     reply(226, "Abort successful");
1912     transflag = 0;
1913 }
1914
1915 static void
1916 myoob(int signo)
1917 {
1918     urgflag = 1;
1919 }
1920
1921 static char *
1922 mec_space(char *p)
1923 {
1924     while(isspace(*(unsigned char *)p))
1925           p++;
1926     return p;
1927 }
1928
1929 static int
1930 handleoobcmd(void)
1931 {
1932         char *cp;
1933
1934         /* only process if transfer occurring */
1935         if (!transflag)
1936                 return 0;
1937
1938         urgflag = 0;
1939
1940         cp = tmpline;
1941         if (ftpd_getline(cp, sizeof(tmpline)) == NULL) {
1942                 reply(221, "You could at least say goodbye.");
1943                 dologout(0);
1944         }
1945
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;
1956         }
1957
1958         if (secure_command())
1959             cp = ftp_command;
1960
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);
1971         }
1972 out:
1973         return (transflag == 0);
1974 }
1975
1976 /*
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.
1981  */
1982 void
1983 pasv(void)
1984 {
1985         socklen_t len;
1986         char *p, *a;
1987         struct sockaddr_in *sin;
1988
1989         if (ctrl_addr->sa_family != AF_INET) {
1990                 reply(425,
1991                       "You cannot do PASV with something that's not IPv4");
1992                 return;
1993         }
1994
1995         if(pdata != -1)
1996             close(pdata);
1997
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;
2002         }
2003         pasv_addr->sa_family = ctrl_addr->sa_family;
2004         socket_set_address_and_port (pasv_addr,
2005                                      socket_get_address (ctrl_addr),
2006                                      0);
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;
2013         }
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;
2023
2024 #define UC(b) (((int) b) & 0xff)
2025
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;
2029
2030 pasv_error:
2031         close(pdata);
2032         pdata = -1;
2033         perror_reply(425, "Can't open passive connection");
2034         return;
2035 }
2036
2037 void
2038 epsv(char *proto)
2039 {
2040         socklen_t len;
2041
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;
2046         }
2047         pasv_addr->sa_family = ctrl_addr->sa_family;
2048         socket_set_address_and_port (pasv_addr,
2049                                      socket_get_address (ctrl_addr),
2050                                      0);
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;
2057         }
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;
2064
2065         reply(229, "Entering Extended Passive Mode (|||%d|)",
2066               ntohs(socket_get_port (pasv_addr)));
2067         return;
2068
2069 pasv_error:
2070         close(pdata);
2071         pdata = -1;
2072         perror_reply(425, "Can't open passive connection");
2073         return;
2074 }
2075
2076 void
2077 eprt(char *str)
2078 {
2079         char *end;
2080         char sep;
2081         int af;
2082         int ret;
2083         int port;
2084
2085         usedefault = 0;
2086         if (pdata >= 0) {
2087             close(pdata);
2088             pdata = -1;
2089         }
2090
2091         sep = *str++;
2092         if (sep == '\0') {
2093                 reply(500, "Bad syntax in EPRT");
2094                 return;
2095         }
2096         af = strtol (str, &end, 0);
2097         if (af == 0 || *end != sep) {
2098                 reply(500, "Bad syntax in EPRT");
2099                 return;
2100         }
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;
2118         }
2119         end = strchr (str, sep);
2120         if (end == NULL) {
2121                 reply(500, "Bad syntax in EPRT");
2122                 return;
2123         }
2124         *end = '\0';
2125         ret = inet_pton (data_dest->sa_family, str,
2126                          socket_get_address (data_dest));
2127
2128         if (ret != 1) {
2129                 reply(500, "Bad address syntax in EPRT");
2130                 return;
2131         }
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;
2137         }
2138         socket_set_port (data_dest, htons(port));
2139         reply(200, "EPRT command successful.");
2140 }
2141
2142 /*
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.
2146  */
2147 static char *
2148 gunique(char *local)
2149 {
2150         static char new[MaxPathLen];
2151         struct stat st;
2152         int count;
2153         char *cp;
2154
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;
2161         }
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);
2168         }
2169         reply(452, "Unique file name cannot be created.");
2170         return (NULL);
2171 }
2172
2173 /*
2174  * Format and send reply containing system error number.
2175  */
2176 void
2177 perror_reply(int code, const char *string)
2178 {
2179         reply(code, "%s: %s.", string, strerror(errno));
2180 }
2181
2182 static char *onefile[] = {
2183         "",
2184         0
2185 };
2186
2187 void
2188 list_file(char *file)
2189 {
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);
2210     }
2211 }
2212
2213 void
2214 send_file_list(char *whichf)
2215 {
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];
2225
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
2233             ;
2234
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;
2244         }
2245         dirlist = gl.gl_pathv;
2246     } else {
2247         onefile[0] = whichf;
2248         dirlist = onefile;
2249         simple = 1;
2250     }
2251
2252     while ((dirname = *dirlist++)) {
2253
2254         if (urgflag && handleoobcmd())
2255             goto out;
2256
2257         if (stat(dirname, &st) < 0) {
2258             /*
2259              * If user typed "ls -l", etc, and the client
2260              * used NLST, do what the user meant.
2261              */
2262             if (dirname[0] == '-' && *dirlist == NULL &&
2263                 transflag == 0) {
2264                 list_file(dirname);
2265                 goto out;
2266             }
2267             perror_reply(550, whichf);
2268             goto out;
2269         }
2270
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;
2277             }
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;
2285
2286         if ((dirp = opendir(dirname)) == NULL)
2287             continue;
2288
2289         while ((dir = readdir(dirp)) != NULL) {
2290             char nbuf[MaxPathLen];
2291
2292             if (urgflag && handleoobcmd())
2293                 goto out;
2294
2295             if (!strcmp(dir->d_name, "."))
2296                 continue;
2297             if (!strcmp(dir->d_name, ".."))
2298                 continue;
2299
2300             snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
2301
2302             /*
2303              * We have to do a stat to insure it's
2304              * not a directory or special file.
2305              */
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;
2313                 }
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;
2322             }
2323         }
2324         closedir(dirp);
2325     }
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.");
2332
2333 out:
2334     transflag = 0;
2335     if (dout != NULL){
2336         sec_write(fileno(dout), buf, 0); /* XXX flush */
2337             
2338         fclose(dout);
2339     }
2340     data = -1;
2341     pdata = -1;
2342     if (freeglob) {
2343         freeglob = 0;
2344         globfree(&gl);
2345     }
2346 }
2347
2348
2349 int
2350 find(char *pattern)
2351 {
2352     char line[1024];
2353     FILE *f;
2354
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;
2363     }
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);
2369     }
2370     reply(200, "Done");
2371     ftpd_pclose(f);
2372     return 0;
2373 }
2374