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