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