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