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