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