GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: libexec/ftpd/ftpd.c Lines: 0 1431 0.0 %
Date: 2017-11-07 Branches: 0 1043 0.0 %

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