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