]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/ftpd/ftpd.c
This commit was generated by cvs2svn to compensate for changes in r96539,
[FreeBSD/FreeBSD.git] / libexec / 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 #if 0
35 #ifndef lint
36 static char copyright[] =
37 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
38         The Regents of the University of California.  All rights reserved.\n";
39 #endif /* not lint */
40 #endif
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)ftpd.c      8.4 (Berkeley) 4/16/94";
45 #endif
46 static const char rcsid[] =
47   "$FreeBSD$";
48 #endif /* not lint */
49
50 /*
51  * FTP server.
52  */
53 #include <sys/param.h>
54 #include <sys/ioctl.h>
55 #include <sys/mman.h>
56 #include <sys/socket.h>
57 #include <sys/stat.h>
58 #include <sys/time.h>
59 #include <sys/wait.h>
60
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #include <netinet/tcp.h>
65
66 #define FTP_NAMES
67 #include <arpa/ftp.h>
68 #include <arpa/inet.h>
69 #include <arpa/telnet.h>
70
71 #include <ctype.h>
72 #include <dirent.h>
73 #include <err.h>
74 #include <errno.h>
75 #include <fcntl.h>
76 #include <glob.h>
77 #include <limits.h>
78 #include <netdb.h>
79 #include <pwd.h>
80 #include <grp.h>
81 #include <opie.h>
82 #include <signal.h>
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <syslog.h>
87 #include <time.h>
88 #include <unistd.h>
89 #include <libutil.h>
90 #ifdef  LOGIN_CAP
91 #include <login_cap.h>
92 #endif
93
94 #ifdef USE_PAM
95 #include <security/pam_appl.h>
96 #endif
97
98 #include "pathnames.h"
99 #include "extern.h"
100
101 #if __STDC__
102 #include <stdarg.h>
103 #else
104 #include <varargs.h>
105 #endif
106
107 static char version[] = "Version 6.00LS";
108 #undef main
109
110 /* wrapper for KAME-special getnameinfo() */
111 #ifndef NI_WITHSCOPEID
112 #define NI_WITHSCOPEID  0
113 #endif
114
115 extern  off_t restart_point;
116 extern  char cbuf[];
117
118 union sockunion server_addr;
119 union sockunion ctrl_addr;
120 union sockunion data_source;
121 union sockunion data_dest;
122 union sockunion his_addr;
123 union sockunion pasv_addr;
124
125 int     daemon_mode;
126 int     data;
127 int     logged_in;
128 struct  passwd *pw;
129 int     ftpdebug;
130 int     timeout = 900;    /* timeout after 15 minutes of inactivity */
131 int     maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
132 int     logging;
133 int     restricted_data_ports = 1;
134 int     paranoid = 1;     /* be extra careful about security */
135 int     anon_only = 0;    /* Only anonymous ftp allowed */
136 int     guest;
137 int     dochroot;
138 int     stats;
139 int     statfd = -1;
140 int     type;
141 int     form;
142 int     stru;                   /* avoid C keyword */
143 int     mode;
144 int     usedefault = 1;         /* for data transfers */
145 int     pdata = -1;             /* for passive mode */
146 int     readonly=0;             /* Server is in readonly mode.  */
147 int     noepsv=0;               /* EPSV command is disabled.    */
148 int     noretr=0;               /* RETR command is disabled.    */
149 int     noguestretr=0;          /* RETR command is disabled for anon users. */
150
151 static volatile sig_atomic_t recvurg;
152 sig_atomic_t transflag;
153 off_t   file_size;
154 off_t   byte_count;
155 #if !defined(CMASK) || CMASK == 0
156 #undef CMASK
157 #define CMASK 027
158 #endif
159 int     defumask = CMASK;               /* default umask value */
160 char    tmpline[7];
161 char    *hostname;
162 int     epsvall = 0;
163
164 #ifdef VIRTUAL_HOSTING
165 char    *ftpuser;
166
167 static struct ftphost {
168         struct ftphost  *next;
169         struct addrinfo *hostinfo;
170         char            *hostname;
171         char            *anonuser;
172         char            *statfile;
173         char            *welcome;
174         char            *loginmsg;
175 } *thishost, *firsthost;
176
177 #endif
178 char    remotehost[MAXHOSTNAMELEN];
179 char    *ident = NULL;
180
181 static char ttyline[20];
182 char    *tty = ttyline;         /* for klogin */
183
184 #ifdef USE_PAM
185 static int      auth_pam(struct passwd**, const char*);
186 pam_handle_t *pamh = NULL;
187 #endif
188
189 static struct opie opiedata;
190 static char opieprompt[OPIE_CHALLENGE_MAX+1];
191 static int pwok;
192
193 char    *pid_file = NULL;
194
195 /*
196  * Limit number of pathnames that glob can return.
197  * A limit of 0 indicates the number of pathnames is unlimited.
198  */
199 #define MAXGLOBARGS     16384
200 #
201
202 /*
203  * Timeout intervals for retrying connections
204  * to hosts that don't accept PORT cmds.  This
205  * is a kludge, but given the problems with TCP...
206  */
207 #define SWAITMAX        90      /* wait at most 90 seconds */
208 #define SWAITINT        5       /* interval between retries */
209
210 int     swaitmax = SWAITMAX;
211 int     swaitint = SWAITINT;
212
213 #ifdef SETPROCTITLE
214 #ifdef OLD_SETPROCTITLE
215 char    **Argv = NULL;          /* pointer to argument vector */
216 char    *LastArgv = NULL;       /* end of argv */
217 #endif /* OLD_SETPROCTITLE */
218 char    proctitle[LINE_MAX];    /* initial part of title */
219 #endif /* SETPROCTITLE */
220
221 #define LOGCMD(cmd, file) \
222         if (logging > 1) \
223             syslog(LOG_INFO,"%s %s%s", cmd, \
224                 *(file) == '/' ? "" : curdir(), file);
225 #define LOGCMD2(cmd, file1, file2) \
226          if (logging > 1) \
227             syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
228                 *(file1) == '/' ? "" : curdir(), file1, \
229                 *(file2) == '/' ? "" : curdir(), file2);
230 #define LOGBYTES(cmd, file, cnt) \
231         if (logging > 1) { \
232                 if (cnt == (off_t)-1) \
233                     syslog(LOG_INFO,"%s %s%s", cmd, \
234                         *(file) == '/' ? "" : curdir(), file); \
235                 else \
236                     syslog(LOG_INFO, "%s %s%s = %qd bytes", \
237                         cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
238         }
239
240 #ifdef VIRTUAL_HOSTING
241 static void      inithosts(void);
242 static void     selecthost(union sockunion *);
243 #endif
244 static void      ack(char *);
245 static void      sigurg(int);
246 static void      myoob(void);
247 static int       checkuser(char *, char *, int);
248 static FILE     *dataconn(char *, off_t, char *);
249 static void      dolog(struct sockaddr *);
250 static char     *curdir(void);
251 static void      end_login(void);
252 static FILE     *getdatasock(char *);
253 static char     *gunique(char *);
254 static void      lostconn(int);
255 static void      sigquit(int);
256 static int       receive_data(FILE *, FILE *);
257 static int       send_data(FILE *, FILE *, off_t, off_t, int);
258 static struct passwd *
259                  sgetpwnam(char *);
260 static char     *sgetsave(char *);
261 static void      reapchild(int);
262 static void      logxfer(char *, off_t, time_t);
263
264 static char *
265 curdir(void)
266 {
267         static char path[MAXPATHLEN+1+1];       /* path + '/' + '\0' */
268
269         if (getcwd(path, sizeof(path)-2) == NULL)
270                 return ("");
271         if (path[1] != '\0')            /* special case for root dir. */
272                 strcat(path, "/");
273         /* For guest account, skip / since it's chrooted */
274         return (guest ? path+1 : path);
275 }
276
277 int
278 main(int argc, char *argv[], char **envp)
279 {
280         int addrlen, ch, on = 1, tos;
281         char *cp, line[LINE_MAX];
282         FILE *fd;
283         int error;
284         char    *bindname = NULL;
285         int     family = AF_UNSPEC;
286         int     enable_v4 = 0;
287         struct sigaction sa;
288
289         tzset();                /* in case no timezone database in ~ftp */
290         sigemptyset(&sa.sa_mask);
291         sa.sa_flags = SA_RESTART;
292
293 #ifdef OLD_SETPROCTITLE
294         /*
295          *  Save start and extent of argv for setproctitle.
296          */
297         Argv = argv;
298         while (*envp)
299                 envp++;
300         LastArgv = envp[-1] + strlen(envp[-1]);
301 #endif /* OLD_SETPROCTITLE */
302
303
304         while ((ch = getopt(argc, argv, "AdlDESURrt:T:u:vOoa:p:46")) != -1) {
305                 switch (ch) {
306                 case 'D':
307                         daemon_mode++;
308                         break;
309
310                 case 'd':
311                         ftpdebug++;
312                         break;
313
314                 case 'E':
315                         noepsv = 1;
316                         break;
317
318                 case 'l':
319                         logging++;      /* > 1 == extra logging */
320                         break;
321
322                 case 'r':
323                         readonly = 1;
324                         break;
325
326                 case 'R':
327                         paranoid = 0;
328                         break;
329
330                 case 'S':
331                         stats++;
332                         break;
333
334                 case 'T':
335                         maxtimeout = atoi(optarg);
336                         if (timeout > maxtimeout)
337                                 timeout = maxtimeout;
338                         break;
339
340                 case 't':
341                         timeout = atoi(optarg);
342                         if (maxtimeout < timeout)
343                                 maxtimeout = timeout;
344                         break;
345
346                 case 'U':
347                         restricted_data_ports = 0;
348                         break;
349
350                 case 'a':
351                         bindname = optarg;
352                         break;
353
354                 case 'p':
355                         pid_file = optarg;
356                         break;
357
358                 case 'u':
359                     {
360                         long val = 0;
361
362                         val = strtol(optarg, &optarg, 8);
363                         if (*optarg != '\0' || val < 0)
364                                 warnx("bad value for -u");
365                         else
366                                 defumask = val;
367                         break;
368                     }
369                 case 'A':
370                         anon_only = 1;
371                         break;
372
373                 case 'v':
374                         ftpdebug = 1;
375                         break;
376
377                 case '4':
378                         enable_v4 = 1;
379                         if (family == AF_UNSPEC)
380                                 family = AF_INET;
381                         break;
382
383                 case '6':
384                         family = AF_INET6;
385                         break;
386
387                 case 'O':
388                         noguestretr = 1;
389                         break;
390
391                 case 'o':
392                         noretr = 1;
393                         break;
394
395                 default:
396                         warnx("unknown flag -%c ignored", optopt);
397                         break;
398                 }
399         }
400
401 #ifdef VIRTUAL_HOSTING
402         inithosts();
403 #endif
404         (void) freopen(_PATH_DEVNULL, "w", stderr);
405
406         /*
407          * LOG_NDELAY sets up the logging connection immediately,
408          * necessary for anonymous ftp's that chroot and can't do it later.
409          */
410         openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
411
412         if (daemon_mode) {
413                 int ctl_sock, fd;
414                 struct addrinfo hints, *res;
415
416                 /*
417                  * Detach from parent.
418                  */
419                 if (daemon(1, 1) < 0) {
420                         syslog(LOG_ERR, "failed to become a daemon");
421                         exit(1);
422                 }
423                 sa.sa_handler = reapchild;
424                 (void)sigaction(SIGCHLD, &sa, NULL);
425                 /* init bind_sa */
426                 memset(&hints, 0, sizeof(hints));
427
428                 hints.ai_family = family == AF_UNSPEC ? AF_INET : family;
429                 hints.ai_socktype = SOCK_STREAM;
430                 hints.ai_protocol = 0;
431                 hints.ai_flags = AI_PASSIVE;
432                 error = getaddrinfo(bindname, "ftp", &hints, &res);
433                 if (error) {
434                         if (family == AF_UNSPEC) {
435                                 hints.ai_family = AF_UNSPEC;
436                                 error = getaddrinfo(bindname, "ftp", &hints,
437                                                     &res);
438                         }
439                 }
440                 if (error) {
441                         syslog(LOG_ERR, "%s", gai_strerror(error));
442                         if (error == EAI_SYSTEM)
443                                 syslog(LOG_ERR, "%s", strerror(errno));
444                         exit(1);
445                 }
446                 if (res->ai_addr == NULL) {
447                         syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
448                         exit(1);
449                 } else
450                         family = res->ai_addr->sa_family;
451                 /*
452                  * Open a socket, bind it to the FTP port, and start
453                  * listening.
454                  */
455                 ctl_sock = socket(family, SOCK_STREAM, 0);
456                 if (ctl_sock < 0) {
457                         syslog(LOG_ERR, "control socket: %m");
458                         exit(1);
459                 }
460                 if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
461                     (char *)&on, sizeof(on)) < 0)
462                         syslog(LOG_ERR, "control setsockopt: %m");
463 #ifdef IPV6_BINDV6ONLY
464                 if (family == AF_INET6 && enable_v4 == 0) {
465                         if (setsockopt(ctl_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
466                                        (char *)&on, sizeof (on)) < 0)
467                                 syslog(LOG_ERR,
468                                        "control setsockopt(IPV6_BINDV6ONLY): %m");
469                 }
470 #endif /* IPV6_BINDV6ONLY */
471                 memcpy(&server_addr, res->ai_addr, res->ai_addr->sa_len);
472                 if (bind(ctl_sock, (struct sockaddr *)&server_addr,
473                          server_addr.su_len) < 0) {
474                         syslog(LOG_ERR, "control bind: %m");
475                         exit(1);
476                 }
477                 if (listen(ctl_sock, 32) < 0) {
478                         syslog(LOG_ERR, "control listen: %m");
479                         exit(1);
480                 }
481                 /*
482                  * Atomically write process ID
483                  */
484                 if (pid_file)
485                 {   
486                         int fd;
487                         char buf[20];
488
489                         fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC
490                                 | O_NONBLOCK | O_EXLOCK, 0644);
491                         if (fd < 0) {
492                                 if (errno == EAGAIN)
493                                         errx(1, "%s: file locked", pid_file);
494                                 else
495                                         err(1, "%s", pid_file);
496                         }
497                         snprintf(buf, sizeof(buf),
498                                 "%lu\n", (unsigned long) getpid());
499                         if (write(fd, buf, strlen(buf)) < 0)
500                                 err(1, "%s: write", pid_file);
501                         /* Leave the pid file open and locked */
502                 }
503                 /*
504                  * Loop forever accepting connection requests and forking off
505                  * children to handle them.
506                  */
507                 while (1) {
508                         addrlen = server_addr.su_len;
509                         fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
510                         if (fork() == 0) {
511                                 /* child */
512                                 (void) dup2(fd, 0);
513                                 (void) dup2(fd, 1);
514                                 close(ctl_sock);
515                                 break;
516                         }
517                         close(fd);
518                 }
519         } else {
520                 addrlen = sizeof(his_addr);
521                 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
522                         syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
523                         exit(1);
524                 }
525         }
526
527         sa.sa_handler = SIG_DFL;
528         (void)sigaction(SIGCHLD, &sa, NULL);
529
530         sa.sa_handler = sigurg;
531         sa.sa_flags = 0;                /* don't restart syscalls for SIGURG */
532         (void)sigaction(SIGURG, &sa, NULL);
533
534         sigfillset(&sa.sa_mask);        /* block all signals in handler */
535         sa.sa_flags = SA_RESTART;
536         sa.sa_handler = sigquit;
537         (void)sigaction(SIGHUP, &sa, NULL);
538         (void)sigaction(SIGINT, &sa, NULL);
539         (void)sigaction(SIGQUIT, &sa, NULL);
540         (void)sigaction(SIGTERM, &sa, NULL);
541
542         sa.sa_handler = lostconn;
543         (void)sigaction(SIGPIPE, &sa, NULL);
544
545         addrlen = sizeof(ctrl_addr);
546         if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
547                 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
548                 exit(1);
549         }
550 #ifdef VIRTUAL_HOSTING
551         /* select our identity from virtual host table */
552         selecthost(&ctrl_addr);
553 #endif
554 #ifdef IP_TOS
555         if (ctrl_addr.su_family == AF_INET)
556       {
557         tos = IPTOS_LOWDELAY;
558         if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
559                 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
560       }
561 #endif
562         /*
563          * Disable Nagle on the control channel so that we don't have to wait
564          * for peer's ACK before issuing our next reply.
565          */
566         if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
567                 syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m");
568
569         data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
570
571         /* set this here so klogin can use it... */
572         (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
573
574         /* Try to handle urgent data inline */
575 #ifdef SO_OOBINLINE
576         if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
577                 syslog(LOG_ERR, "setsockopt: %m");
578 #endif
579
580 #ifdef  F_SETOWN
581         if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
582                 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
583 #endif
584         dolog((struct sockaddr *)&his_addr);
585         /*
586          * Set up default state
587          */
588         data = -1;
589         type = TYPE_A;
590         form = FORM_N;
591         stru = STRU_F;
592         mode = MODE_S;
593         tmpline[0] = '\0';
594
595         /* If logins are disabled, print out the message. */
596         if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
597                 while (fgets(line, sizeof(line), fd) != NULL) {
598                         if ((cp = strchr(line, '\n')) != NULL)
599                                 *cp = '\0';
600                         lreply(530, "%s", line);
601                 }
602                 (void) fflush(stdout);
603                 (void) fclose(fd);
604                 reply(530, "System not available.");
605                 exit(0);
606         }
607 #ifdef VIRTUAL_HOSTING
608         if ((fd = fopen(thishost->welcome, "r")) != NULL) {
609 #else
610         if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
611 #endif
612                 while (fgets(line, sizeof(line), fd) != NULL) {
613                         if ((cp = strchr(line, '\n')) != NULL)
614                                 *cp = '\0';
615                         lreply(220, "%s", line);
616                 }
617                 (void) fflush(stdout);
618                 (void) fclose(fd);
619                 /* reply(220,) must follow */
620         }
621 #ifndef VIRTUAL_HOSTING
622         if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL)
623                 fatalerror("Ran out of memory.");
624         (void) gethostname(hostname, MAXHOSTNAMELEN - 1);
625         hostname[MAXHOSTNAMELEN - 1] = '\0';
626 #endif
627         reply(220, "%s FTP server (%s) ready.", hostname, version);
628         for (;;)
629                 (void) yyparse();
630         /* NOTREACHED */
631 }
632
633 static void
634 lostconn(int signo)
635 {
636
637         if (ftpdebug)
638                 syslog(LOG_DEBUG, "lost connection");
639         dologout(1);
640 }
641
642 static void
643 sigquit(int signo)
644 {
645
646         syslog(LOG_ERR, "got signal %d", signo);
647         dologout(1);
648 }
649
650 #ifdef VIRTUAL_HOSTING
651 /*
652  * read in virtual host tables (if they exist)
653  */
654
655 static void
656 inithosts(void)
657 {
658         FILE *fp;
659         char *cp;
660         struct ftphost *hrp, *lhrp;
661         char line[1024];
662         struct addrinfo hints, *res, *ai;
663
664         /*
665          * Fill in the default host information
666          */
667         if (gethostname(line, sizeof(line)) < 0)
668                 line[0] = '\0';
669         if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
670             (hrp->hostname = strdup(line)) == NULL)
671                 fatalerror("Ran out of memory.");
672         hrp->hostinfo = NULL;
673
674         memset(&hints, 0, sizeof(hints));
675         hints.ai_flags = AI_CANONNAME;
676         hints.ai_family = AF_UNSPEC;
677         getaddrinfo(hrp->hostname, NULL, &hints, &res);
678         if (res)
679                 hrp->hostinfo = res;
680         hrp->statfile = _PATH_FTPDSTATFILE;
681         hrp->welcome  = _PATH_FTPWELCOME;
682         hrp->loginmsg = _PATH_FTPLOGINMESG;
683         hrp->anonuser = "ftp";
684         hrp->next = NULL;
685         thishost = firsthost = lhrp = hrp;
686         if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
687                 int addrsize, error, gothost;
688                 void *addr;
689                 struct hostent *hp;
690
691                 while (fgets(line, sizeof(line), fp) != NULL) {
692                         int     i, hp_error;
693
694                         if ((cp = strchr(line, '\n')) == NULL) {
695                                 /* ignore long lines */
696                                 while (fgets(line, sizeof(line), fp) != NULL &&
697                                         strchr(line, '\n') == NULL)
698                                         ;
699                                 continue;
700                         }
701                         *cp = '\0';
702                         cp = strtok(line, " \t");
703                         /* skip comments and empty lines */
704                         if (cp == NULL || line[0] == '#')
705                                 continue;
706
707                         hints.ai_flags = 0;
708                         hints.ai_family = AF_UNSPEC;
709                         hints.ai_flags = AI_PASSIVE;
710                         error = getaddrinfo(cp, NULL, &hints, &res);
711                         if (error != NULL)
712                                 continue;
713                         for (ai = res; ai != NULL && ai->ai_addr != NULL;
714                              ai = ai->ai_next) {
715
716                         gothost = 0;
717                         for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
718                                 struct addrinfo *hi;
719
720                                 for (hi = hrp->hostinfo; hi != NULL;
721                                      hi = hi->ai_next)
722                                         if (hi->ai_addrlen == ai->ai_addrlen &&
723                                             memcmp(hi->ai_addr,
724                                                    ai->ai_addr,
725                                                    ai->ai_addr->sa_len) == 0) {
726                                                 gothost++;
727                                                 break;
728                                 }
729                                 if (gothost)
730                                         break;
731                         }
732                         if (hrp == NULL) {
733                                 if ((hrp = malloc(sizeof(struct ftphost))) == NULL)
734                                         continue;
735                                 /* defaults */
736                                 hrp->statfile = _PATH_FTPDSTATFILE;
737                                 hrp->welcome  = _PATH_FTPWELCOME;
738                                 hrp->loginmsg = _PATH_FTPLOGINMESG;
739                                 hrp->anonuser = "ftp";
740                                 hrp->next     = NULL;
741                                 lhrp->next = hrp;
742                                 lhrp = hrp;
743                         }
744                         hrp->hostinfo = res;
745
746                         /*
747                          * determine hostname to use.
748                          * force defined name if there is a valid alias
749                          * otherwise fallback to primary hostname
750                          */
751                         /* XXX: getaddrinfo() can't do alias check */
752                         switch(hrp->hostinfo->ai_family) {
753                         case AF_INET:
754                                 addr = &((struct sockaddr_in *)&hrp->hostinfo->ai_addr)->sin_addr;
755                                 addrsize = sizeof(struct sockaddr_in);
756                                 break;
757                         case AF_INET6:
758                                 addr = &((struct sockaddr_in6 *)&hrp->hostinfo->ai_addr)->sin6_addr;
759                                 addrsize = sizeof(struct sockaddr_in6);
760                                 break;
761                         default:
762                                 /* should not reach here */
763                                 if (hrp->hostinfo != NULL)
764                                         freeaddrinfo(hrp->hostinfo);
765                                 free(hrp);
766                                 continue;
767                                 /* NOTREACHED */
768                         }
769                         if ((hp = getipnodebyaddr((char*)addr, addrsize,
770                                                   hrp->hostinfo->ai_family,
771                                                   &hp_error)) != NULL) {
772                                 if (strcmp(cp, hp->h_name) != 0) {
773                                         if (hp->h_aliases == NULL)
774                                                 cp = hp->h_name;
775                                         else {
776                                                 i = 0;
777                                                 while (hp->h_aliases[i] &&
778                                                        strcmp(cp, hp->h_aliases[i]) != 0)
779                                                         ++i;
780                                                 if (hp->h_aliases[i] == NULL)
781                                                         cp = hp->h_name;
782                                         }
783                                 }
784                         }
785                         hrp->hostname = strdup(cp);
786                         freehostent(hp);
787                         /* ok, now we now peel off the rest */
788                         i = 0;
789                         while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
790                                 if (*cp != '-' && (cp = strdup(cp)) != NULL) {
791                                         switch (i) {
792                                         case 0: /* anon user permissions */
793                                                 hrp->anonuser = cp;
794                                                 break;
795                                         case 1: /* statistics file */
796                                                 hrp->statfile = cp;
797                                                 break;
798                                         case 2: /* welcome message */
799                                                 hrp->welcome  = cp;
800                                                 break;
801                                         case 3: /* login message */
802                                                 hrp->loginmsg = cp;
803                                                 break;
804                                         }
805                                 }
806                                 ++i;
807                         }
808                         /* XXX: re-initialization for getaddrinfo() loop */
809                         cp = strtok(line, " \t");
810                       }
811                 }
812                 (void) fclose(fp);
813         }
814 }
815
816 static void
817 selecthost(union sockunion *su)
818 {
819         struct ftphost  *hrp;
820         u_int16_t port;
821 #ifdef INET6
822         struct in6_addr *mapped_in6 = NULL;
823 #endif
824         struct addrinfo *hi;
825
826 #ifdef INET6
827         /*
828          * XXX IPv4 mapped IPv6 addr consideraton,
829          * specified in rfc2373.
830          */
831         if (su->su_family == AF_INET6 &&
832             IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr))
833                 mapped_in6 = &su->su_sin6.sin6_addr;
834 #endif
835
836         hrp = thishost = firsthost;     /* default */
837         port = su->su_port;
838         su->su_port = 0;
839         while (hrp != NULL) {
840             for (hi = hrp->hostinfo; hi != NULL; hi = hi->ai_next) {
841                 if (memcmp(su, hi->ai_addr, hi->ai_addrlen) == 0) {
842                         thishost = hrp;
843                         break;
844                 }
845 #ifdef INET6
846                 /* XXX IPv4 mapped IPv6 addr consideraton */
847                 if (hi->ai_addr->sa_family == AF_INET && mapped_in6 != NULL &&
848                     (memcmp(&mapped_in6->s6_addr[12],
849                             &((struct sockaddr_in *)hi->ai_addr)->sin_addr,
850                             sizeof(struct in_addr)) == 0)) {
851                         thishost = hrp;
852                         break;
853                 }
854 #endif
855             }
856             hrp = hrp->next;
857         }
858         su->su_port = port;
859         /* setup static variables as appropriate */
860         hostname = thishost->hostname;
861         ftpuser = thishost->anonuser;
862 }
863 #endif
864
865 /*
866  * Helper function for sgetpwnam().
867  */
868 static char *
869 sgetsave(char *s)
870 {
871         char *new = malloc((unsigned) strlen(s) + 1);
872
873         if (new == NULL) {
874                 perror_reply(421, "Local resource failure: malloc");
875                 dologout(1);
876                 /* NOTREACHED */
877         }
878         (void) strcpy(new, s);
879         return (new);
880 }
881
882 /*
883  * Save the result of a getpwnam.  Used for USER command, since
884  * the data returned must not be clobbered by any other command
885  * (e.g., globbing).
886  */
887 static struct passwd *
888 sgetpwnam(char *name)
889 {
890         static struct passwd save;
891         struct passwd *p;
892
893         if ((p = getpwnam(name)) == NULL)
894                 return (p);
895         if (save.pw_name) {
896                 free(save.pw_name);
897                 free(save.pw_passwd);
898                 free(save.pw_gecos);
899                 free(save.pw_dir);
900                 free(save.pw_shell);
901         }
902         save = *p;
903         save.pw_name = sgetsave(p->pw_name);
904         save.pw_passwd = sgetsave(p->pw_passwd);
905         save.pw_gecos = sgetsave(p->pw_gecos);
906         save.pw_dir = sgetsave(p->pw_dir);
907         save.pw_shell = sgetsave(p->pw_shell);
908         return (&save);
909 }
910
911 static int login_attempts;      /* number of failed login attempts */
912 static int askpasswd;           /* had user command, ask for passwd */
913 static char curname[MAXLOGNAME];        /* current USER name */
914
915 /*
916  * USER command.
917  * Sets global passwd pointer pw if named account exists and is acceptable;
918  * sets askpasswd if a PASS command is expected.  If logged in previously,
919  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
920  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
921  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
922  * requesting login privileges.  Disallow anyone who does not have a standard
923  * shell as returned by getusershell().  Disallow anyone mentioned in the file
924  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
925  */
926 void
927 user(char *name)
928 {
929         char *cp, *shell;
930
931         if (logged_in) {
932                 if (guest) {
933                         reply(530, "Can't change user from guest login.");
934                         return;
935                 } else if (dochroot) {
936                         reply(530, "Can't change user from chroot user.");
937                         return;
938                 }
939                 end_login();
940         }
941
942         guest = 0;
943         if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
944                 if (checkuser(_PATH_FTPUSERS, "ftp", 0) ||
945                     checkuser(_PATH_FTPUSERS, "anonymous", 0))
946                         reply(530, "User %s access denied.", name);
947 #ifdef VIRTUAL_HOSTING
948                 else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) {
949 #else
950                 else if ((pw = sgetpwnam("ftp")) != NULL) {
951 #endif
952                         guest = 1;
953                         askpasswd = 1;
954                         reply(331,
955                         "Guest login ok, send your email address as password.");
956                 } else
957                         reply(530, "User %s unknown.", name);
958                 if (!askpasswd && logging)
959                         syslog(LOG_NOTICE,
960                             "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
961                 return;
962         }
963         if (anon_only != 0) {
964                 reply(530, "Sorry, only anonymous ftp allowed.");
965                 return;
966         }
967                 
968         if ((pw = sgetpwnam(name))) {
969                 if ((shell = pw->pw_shell) == NULL || *shell == 0)
970                         shell = _PATH_BSHELL;
971                 while ((cp = getusershell()) != NULL)
972                         if (strcmp(cp, shell) == 0)
973                                 break;
974                 endusershell();
975
976                 if (cp == NULL || checkuser(_PATH_FTPUSERS, name, 1)) {
977                         reply(530, "User %s access denied.", name);
978                         if (logging)
979                                 syslog(LOG_NOTICE,
980                                     "FTP LOGIN REFUSED FROM %s, %s",
981                                     remotehost, name);
982                         pw = (struct passwd *) NULL;
983                         return;
984                 }
985         }
986         if (logging)
987                 strncpy(curname, name, sizeof(curname)-1);
988
989         pwok = 0;
990 #ifdef USE_PAM
991         /* XXX Kluge! The conversation mechanism needs to be fixed. */
992 #endif
993         if (opiechallenge(&opiedata, name, opieprompt) == 0) {
994                 pwok = (pw != NULL) &&
995                        opieaccessfile(remotehost) &&
996                        opiealways(pw->pw_dir);
997                 reply(331, "Response to %s %s for %s.",
998                       opieprompt, pwok ? "requested" : "required", name);
999         } else {
1000                 pwok = 1;
1001                 reply(331, "Password required for %s.", name);
1002         }
1003         askpasswd = 1;
1004         /*
1005          * Delay before reading passwd after first failed
1006          * attempt to slow down passwd-guessing programs.
1007          */
1008         if (login_attempts)
1009                 sleep((unsigned) login_attempts);
1010 }
1011
1012 /*
1013  * Check if a user is in the file "fname"
1014  */
1015 static int
1016 checkuser(char *fname, char *name, int pwset)
1017 {
1018         FILE *fd;
1019         int found = 0;
1020         char *p, line[BUFSIZ];
1021
1022         if ((fd = fopen(fname, "r")) != NULL) {
1023                 while (!found && fgets(line, sizeof(line), fd) != NULL)
1024                         if ((p = strchr(line, '\n')) != NULL) {
1025                                 *p = '\0';
1026                                 if (line[0] == '#')
1027                                         continue;
1028                                 /*
1029                                  * if first chr is '@', check group membership
1030                                  */
1031                                 if (line[0] == '@') {
1032                                         int i = 0;
1033                                         struct group *grp;
1034
1035                                         if ((grp = getgrnam(line+1)) == NULL)
1036                                                 continue;
1037                                         /*
1038                                          * Check user's default group
1039                                          */
1040                                         if (pwset && grp->gr_gid == pw->pw_gid)
1041                                                 found = 1;
1042                                         /*
1043                                          * Check supplementary groups
1044                                          */
1045                                         while (!found && grp->gr_mem[i])
1046                                                 found = strcmp(name,
1047                                                         grp->gr_mem[i++])
1048                                                         == 0;
1049                                 }
1050                                 /*
1051                                  * Otherwise, just check for username match
1052                                  */
1053                                 else
1054                                         found = strcmp(line, name) == 0;
1055                         }
1056                 (void) fclose(fd);
1057         }
1058         return (found);
1059 }
1060
1061 /*
1062  * Terminate login as previous user, if any, resetting state;
1063  * used when USER command is given or login fails.
1064  */
1065 static void
1066 end_login(void)
1067 {
1068 #ifdef USE_PAM
1069         int e;
1070 #endif
1071
1072         (void) seteuid((uid_t)0);
1073         if (logged_in)
1074                 ftpd_logwtmp(ttyline, "", NULL);
1075         pw = NULL;
1076 #ifdef  LOGIN_CAP
1077         setusercontext(NULL, getpwuid(0), (uid_t)0,
1078                        LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1079 #endif
1080 #ifdef USE_PAM
1081         if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS)
1082                 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e));
1083         if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS)
1084                 syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e));
1085         if ((e = pam_end(pamh, e)) != PAM_SUCCESS)
1086                 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
1087         pamh = NULL;
1088 #endif
1089         logged_in = 0;
1090         guest = 0;
1091         dochroot = 0;
1092 }
1093
1094 #ifdef USE_PAM
1095
1096 /*
1097  * the following code is stolen from imap-uw PAM authentication module and
1098  * login.c
1099  */
1100 #define COPY_STRING(s) (s ? strdup(s) : NULL)
1101
1102 struct cred_t {
1103         const char *uname;              /* user name */
1104         const char *pass;               /* password */
1105 };
1106 typedef struct cred_t cred_t;
1107
1108 static int
1109 auth_conv(int num_msg, const struct pam_message **msg,
1110           struct pam_response **resp, void *appdata)
1111 {
1112         int i;
1113         cred_t *cred = (cred_t *) appdata;
1114         struct pam_response *reply;
1115
1116         reply = calloc(num_msg, sizeof *reply);
1117         if (reply == NULL)
1118                 return PAM_BUF_ERR;
1119
1120         for (i = 0; i < num_msg; i++) {
1121                 switch (msg[i]->msg_style) {
1122                 case PAM_PROMPT_ECHO_ON:        /* assume want user name */
1123                         reply[i].resp_retcode = PAM_SUCCESS;
1124                         reply[i].resp = COPY_STRING(cred->uname);
1125                         /* PAM frees resp. */
1126                         break;
1127                 case PAM_PROMPT_ECHO_OFF:       /* assume want password */
1128                         reply[i].resp_retcode = PAM_SUCCESS;
1129                         reply[i].resp = COPY_STRING(cred->pass);
1130                         /* PAM frees resp. */
1131                         break;
1132                 case PAM_TEXT_INFO:
1133                 case PAM_ERROR_MSG:
1134                         reply[i].resp_retcode = PAM_SUCCESS;
1135                         reply[i].resp = NULL;
1136                         break;
1137                 default:                        /* unknown message style */
1138                         free(reply);
1139                         return PAM_CONV_ERR;
1140                 }
1141         }
1142
1143         *resp = reply;
1144         return PAM_SUCCESS;
1145 }
1146
1147 /*
1148  * Attempt to authenticate the user using PAM.  Returns 0 if the user is
1149  * authenticated, or 1 if not authenticated.  If some sort of PAM system
1150  * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
1151  * function returns -1.  This can be used as an indication that we should
1152  * fall back to a different authentication mechanism.
1153  */
1154 static int
1155 auth_pam(struct passwd **ppw, const char *pass)
1156 {
1157         pam_handle_t *pamh = NULL;
1158         const char *tmpl_user;
1159         const void *item;
1160         int rval;
1161         int e;
1162         cred_t auth_cred = { (*ppw)->pw_name, pass };
1163         struct pam_conv conv = { &auth_conv, &auth_cred };
1164
1165         e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh);
1166         if (e != PAM_SUCCESS) {
1167                 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
1168                 return -1;
1169         }
1170
1171         e = pam_set_item(pamh, PAM_RHOST, remotehost);
1172         if (e != PAM_SUCCESS) {
1173                 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
1174                         pam_strerror(pamh, e));
1175                 return -1;
1176         }
1177
1178         e = pam_authenticate(pamh, 0);
1179         switch (e) {
1180         case PAM_SUCCESS:
1181                 /*
1182                  * With PAM we support the concept of a "template"
1183                  * user.  The user enters a login name which is
1184                  * authenticated by PAM, usually via a remote service
1185                  * such as RADIUS or TACACS+.  If authentication
1186                  * succeeds, a different but related "template" name
1187                  * is used for setting the credentials, shell, and
1188                  * home directory.  The name the user enters need only
1189                  * exist on the remote authentication server, but the
1190                  * template name must be present in the local password
1191                  * database.
1192                  *
1193                  * This is supported by two various mechanisms in the
1194                  * individual modules.  However, from the application's
1195                  * point of view, the template user is always passed
1196                  * back as a changed value of the PAM_USER item.
1197                  */
1198                 if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
1199                     PAM_SUCCESS) {
1200                         tmpl_user = (const char *) item;
1201                         if (strcmp((*ppw)->pw_name, tmpl_user) != 0)
1202                                 *ppw = getpwnam(tmpl_user);
1203                 } else
1204                         syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
1205                             pam_strerror(pamh, e));
1206                 rval = 0;
1207                 break;
1208
1209         case PAM_AUTH_ERR:
1210         case PAM_USER_UNKNOWN:
1211         case PAM_MAXTRIES:
1212                 rval = 1;
1213                 break;
1214
1215         default:
1216                 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
1217                 rval = -1;
1218                 break;
1219         }
1220
1221         if (rval == 0) {
1222                 e = pam_acct_mgmt(pamh, 0);
1223                 if (e == PAM_NEW_AUTHTOK_REQD) {
1224                         e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
1225                         if (e != PAM_SUCCESS) {
1226                                 syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pamh, e));
1227                                 rval = 1;
1228                         }
1229                 } else if (e != PAM_SUCCESS) {
1230                         rval = 1;
1231                 }
1232         }
1233
1234         if (rval != 0) {
1235                 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
1236                         syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
1237                 }
1238                 pamh = NULL;
1239         }
1240         return rval;
1241 }
1242
1243 #endif /* USE_PAM */
1244
1245 void
1246 pass(char *passwd)
1247 {
1248         int rval;
1249         FILE *fd;
1250 #ifdef  LOGIN_CAP
1251         login_cap_t *lc = NULL;
1252 #endif
1253 #ifdef USE_PAM
1254         int e;
1255 #endif
1256         char *xpasswd;
1257
1258         if (logged_in || askpasswd == 0) {
1259                 reply(503, "Login with USER first.");
1260                 return;
1261         }
1262         askpasswd = 0;
1263         if (!guest) {           /* "ftp" is only account allowed no password */
1264                 if (pw == NULL) {
1265                         rval = 1;       /* failure below */
1266                         goto skip;
1267                 }
1268 #ifdef USE_PAM
1269                 rval = auth_pam(&pw, passwd);
1270                 if (rval >= 0) {
1271                         opieunlock();
1272                         goto skip;
1273                 }
1274 #endif
1275                 if (opieverify(&opiedata, passwd) == 0)
1276                         xpasswd = pw->pw_passwd;
1277                 else if (pwok) {
1278                         xpasswd = crypt(passwd, pw->pw_passwd);
1279                         if (passwd[0] == '\0' && pw->pw_passwd[0] != '\0')
1280                                 xpasswd = ":";
1281                 } else {
1282                         rval = 1;
1283                         goto skip;
1284                 }
1285                 rval = strcmp(pw->pw_passwd, xpasswd);
1286                 if (pw->pw_expire && time(NULL) >= pw->pw_expire)
1287                         rval = 1;       /* failure */
1288 skip:
1289                 /*
1290                  * If rval == 1, the user failed the authentication check
1291                  * above.  If rval == 0, either PAM or local authentication
1292                  * succeeded.
1293                  */
1294                 if (rval) {
1295                         reply(530, "Login incorrect.");
1296                         if (logging)
1297                                 syslog(LOG_NOTICE,
1298                                     "FTP LOGIN FAILED FROM %s, %s",
1299                                     remotehost, curname);
1300                         pw = NULL;
1301                         if (login_attempts++ >= 5) {
1302                                 syslog(LOG_NOTICE,
1303                                     "repeated login failures from %s",
1304                                     remotehost);
1305                                 exit(0);
1306                         }
1307                         return;
1308                 }
1309         }
1310         login_attempts = 0;             /* this time successful */
1311         if (setegid((gid_t)pw->pw_gid) < 0) {
1312                 reply(550, "Can't set gid.");
1313                 return;
1314         }
1315         /* May be overridden by login.conf */
1316         (void) umask(defumask);
1317 #ifdef  LOGIN_CAP
1318         if ((lc = login_getpwclass(pw)) != NULL) {
1319                 char    remote_ip[MAXHOSTNAMELEN];
1320
1321                 getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1322                         remote_ip, sizeof(remote_ip) - 1, NULL, 0,
1323                         NI_NUMERICHOST|NI_WITHSCOPEID);
1324                 remote_ip[sizeof(remote_ip) - 1] = 0;
1325                 if (!auth_hostok(lc, remotehost, remote_ip)) {
1326                         syslog(LOG_INFO|LOG_AUTH,
1327                             "FTP LOGIN FAILED (HOST) as %s: permission denied.",
1328                             pw->pw_name);
1329                         reply(530, "Permission denied.\n");
1330                         pw = NULL;
1331                         return;
1332                 }
1333                 if (!auth_timeok(lc, time(NULL))) {
1334                         reply(530, "Login not available right now.\n");
1335                         pw = NULL;
1336                         return;
1337                 }
1338         }
1339         setusercontext(lc, pw, (uid_t)0,
1340                 LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY|
1341                 LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1342 #else
1343         setlogin(pw->pw_name);
1344         (void) initgroups(pw->pw_name, pw->pw_gid);
1345 #endif
1346
1347 #ifdef USE_PAM
1348         if (pamh) {
1349                 if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
1350                         syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, e));
1351                 } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
1352                         syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e));
1353                 }
1354         }
1355 #endif
1356
1357         /* open wtmp before chroot */
1358         ftpd_logwtmp(ttyline, pw->pw_name, (struct sockaddr *)&his_addr);
1359         logged_in = 1;
1360
1361         if (guest && stats && statfd < 0)
1362 #ifdef VIRTUAL_HOSTING
1363                 if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0)
1364 #else
1365                 if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
1366 #endif
1367                         stats = 0;
1368
1369         dochroot =
1370 #ifdef  LOGIN_CAP       /* Allow login.conf configuration as well */
1371                 login_getcapbool(lc, "ftp-chroot", 0) ||
1372 #endif
1373                 checkuser(_PATH_FTPCHROOT, pw->pw_name, 1);
1374         if (guest) {
1375                 /*
1376                  * We MUST do a chdir() after the chroot. Otherwise
1377                  * the old current directory will be accessible as "."
1378                  * outside the new root!
1379                  */
1380                 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
1381                         reply(550, "Can't set guest privileges.");
1382                         goto bad;
1383                 }
1384         } else if (dochroot) {
1385                 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
1386                         reply(550, "Can't change root.");
1387                         goto bad;
1388                 }
1389         } else if (chdir(pw->pw_dir) < 0) {
1390                 if (chdir("/") < 0) {
1391                         reply(530, "User %s: can't change directory to %s.",
1392                             pw->pw_name, pw->pw_dir);
1393                         goto bad;
1394                 } else
1395                         lreply(230, "No directory! Logging in with home=/");
1396         }
1397         if (seteuid((uid_t)pw->pw_uid) < 0) {
1398                 reply(550, "Can't set uid.");
1399                 goto bad;
1400         }
1401
1402         /*
1403          * Display a login message, if it exists.
1404          * N.B. reply(230,) must follow the message.
1405          */
1406 #ifdef VIRTUAL_HOSTING
1407         if ((fd = fopen(thishost->loginmsg, "r")) != NULL) {
1408 #else
1409         if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
1410 #endif
1411                 char *cp, line[LINE_MAX];
1412
1413                 while (fgets(line, sizeof(line), fd) != NULL) {
1414                         if ((cp = strchr(line, '\n')) != NULL)
1415                                 *cp = '\0';
1416                         lreply(230, "%s", line);
1417                 }
1418                 (void) fflush(stdout);
1419                 (void) fclose(fd);
1420         }
1421         if (guest) {
1422                 if (ident != NULL)
1423                         free(ident);
1424                 ident = strdup(passwd);
1425                 if (ident == NULL)
1426                         fatalerror("Ran out of memory.");
1427
1428                 reply(230, "Guest login ok, access restrictions apply.");
1429 #ifdef SETPROCTITLE
1430 #ifdef VIRTUAL_HOSTING
1431                 if (thishost != firsthost)
1432                         snprintf(proctitle, sizeof(proctitle),
1433                                  "%s: anonymous(%s)/%s", remotehost, hostname,
1434                                  passwd);
1435                 else
1436 #endif
1437                         snprintf(proctitle, sizeof(proctitle),
1438                                  "%s: anonymous/%s", remotehost, passwd);
1439                 setproctitle("%s", proctitle);
1440 #endif /* SETPROCTITLE */
1441                 if (logging)
1442                         syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1443                             remotehost, passwd);
1444         } else {
1445                 if (dochroot)
1446                         reply(230, "User %s logged in, "
1447                                    "access restrictions apply.", pw->pw_name);
1448                 else
1449                         reply(230, "User %s logged in.", pw->pw_name);
1450
1451 #ifdef SETPROCTITLE
1452                 snprintf(proctitle, sizeof(proctitle),
1453                          "%s: user/%s", remotehost, pw->pw_name);
1454                 setproctitle("%s", proctitle);
1455 #endif /* SETPROCTITLE */
1456                 if (logging)
1457                         syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1458                             remotehost, pw->pw_name);
1459         }
1460 #ifdef  LOGIN_CAP
1461         login_close(lc);
1462 #endif
1463         return;
1464 bad:
1465         /* Forget all about it... */
1466 #ifdef  LOGIN_CAP
1467         login_close(lc);
1468 #endif
1469         end_login();
1470 }
1471
1472 void
1473 retrieve(char *cmd, char *name)
1474 {
1475         FILE *fin, *dout;
1476         struct stat st;
1477         int (*closefunc)(FILE *);
1478         time_t start;
1479
1480         if (cmd == 0) {
1481                 fin = fopen(name, "r"), closefunc = fclose;
1482                 st.st_size = 0;
1483         } else {
1484                 char line[BUFSIZ];
1485
1486                 (void) snprintf(line, sizeof(line), cmd, name), name = line;
1487                 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1488                 st.st_size = -1;
1489                 st.st_blksize = BUFSIZ;
1490         }
1491         if (fin == NULL) {
1492                 if (errno != 0) {
1493                         perror_reply(550, name);
1494                         if (cmd == 0) {
1495                                 LOGCMD("get", name);
1496                         }
1497                 }
1498                 return;
1499         }
1500         byte_count = -1;
1501         if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1502                 reply(550, "%s: not a plain file.", name);
1503                 goto done;
1504         }
1505         if (restart_point) {
1506                 if (type == TYPE_A) {
1507                         off_t i, n;
1508                         int c;
1509
1510                         n = restart_point;
1511                         i = 0;
1512                         while (i++ < n) {
1513                                 if ((c=getc(fin)) == EOF) {
1514                                         perror_reply(550, name);
1515                                         goto done;
1516                                 }
1517                                 if (c == '\n')
1518                                         i++;
1519                         }
1520                 } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
1521                         perror_reply(550, name);
1522                         goto done;
1523                 }
1524         }
1525         dout = dataconn(name, st.st_size, "w");
1526         if (dout == NULL)
1527                 goto done;
1528         time(&start);
1529         send_data(fin, dout, st.st_blksize, st.st_size,
1530                   restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
1531         if (cmd == 0 && guest && stats)
1532                 logxfer(name, st.st_size, start);
1533         (void) fclose(dout);
1534         data = -1;
1535         pdata = -1;
1536 done:
1537         if (cmd == 0)
1538                 LOGBYTES("get", name, byte_count);
1539         (*closefunc)(fin);
1540 }
1541
1542 void
1543 store(char *name, char *mode, int unique)
1544 {
1545         FILE *fout, *din;
1546         struct stat st;
1547         int (*closefunc)(FILE *);
1548
1549         if ((unique || guest) && stat(name, &st) == 0 &&
1550             (name = gunique(name)) == NULL) {
1551                 LOGCMD(*mode == 'w' ? "put" : "append", name);
1552                 return;
1553         }
1554
1555         if (restart_point)
1556                 mode = "r+";
1557         fout = fopen(name, mode);
1558         closefunc = fclose;
1559         if (fout == NULL) {
1560                 perror_reply(553, name);
1561                 LOGCMD(*mode == 'w' ? "put" : "append", name);
1562                 return;
1563         }
1564         byte_count = -1;
1565         if (restart_point) {
1566                 if (type == TYPE_A) {
1567                         off_t i, n;
1568                         int c;
1569
1570                         n = restart_point;
1571                         i = 0;
1572                         while (i++ < n) {
1573                                 if ((c=getc(fout)) == EOF) {
1574                                         perror_reply(550, name);
1575                                         goto done;
1576                                 }
1577                                 if (c == '\n')
1578                                         i++;
1579                         }
1580                         /*
1581                          * We must do this seek to "current" position
1582                          * because we are changing from reading to
1583                          * writing.
1584                          */
1585                         if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) {
1586                                 perror_reply(550, name);
1587                                 goto done;
1588                         }
1589                 } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
1590                         perror_reply(550, name);
1591                         goto done;
1592                 }
1593         }
1594         din = dataconn(name, (off_t)-1, "r");
1595         if (din == NULL)
1596                 goto done;
1597         if (receive_data(din, fout) == 0) {
1598                 if (unique)
1599                         reply(226, "Transfer complete (unique file name:%s).",
1600                             name);
1601                 else
1602                         reply(226, "Transfer complete.");
1603         }
1604         (void) fclose(din);
1605         data = -1;
1606         pdata = -1;
1607 done:
1608         LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1609         (*closefunc)(fout);
1610 }
1611
1612 static FILE *
1613 getdatasock(char *mode)
1614 {
1615         int on = 1, s, t, tries;
1616
1617         if (data >= 0)
1618                 return (fdopen(data, mode));
1619         (void) seteuid((uid_t)0);
1620
1621         s = socket(data_dest.su_family, SOCK_STREAM, 0);
1622         if (s < 0)
1623                 goto bad;
1624         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1625             (char *) &on, sizeof(on)) < 0)
1626                 goto bad;
1627         /* anchor socket to avoid multi-homing problems */
1628         data_source = ctrl_addr;
1629         data_source.su_port = htons(20); /* ftp-data port */
1630         for (tries = 1; ; tries++) {
1631                 if (bind(s, (struct sockaddr *)&data_source,
1632                     data_source.su_len) >= 0)
1633                         break;
1634                 if (errno != EADDRINUSE || tries > 10)
1635                         goto bad;
1636                 sleep(tries);
1637         }
1638         (void) seteuid((uid_t)pw->pw_uid);
1639 #ifdef IP_TOS
1640         if (data_source.su_family == AF_INET)
1641       {
1642         on = IPTOS_THROUGHPUT;
1643         if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1644                 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1645       }
1646 #endif
1647 #ifdef TCP_NOPUSH
1648         /*
1649          * Turn off push flag to keep sender TCP from sending short packets
1650          * at the boundaries of each write().  Should probably do a SO_SNDBUF
1651          * to set the send buffer size as well, but that may not be desirable
1652          * in heavy-load situations.
1653          */
1654         on = 1;
1655         if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
1656                 syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1657 #endif
1658 #ifdef SO_SNDBUF
1659         on = 65536;
1660         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
1661                 syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1662 #endif
1663
1664         return (fdopen(s, mode));
1665 bad:
1666         /* Return the real value of errno (close may change it) */
1667         t = errno;
1668         (void) seteuid((uid_t)pw->pw_uid);
1669         (void) close(s);
1670         errno = t;
1671         return (NULL);
1672 }
1673
1674 static FILE *
1675 dataconn(char *name, off_t size, char *mode)
1676 {
1677         char sizebuf[32];
1678         FILE *file;
1679         int retry = 0, tos;
1680
1681         file_size = size;
1682         byte_count = 0;
1683         if (size != (off_t) -1)
1684                 (void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", size);
1685         else
1686                 *sizebuf = '\0';
1687         if (pdata >= 0) {
1688                 union sockunion from;
1689                 int flags;
1690                 int s, fromlen = ctrl_addr.su_len;
1691                 struct timeval timeout;
1692                 fd_set set;
1693
1694                 FD_ZERO(&set);
1695                 FD_SET(pdata, &set);
1696
1697                 timeout.tv_usec = 0;
1698                 timeout.tv_sec = 120;
1699
1700                 /*
1701                  * Granted a socket is in the blocking I/O mode,
1702                  * accept() will block after a successful select()
1703                  * if the selected connection dies in between.
1704                  * Therefore set the non-blocking I/O flag here.
1705                  */
1706                 if ((flags = fcntl(pdata, F_GETFL, 0)) == -1 ||
1707                     fcntl(pdata, F_SETFL, flags | O_NONBLOCK) == -1)
1708                         goto pdata_err;
1709                 if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) <= 0 ||
1710                     (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0)
1711                         goto pdata_err;
1712                 (void) close(pdata);
1713                 pdata = s;
1714                 /*
1715                  * Unset the blocking I/O flag on the child socket
1716                  * again so stdio can work on it.
1717                  */
1718                 if ((flags = fcntl(pdata, F_GETFL, 0)) == -1 ||
1719                     fcntl(pdata, F_SETFL, flags & ~O_NONBLOCK) == -1)
1720                         goto pdata_err;
1721 #ifdef IP_TOS
1722                 if (from.su_family == AF_INET)
1723               {
1724                 tos = IPTOS_THROUGHPUT;
1725                 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1726                     sizeof(int));
1727               }
1728 #endif
1729                 reply(150, "Opening %s mode data connection for '%s'%s.",
1730                      type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1731                 return (fdopen(pdata, mode));
1732 pdata_err:
1733                 reply(425, "Can't open data connection.");
1734                 (void) close(pdata);
1735                 pdata = -1;
1736                 return (NULL);
1737         }
1738         if (data >= 0) {
1739                 reply(125, "Using existing data connection for '%s'%s.",
1740                     name, sizebuf);
1741                 usedefault = 1;
1742                 return (fdopen(data, mode));
1743         }
1744         if (usedefault)
1745                 data_dest = his_addr;
1746         usedefault = 1;
1747         file = getdatasock(mode);
1748         if (file == NULL) {
1749                 char hostbuf[BUFSIZ], portbuf[BUFSIZ];
1750                 getnameinfo((struct sockaddr *)&data_source,
1751                         data_source.su_len, hostbuf, sizeof(hostbuf) - 1,
1752                         portbuf, sizeof(portbuf),
1753                         NI_NUMERICHOST|NI_NUMERICSERV|NI_WITHSCOPEID);
1754                 reply(425, "Can't create data socket (%s,%s): %s.",
1755                         hostbuf, portbuf, strerror(errno));
1756                 return (NULL);
1757         }
1758         data = fileno(file);
1759         while (connect(data, (struct sockaddr *)&data_dest,
1760             data_dest.su_len) < 0) {
1761                 if (errno == EADDRINUSE && retry < swaitmax) {
1762                         sleep((unsigned) swaitint);
1763                         retry += swaitint;
1764                         continue;
1765                 }
1766                 perror_reply(425, "Can't build data connection");
1767                 (void) fclose(file);
1768                 data = -1;
1769                 return (NULL);
1770         }
1771         reply(150, "Opening %s mode data connection for '%s'%s.",
1772              type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1773         return (file);
1774 }
1775
1776 /*
1777  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1778  * encapsulation of the data subject to Mode, Structure, and Type.
1779  *
1780  * NB: Form isn't handled.
1781  */
1782 static int
1783 send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg)
1784 {
1785         int c, filefd, netfd;
1786         char *buf;
1787         off_t cnt;
1788
1789         transflag++;
1790         switch (type) {
1791
1792         case TYPE_A:
1793                 while ((c = getc(instr)) != EOF) {
1794                         if (recvurg)
1795                                 goto got_oob;
1796                         byte_count++;
1797                         if (c == '\n') {
1798                                 if (ferror(outstr))
1799                                         goto data_err;
1800                                 (void) putc('\r', outstr);
1801                         }
1802                         (void) putc(c, outstr);
1803                 }
1804                 if (recvurg)
1805                         goto got_oob;
1806                 fflush(outstr);
1807                 transflag = 0;
1808                 if (ferror(instr))
1809                         goto file_err;
1810                 if (ferror(outstr))
1811                         goto data_err;
1812                 reply(226, "Transfer complete.");
1813                 return (0);
1814
1815         case TYPE_I:
1816         case TYPE_L:
1817                 /*
1818                  * isreg is only set if we are not doing restart and we
1819                  * are sending a regular file
1820                  */
1821                 netfd = fileno(outstr);
1822                 filefd = fileno(instr);
1823
1824                 if (isreg) {
1825
1826                         off_t offset;
1827                         int err;
1828
1829                         err = cnt = offset = 0;
1830
1831                         while (err != -1 && filesize > 0) {
1832                                 err = sendfile(filefd, netfd, offset, 0,
1833                                         (struct sf_hdtr *) NULL, &cnt, 0);
1834                                 if (recvurg)
1835                                         goto got_oob;
1836                                 byte_count += cnt;
1837                                 offset += cnt;
1838                                 filesize -= cnt;
1839
1840                                 if (err == -1) {
1841                                         if (!cnt)
1842                                                 goto oldway;
1843
1844                                         goto data_err;
1845                                 }
1846                         }
1847
1848                         reply(226, "Transfer complete.");
1849                         return (0);
1850                 }
1851
1852 oldway:
1853                 if ((buf = malloc((u_int)blksize)) == NULL) {
1854                         transflag = 0;
1855                         perror_reply(451, "Local resource failure: malloc");
1856                         return (-1);
1857                 }
1858
1859                 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1860                     write(netfd, buf, cnt) == cnt)
1861                         byte_count += cnt;
1862                 transflag = 0;
1863                 (void)free(buf);
1864                 if (cnt != 0) {
1865                         if (cnt < 0)
1866                                 goto file_err;
1867                         goto data_err;
1868                 }
1869                 reply(226, "Transfer complete.");
1870                 return (0);
1871         default:
1872                 transflag = 0;
1873                 reply(550, "Unimplemented TYPE %d in send_data", type);
1874                 return (-1);
1875         }
1876
1877 data_err:
1878         transflag = 0;
1879         perror_reply(426, "Data connection");
1880         return (-1);
1881
1882 file_err:
1883         transflag = 0;
1884         perror_reply(551, "Error on input file");
1885         return (-1);
1886
1887 got_oob:
1888         myoob();
1889         recvurg = 0;
1890         transflag = 0;
1891         return (-1);
1892 }
1893
1894 /*
1895  * Transfer data from peer to "outstr" using the appropriate encapulation of
1896  * the data subject to Mode, Structure, and Type.
1897  *
1898  * N.B.: Form isn't handled.
1899  */
1900 static int
1901 receive_data(FILE *instr, FILE *outstr)
1902 {
1903         int c;
1904         int cnt, bare_lfs;
1905         char buf[BUFSIZ];
1906
1907         transflag++;
1908         bare_lfs = 0;
1909
1910         switch (type) {
1911
1912         case TYPE_I:
1913         case TYPE_L:
1914                 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1915                         if (recvurg)
1916                                 goto got_oob;
1917                         if (write(fileno(outstr), buf, cnt) != cnt)
1918                                 goto file_err;
1919                         byte_count += cnt;
1920                 }
1921                 if (recvurg)
1922                         goto got_oob;
1923                 if (cnt < 0)
1924                         goto data_err;
1925                 transflag = 0;
1926                 return (0);
1927
1928         case TYPE_E:
1929                 reply(553, "TYPE E not implemented.");
1930                 transflag = 0;
1931                 return (-1);
1932
1933         case TYPE_A:
1934                 while ((c = getc(instr)) != EOF) {
1935                         if (recvurg)
1936                                 goto got_oob;
1937                         byte_count++;
1938                         if (c == '\n')
1939                                 bare_lfs++;
1940                         while (c == '\r') {
1941                                 if (ferror(outstr))
1942                                         goto data_err;
1943                                 if ((c = getc(instr)) != '\n') {
1944                                         (void) putc ('\r', outstr);
1945                                         if (c == '\0' || c == EOF)
1946                                                 goto contin2;
1947                                 }
1948                         }
1949                         (void) putc(c, outstr);
1950         contin2:        ;
1951                 }
1952                 if (recvurg)
1953                         goto got_oob;
1954                 fflush(outstr);
1955                 if (ferror(instr))
1956                         goto data_err;
1957                 if (ferror(outstr))
1958                         goto file_err;
1959                 transflag = 0;
1960                 if (bare_lfs) {
1961                         lreply(226,
1962                 "WARNING! %d bare linefeeds received in ASCII mode",
1963                             bare_lfs);
1964                 (void)printf("   File may not have transferred correctly.\r\n");
1965                 }
1966                 return (0);
1967         default:
1968                 reply(550, "Unimplemented TYPE %d in receive_data", type);
1969                 transflag = 0;
1970                 return (-1);
1971         }
1972
1973 data_err:
1974         transflag = 0;
1975         perror_reply(426, "Data Connection");
1976         return (-1);
1977
1978 file_err:
1979         transflag = 0;
1980         perror_reply(452, "Error writing file");
1981         return (-1);
1982
1983 got_oob:
1984         myoob();
1985         recvurg = 0;
1986         transflag = 0;
1987         return (-1);
1988 }
1989
1990 void
1991 statfilecmd(char *filename)
1992 {
1993         FILE *fin;
1994         int c;
1995         char line[LINE_MAX];
1996
1997         (void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename);
1998         fin = ftpd_popen(line, "r");
1999         lreply(211, "status of %s:", filename);
2000         while ((c = getc(fin)) != EOF) {
2001                 if (c == '\n') {
2002                         if (ferror(stdout)){
2003                                 perror_reply(421, "control connection");
2004                                 (void) ftpd_pclose(fin);
2005                                 dologout(1);
2006                                 /* NOTREACHED */
2007                         }
2008                         if (ferror(fin)) {
2009                                 perror_reply(551, filename);
2010                                 (void) ftpd_pclose(fin);
2011                                 return;
2012                         }
2013                         (void) putc('\r', stdout);
2014                 }
2015                 (void) putc(c, stdout);
2016         }
2017         (void) ftpd_pclose(fin);
2018         reply(211, "End of Status");
2019 }
2020
2021 void
2022 statcmd(void)
2023 {
2024         union sockunion *su;
2025         u_char *a, *p;
2026         char hname[INET6_ADDRSTRLEN];
2027         int ispassive;
2028
2029         lreply(211, "%s FTP server status:", hostname, version);
2030         printf("     %s\r\n", version);
2031         printf("     Connected to %s", remotehost);
2032         if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
2033                          hname, sizeof(hname) - 1, NULL, 0,
2034                          NI_NUMERICHOST|NI_WITHSCOPEID)) {
2035                 if (strcmp(hname, remotehost) != 0)
2036                         printf(" (%s)", hname);
2037         }
2038         printf("\r\n");
2039         if (logged_in) {
2040                 if (guest)
2041                         printf("     Logged in anonymously\r\n");
2042                 else
2043                         printf("     Logged in as %s\r\n", pw->pw_name);
2044         } else if (askpasswd)
2045                 printf("     Waiting for password\r\n");
2046         else
2047                 printf("     Waiting for user name\r\n");
2048         printf("     TYPE: %s", typenames[type]);
2049         if (type == TYPE_A || type == TYPE_E)
2050                 printf(", FORM: %s", formnames[form]);
2051         if (type == TYPE_L)
2052 #if NBBY == 8
2053                 printf(" %d", NBBY);
2054 #else
2055                 printf(" %d", bytesize);        /* need definition! */
2056 #endif
2057         printf("; STRUcture: %s; transfer MODE: %s\r\n",
2058             strunames[stru], modenames[mode]);
2059         if (data != -1)
2060                 printf("     Data connection open\r\n");
2061         else if (pdata != -1) {
2062                 ispassive = 1;
2063                 su = &pasv_addr;
2064                 goto printaddr;
2065         } else if (usedefault == 0) {
2066                 ispassive = 0;
2067                 su = &data_dest;
2068 printaddr:
2069 #define UC(b) (((int) b) & 0xff)
2070                 if (epsvall) {
2071                         printf("     EPSV only mode (EPSV ALL)\r\n");
2072                         goto epsvonly;
2073                 }
2074
2075                 /* PORT/PASV */
2076                 if (su->su_family == AF_INET) {
2077                         a = (u_char *) &su->su_sin.sin_addr;
2078                         p = (u_char *) &su->su_sin.sin_port;
2079                         printf("     %s (%d,%d,%d,%d,%d,%d)\r\n",
2080                                 ispassive ? "PASV" : "PORT",
2081                                 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2082                                 UC(p[0]), UC(p[1]));
2083                 }
2084
2085                 /* LPRT/LPSV */
2086             {
2087                 int alen, af, i;
2088
2089                 switch (su->su_family) {
2090                 case AF_INET:
2091                         a = (u_char *) &su->su_sin.sin_addr;
2092                         p = (u_char *) &su->su_sin.sin_port;
2093                         alen = sizeof(su->su_sin.sin_addr);
2094                         af = 4;
2095                         break;
2096                 case AF_INET6:
2097                         a = (u_char *) &su->su_sin6.sin6_addr;
2098                         p = (u_char *) &su->su_sin6.sin6_port;
2099                         alen = sizeof(su->su_sin6.sin6_addr);
2100                         af = 6;
2101                         break;
2102                 default:
2103                         af = 0;
2104                         break;
2105                 }
2106                 if (af) {
2107                         printf("     %s (%d,%d,", ispassive ? "LPSV" : "LPRT",
2108                                 af, alen);
2109                         for (i = 0; i < alen; i++)
2110                                 printf("%d,", UC(a[i]));
2111                         printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
2112                 }
2113             }
2114
2115 epsvonly:;
2116                 /* EPRT/EPSV */
2117             {
2118                 int af;
2119
2120                 switch (su->su_family) {
2121                 case AF_INET:
2122                         af = 1;
2123                         break;
2124                 case AF_INET6:
2125                         af = 2;
2126                         break;
2127                 default:
2128                         af = 0;
2129                         break;
2130                 }
2131                 if (af) {
2132                         if (!getnameinfo((struct sockaddr *)su, su->su_len,
2133                                         hname, sizeof(hname) - 1, NULL, 0,
2134                                         NI_NUMERICHOST)) {
2135                                 printf("     %s |%d|%s|%d|\r\n",
2136                                         ispassive ? "EPSV" : "EPRT",
2137                                         af, hname, htons(su->su_port));
2138                         }
2139                 }
2140             }
2141 #undef UC
2142         } else
2143                 printf("     No data connection\r\n");
2144         reply(211, "End of status");
2145 }
2146
2147 void
2148 fatalerror(char *s)
2149 {
2150
2151         reply(451, "Error in server: %s\n", s);
2152         reply(221, "Closing connection due to server error.");
2153         dologout(0);
2154         /* NOTREACHED */
2155 }
2156
2157 void
2158 reply(int n, const char *fmt, ...)
2159 {
2160         va_list ap;
2161
2162         va_start(ap, fmt);
2163         (void)printf("%d ", n);
2164         (void)vprintf(fmt, ap);
2165         (void)printf("\r\n");
2166         (void)fflush(stdout);
2167         if (ftpdebug) {
2168                 syslog(LOG_DEBUG, "<--- %d ", n);
2169                 vsyslog(LOG_DEBUG, fmt, ap);
2170         }
2171 }
2172
2173 void
2174 lreply(int n, const char *fmt, ...)
2175 {
2176         va_list ap;
2177
2178         va_start(ap, fmt);
2179         (void)printf("%d- ", n);
2180         (void)vprintf(fmt, ap);
2181         (void)printf("\r\n");
2182         (void)fflush(stdout);
2183         if (ftpdebug) {
2184                 syslog(LOG_DEBUG, "<--- %d- ", n);
2185                 vsyslog(LOG_DEBUG, fmt, ap);
2186         }
2187 }
2188
2189 static void
2190 ack(char *s)
2191 {
2192
2193         reply(250, "%s command successful.", s);
2194 }
2195
2196 void
2197 nack(char *s)
2198 {
2199
2200         reply(502, "%s command not implemented.", s);
2201 }
2202
2203 /* ARGSUSED */
2204 void
2205 yyerror(char *s)
2206 {
2207         char *cp;
2208
2209         if ((cp = strchr(cbuf,'\n')))
2210                 *cp = '\0';
2211         reply(500, "'%s': command not understood.", cbuf);
2212 }
2213
2214 void
2215 delete(char *name)
2216 {
2217         struct stat st;
2218
2219         LOGCMD("delete", name);
2220         if (stat(name, &st) < 0) {
2221                 perror_reply(550, name);
2222                 return;
2223         }
2224         if ((st.st_mode&S_IFMT) == S_IFDIR) {
2225                 if (rmdir(name) < 0) {
2226                         perror_reply(550, name);
2227                         return;
2228                 }
2229                 goto done;
2230         }
2231         if (unlink(name) < 0) {
2232                 perror_reply(550, name);
2233                 return;
2234         }
2235 done:
2236         ack("DELE");
2237 }
2238
2239 void
2240 cwd(char *path)
2241 {
2242
2243         if (chdir(path) < 0)
2244                 perror_reply(550, path);
2245         else
2246                 ack("CWD");
2247 }
2248
2249 void
2250 makedir(char *name)
2251 {
2252
2253         LOGCMD("mkdir", name);
2254         if (mkdir(name, 0777) < 0)
2255                 perror_reply(550, name);
2256         else
2257                 reply(257, "MKD command successful.");
2258 }
2259
2260 void
2261 removedir(char *name)
2262 {
2263
2264         LOGCMD("rmdir", name);
2265         if (rmdir(name) < 0)
2266                 perror_reply(550, name);
2267         else
2268                 ack("RMD");
2269 }
2270
2271 void
2272 pwd(void)
2273 {
2274         char path[MAXPATHLEN + 1];
2275
2276         if (getwd(path) == (char *)NULL)
2277                 reply(550, "%s.", path);
2278         else
2279                 reply(257, "\"%s\" is current directory.", path);
2280 }
2281
2282 char *
2283 renamefrom(char *name)
2284 {
2285         struct stat st;
2286
2287         if (stat(name, &st) < 0) {
2288                 perror_reply(550, name);
2289                 return ((char *)0);
2290         }
2291         reply(350, "File exists, ready for destination name");
2292         return (name);
2293 }
2294
2295 void
2296 renamecmd(char *from, char *to)
2297 {
2298         struct stat st;
2299
2300         LOGCMD2("rename", from, to);
2301
2302         if (guest && (stat(to, &st) == 0)) {
2303                 reply(550, "%s: permission denied", to);
2304                 return;
2305         }
2306
2307         if (rename(from, to) < 0)
2308                 perror_reply(550, "rename");
2309         else
2310                 ack("RNTO");
2311 }
2312
2313 static void
2314 dolog(struct sockaddr *who)
2315 {
2316         int error;
2317
2318         realhostname_sa(remotehost, sizeof(remotehost) - 1, who, who->sa_len);
2319
2320 #ifdef SETPROCTITLE
2321 #ifdef VIRTUAL_HOSTING
2322         if (thishost != firsthost)
2323                 snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)",
2324                          remotehost, hostname);
2325         else
2326 #endif
2327                 snprintf(proctitle, sizeof(proctitle), "%s: connected",
2328                          remotehost);
2329         setproctitle("%s", proctitle);
2330 #endif /* SETPROCTITLE */
2331
2332         if (logging) {
2333 #ifdef VIRTUAL_HOSTING
2334                 if (thishost != firsthost)
2335                         syslog(LOG_INFO, "connection from %s (to %s)",
2336                                remotehost, hostname);
2337                 else
2338 #endif
2339                 {
2340                         char    who_name[MAXHOSTNAMELEN];
2341
2342                         error = getnameinfo(who, who->sa_len,
2343                                             who_name, sizeof(who_name) - 1,
2344                                             NULL, 0,
2345                                             NI_NUMERICHOST|NI_WITHSCOPEID);
2346                         syslog(LOG_INFO, "connection from %s (%s)", remotehost,
2347                                error == 0 ? who_name : "");
2348                 }
2349         }
2350 }
2351
2352 /*
2353  * Record logout in wtmp file
2354  * and exit with supplied status.
2355  */
2356 void
2357 dologout(int status)
2358 {
2359         /*
2360          * Prevent reception of SIGURG from resulting in a resumption
2361          * back to the main program loop.
2362          */
2363         transflag = 0;
2364
2365         if (logged_in) {
2366                 (void) seteuid((uid_t)0);
2367                 ftpd_logwtmp(ttyline, "", NULL);
2368         }
2369         /* beware of flushing buffers after a SIGPIPE */
2370         _exit(status);
2371 }
2372
2373 static void
2374 sigurg(int signo)
2375 {
2376
2377         recvurg = 1;
2378 }
2379
2380 static void
2381 myoob(void)
2382 {
2383         char *cp;
2384
2385         /* only process if transfer occurring */
2386         if (!transflag)
2387                 return;
2388         cp = tmpline;
2389         if (getline(cp, 7, stdin) == NULL) {
2390                 reply(221, "You could at least say goodbye.");
2391                 dologout(0);
2392         }
2393         upper(cp);
2394         if (strcmp(cp, "ABOR\r\n") == 0) {
2395                 tmpline[0] = '\0';
2396                 reply(426, "Transfer aborted. Data connection closed.");
2397                 reply(226, "Abort successful");
2398         }
2399         if (strcmp(cp, "STAT\r\n") == 0) {
2400                 tmpline[0] = '\0';
2401                 if (file_size != (off_t) -1)
2402                         reply(213, "Status: %qd of %qd bytes transferred",
2403                             byte_count, file_size);
2404                 else
2405                         reply(213, "Status: %qd bytes transferred", byte_count);
2406         }
2407 }
2408
2409 /*
2410  * Note: a response of 425 is not mentioned as a possible response to
2411  *      the PASV command in RFC959. However, it has been blessed as
2412  *      a legitimate response by Jon Postel in a telephone conversation
2413  *      with Rick Adams on 25 Jan 89.
2414  */
2415 void
2416 passive(void)
2417 {
2418         int len;
2419         char *p, *a;
2420
2421         if (pdata >= 0)         /* close old port if one set */
2422                 close(pdata);
2423
2424         pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2425         if (pdata < 0) {
2426                 perror_reply(425, "Can't open passive connection");
2427                 return;
2428         }
2429
2430         (void) seteuid((uid_t)0);
2431
2432 #ifdef IP_PORTRANGE
2433         if (ctrl_addr.su_family == AF_INET) {
2434             int on = restricted_data_ports ? IP_PORTRANGE_HIGH
2435                                            : IP_PORTRANGE_DEFAULT;
2436
2437             if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2438                             (char *)&on, sizeof(on)) < 0)
2439                     goto pasv_error;
2440         }
2441 #endif
2442 #ifdef IPV6_PORTRANGE
2443         if (ctrl_addr.su_family == AF_INET6) {
2444             int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
2445                                            : IPV6_PORTRANGE_DEFAULT;
2446
2447             if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2448                             (char *)&on, sizeof(on)) < 0)
2449                     goto pasv_error;
2450         }
2451 #endif
2452
2453         pasv_addr = ctrl_addr;
2454         pasv_addr.su_port = 0;
2455         if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
2456                 goto pasv_error;
2457
2458         (void) seteuid((uid_t)pw->pw_uid);
2459
2460         len = sizeof(pasv_addr);
2461         if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2462                 goto pasv_error;
2463         if (listen(pdata, 1) < 0)
2464                 goto pasv_error;
2465         if (pasv_addr.su_family == AF_INET)
2466                 a = (char *) &pasv_addr.su_sin.sin_addr;
2467         else if (pasv_addr.su_family == AF_INET6 &&
2468                  IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr))
2469                 a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
2470         else
2471                 goto pasv_error;
2472                 
2473         p = (char *) &pasv_addr.su_port;
2474
2475 #define UC(b) (((int) b) & 0xff)
2476
2477         reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2478                 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2479         return;
2480
2481 pasv_error:
2482         (void) seteuid((uid_t)pw->pw_uid);
2483         (void) close(pdata);
2484         pdata = -1;
2485         perror_reply(425, "Can't open passive connection");
2486         return;
2487 }
2488
2489 /*
2490  * Long Passive defined in RFC 1639.
2491  *     228 Entering Long Passive Mode
2492  *         (af, hal, h1, h2, h3,..., pal, p1, p2...)
2493  */
2494
2495 void
2496 long_passive(char *cmd, int pf)
2497 {
2498         int len;
2499         char *p, *a;
2500
2501         if (pdata >= 0)         /* close old port if one set */
2502                 close(pdata);
2503
2504         if (pf != PF_UNSPEC) {
2505                 if (ctrl_addr.su_family != pf) {
2506                         switch (ctrl_addr.su_family) {
2507                         case AF_INET:
2508                                 pf = 1;
2509                                 break;
2510                         case AF_INET6:
2511                                 pf = 2;
2512                                 break;
2513                         default:
2514                                 pf = 0;
2515                                 break;
2516                         }
2517                         /*
2518                          * XXX
2519                          * only EPRT/EPSV ready clients will understand this
2520                          */
2521                         if (strcmp(cmd, "EPSV") == 0 && pf) {
2522                                 reply(522, "Network protocol mismatch, "
2523                                         "use (%d)", pf);
2524                         } else
2525                                 reply(501, "Network protocol mismatch"); /*XXX*/
2526
2527                         return;
2528                 }
2529         }
2530                 
2531         pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2532         if (pdata < 0) {
2533                 perror_reply(425, "Can't open passive connection");
2534                 return;
2535         }
2536
2537         (void) seteuid((uid_t)0);
2538
2539         pasv_addr = ctrl_addr;
2540         pasv_addr.su_port = 0;
2541         len = pasv_addr.su_len;
2542
2543 #ifdef IP_PORTRANGE
2544         if (ctrl_addr.su_family == AF_INET) {
2545             int on = restricted_data_ports ? IP_PORTRANGE_HIGH
2546                                            : IP_PORTRANGE_DEFAULT;
2547
2548             if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2549                             (char *)&on, sizeof(on)) < 0)
2550                     goto pasv_error;
2551         }
2552 #endif
2553 #ifdef IPV6_PORTRANGE
2554         if (ctrl_addr.su_family == AF_INET6) {
2555             int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
2556                                            : IPV6_PORTRANGE_DEFAULT;
2557
2558             if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2559                             (char *)&on, sizeof(on)) < 0)
2560                     goto pasv_error;
2561         }
2562 #endif
2563
2564         if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0)
2565                 goto pasv_error;
2566
2567         (void) seteuid((uid_t)pw->pw_uid);
2568
2569         if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2570                 goto pasv_error;
2571         if (listen(pdata, 1) < 0)
2572                 goto pasv_error;
2573
2574 #define UC(b) (((int) b) & 0xff)
2575
2576         if (strcmp(cmd, "LPSV") == 0) {
2577                 p = (char *)&pasv_addr.su_port;
2578                 switch (pasv_addr.su_family) {
2579                 case AF_INET:
2580                         a = (char *) &pasv_addr.su_sin.sin_addr;
2581                 v4_reply:
2582                         reply(228,
2583 "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
2584                               4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2585                               2, UC(p[0]), UC(p[1]));
2586                         return;
2587                 case AF_INET6:
2588                         if (IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) {
2589                                 a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
2590                                 goto v4_reply;
2591                         }
2592                         a = (char *) &pasv_addr.su_sin6.sin6_addr;
2593                         reply(228,
2594 "Entering Long Passive Mode "
2595 "(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
2596                               6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2597                               UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
2598                               UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
2599                               UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
2600                               2, UC(p[0]), UC(p[1]));
2601                         return;
2602                 }
2603         } else if (strcmp(cmd, "EPSV") == 0) {
2604                 switch (pasv_addr.su_family) {
2605                 case AF_INET:
2606                 case AF_INET6:
2607                         reply(229, "Entering Extended Passive Mode (|||%d|)",
2608                                 ntohs(pasv_addr.su_port));
2609                         return;
2610                 }
2611         } else {
2612                 /* more proper error code? */
2613         }
2614
2615 pasv_error:
2616         (void) seteuid((uid_t)pw->pw_uid);
2617         (void) close(pdata);
2618         pdata = -1;
2619         perror_reply(425, "Can't open passive connection");
2620         return;
2621 }
2622
2623 /*
2624  * Generate unique name for file with basename "local".
2625  * The file named "local" is already known to exist.
2626  * Generates failure reply on error.
2627  */
2628 static char *
2629 gunique(char *local)
2630 {
2631         static char new[MAXPATHLEN];
2632         struct stat st;
2633         int count;
2634         char *cp;
2635
2636         cp = strrchr(local, '/');
2637         if (cp)
2638                 *cp = '\0';
2639         if (stat(cp ? local : ".", &st) < 0) {
2640                 perror_reply(553, cp ? local : ".");
2641                 return ((char *) 0);
2642         }
2643         if (cp)
2644                 *cp = '/';
2645         /* -4 is for the .nn<null> we put on the end below */
2646         (void) snprintf(new, sizeof(new) - 4, "%s", local);
2647         cp = new + strlen(new);
2648         *cp++ = '.';
2649         for (count = 1; count < 100; count++) {
2650                 (void)sprintf(cp, "%d", count);
2651                 if (stat(new, &st) < 0)
2652                         return (new);
2653         }
2654         reply(452, "Unique file name cannot be created.");
2655         return (NULL);
2656 }
2657
2658 /*
2659  * Format and send reply containing system error number.
2660  */
2661 void
2662 perror_reply(int code, char *string)
2663 {
2664
2665         reply(code, "%s: %s.", string, strerror(errno));
2666 }
2667
2668 static char *onefile[] = {
2669         "",
2670         0
2671 };
2672
2673 void
2674 send_file_list(char *whichf)
2675 {
2676         struct stat st;
2677         DIR *dirp = NULL;
2678         struct dirent *dir;
2679         FILE *dout = NULL;
2680         char **dirlist, *dirname;
2681         int simple = 0;
2682         int freeglob = 0;
2683         glob_t gl;
2684
2685         if (strpbrk(whichf, "~{[*?") != NULL) {
2686                 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
2687
2688                 memset(&gl, 0, sizeof(gl));
2689                 gl.gl_matchc = MAXGLOBARGS;
2690                 flags |= GLOB_LIMIT;
2691                 freeglob = 1;
2692                 if (glob(whichf, flags, 0, &gl)) {
2693                         reply(550, "not found");
2694                         goto out;
2695                 } else if (gl.gl_pathc == 0) {
2696                         errno = ENOENT;
2697                         perror_reply(550, whichf);
2698                         goto out;
2699                 }
2700                 dirlist = gl.gl_pathv;
2701         } else {
2702                 onefile[0] = whichf;
2703                 dirlist = onefile;
2704                 simple = 1;
2705         }
2706
2707         while ((dirname = *dirlist++)) {
2708                 if (stat(dirname, &st) < 0) {
2709                         /*
2710                          * If user typed "ls -l", etc, and the client
2711                          * used NLST, do what the user meant.
2712                          */
2713                         if (dirname[0] == '-' && *dirlist == NULL &&
2714                             transflag == 0) {
2715                                 retrieve(_PATH_LS " %s", dirname);
2716                                 goto out;
2717                         }
2718                         perror_reply(550, whichf);
2719                         if (dout != NULL) {
2720                                 (void) fclose(dout);
2721                                 transflag = 0;
2722                                 data = -1;
2723                                 pdata = -1;
2724                         }
2725                         goto out;
2726                 }
2727
2728                 if (S_ISREG(st.st_mode)) {
2729                         if (dout == NULL) {
2730                                 dout = dataconn("file list", (off_t)-1, "w");
2731                                 if (dout == NULL)
2732                                         goto out;
2733                                 transflag++;
2734                         }
2735                         fprintf(dout, "%s%s\n", dirname,
2736                                 type == TYPE_A ? "\r" : "");
2737                         byte_count += strlen(dirname) + 1;
2738                         continue;
2739                 } else if (!S_ISDIR(st.st_mode))
2740                         continue;
2741
2742                 if ((dirp = opendir(dirname)) == NULL)
2743                         continue;
2744
2745                 while ((dir = readdir(dirp)) != NULL) {
2746                         char nbuf[MAXPATHLEN];
2747
2748                         if (recvurg) {
2749                                 myoob();
2750                                 recvurg = 0;
2751                                 transflag = 0;
2752                                 goto out;
2753                         }
2754
2755                         if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2756                                 continue;
2757                         if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2758                             dir->d_namlen == 2)
2759                                 continue;
2760
2761                         snprintf(nbuf, sizeof(nbuf), 
2762                                 "%s/%s", dirname, dir->d_name);
2763
2764                         /*
2765                          * We have to do a stat to insure it's
2766                          * not a directory or special file.
2767                          */
2768                         if (simple || (stat(nbuf, &st) == 0 &&
2769                             S_ISREG(st.st_mode))) {
2770                                 if (dout == NULL) {
2771                                         dout = dataconn("file list", (off_t)-1,
2772                                                 "w");
2773                                         if (dout == NULL)
2774                                                 goto out;
2775                                         transflag++;
2776                                 }
2777                                 if (nbuf[0] == '.' && nbuf[1] == '/')
2778                                         fprintf(dout, "%s%s\n", &nbuf[2],
2779                                                 type == TYPE_A ? "\r" : "");
2780                                 else
2781                                         fprintf(dout, "%s%s\n", nbuf,
2782                                                 type == TYPE_A ? "\r" : "");
2783                                 byte_count += strlen(nbuf) + 1;
2784                         }
2785                 }
2786                 (void) closedir(dirp);
2787         }
2788
2789         if (dout == NULL)
2790                 reply(550, "No files found.");
2791         else if (ferror(dout) != 0)
2792                 perror_reply(550, "Data connection");
2793         else
2794                 reply(226, "Transfer complete.");
2795
2796         transflag = 0;
2797         if (dout != NULL)
2798                 (void) fclose(dout);
2799         data = -1;
2800         pdata = -1;
2801 out:
2802         if (freeglob) {
2803                 freeglob = 0;
2804                 globfree(&gl);
2805         }
2806 }
2807
2808 void
2809 reapchild(int signo)
2810 {
2811         while (wait3(NULL, WNOHANG, NULL) > 0);
2812 }
2813
2814 #ifdef OLD_SETPROCTITLE
2815 /*
2816  * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
2817  * Warning, since this is usually started from inetd.conf, it often doesn't
2818  * have much of an environment or arglist to overwrite.
2819  */
2820 void
2821 setproctitle(const char *fmt, ...)
2822 {
2823         int i;
2824         va_list ap;
2825         char *p, *bp, ch;
2826         char buf[LINE_MAX];
2827
2828         va_start(ap, fmt);
2829         (void)vsnprintf(buf, sizeof(buf), fmt, ap);
2830
2831         /* make ps print our process name */
2832         p = Argv[0];
2833         *p++ = '-';
2834
2835         i = strlen(buf);
2836         if (i > LastArgv - p - 2) {
2837                 i = LastArgv - p - 2;
2838                 buf[i] = '\0';
2839         }
2840         bp = buf;
2841         while (ch = *bp++)
2842                 if (ch != '\n' && ch != '\r')
2843                         *p++ = ch;
2844         while (p < LastArgv)
2845                 *p++ = ' ';
2846 }
2847 #endif /* OLD_SETPROCTITLE */
2848
2849 static void
2850 logxfer(char *name, off_t size, time_t start)
2851 {
2852         char buf[1024];
2853         char path[MAXPATHLEN + 1];
2854         time_t now;
2855
2856         if (statfd >= 0 && getwd(path) != NULL) {
2857                 time(&now);
2858                 snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%qd!%ld\n",
2859                         ctime(&now)+4, ident, remotehost,
2860                         path, name, (long long)size,
2861                         (long)(now - start + (now == start)));
2862                 write(statfd, buf, strlen(buf));
2863         }
2864 }