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

Line Branch Exec Source
1
/*	$OpenBSD: monitor.c,v 1.25 2017/04/17 21:48:26 deraadt Exp $	*/
2
3
/*
4
 * Copyright (c) 2004 Moritz Jodeit <moritz@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/socket.h>
21
#include <sys/wait.h>
22
#include <netinet/in.h>
23
24
#include <errno.h>
25
#include <fcntl.h>
26
#include <paths.h>
27
#include <pwd.h>
28
#include <signal.h>
29
#include <stdarg.h>
30
#include <stdint.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <syslog.h>
35
#include <unistd.h>
36
37
#include "monitor.h"
38
#include "extern.h"
39
40
enum monitor_command {
41
	CMD_USER,
42
	CMD_PASS,
43
	CMD_SOCKET,
44
	CMD_BIND
45
};
46
47
enum monitor_state {
48
	PREAUTH,
49
	POSTAUTH
50
};
51
52
extern char	remotehost[];
53
extern char	ttyline[20];
54
extern int	debug;
55
56
extern void	set_slave_signals(void);
57
58
int	fd_monitor = -1;
59
int	fd_slave = -1;
60
int	nullfd;
61
pid_t	slave_pid = -1;
62
enum monitor_state	state = PREAUTH;
63
64
void	send_data(int, void *, size_t);
65
void	recv_data(int, void *, size_t);
66
void	handle_cmds(void);
67
void	set_monitor_signals(void);
68
void	sig_pass_to_slave(int);
69
void	sig_chld(int);
70
void	fatalx(char *, ...);
71
void	debugmsg(char *, ...);
72
73
/*
74
 * Send data over a socket and exit if something fails.
75
 */
76
void
77
send_data(int sock, void *buf, size_t len)
78
{
79
	ssize_t n;
80
	size_t pos = 0;
81
	char *ptr = buf;
82
83
	while (len > pos) {
84
		switch (n = write(sock, ptr + pos, len - pos)) {
85
		case 0:
86
			kill_slave("write failure");
87
			_exit(0);
88
			/* NOTREACHED */
89
		case -1:
90
			if (errno != EINTR && errno != EAGAIN)
91
				fatalx("send_data: %m");
92
			break;
93
		default:
94
			pos += n;
95
		}
96
	}
97
}
98
99
/*
100
 * Receive data from socket and exit if something fails.
101
 */
102
void
103
recv_data(int sock, void *buf, size_t len)
104
{
105
	ssize_t n;
106
	size_t pos = 0;
107
	char *ptr = buf;
108
109
	while (len > pos) {
110
		switch (n = read(sock, ptr + pos, len - pos)) {
111
		case 0:
112
			kill_slave(NULL);
113
			_exit(0);
114
			/* NOTREACHED */
115
		case -1:
116
			if (errno != EINTR && errno != EAGAIN)
117
				fatalx("recv_data: %m");
118
			break;
119
		default:
120
			pos += n;
121
		}
122
	}
123
}
124
125
void
126
set_monitor_signals(void)
127
{
128
	struct sigaction act;
129
	int i;
130
131
	sigfillset(&act.sa_mask);
132
	act.sa_flags = SA_RESTART;
133
134
	act.sa_handler = SIG_DFL;
135
	for (i = 1; i < _NSIG; i++)
136
		sigaction(i, &act, NULL);
137
138
	act.sa_handler = sig_chld;
139
	sigaction(SIGCHLD, &act, NULL);
140
141
	act.sa_handler = sig_pass_to_slave;
142
	sigaction(SIGHUP, &act, NULL);
143
	sigaction(SIGINT, &act, NULL);
144
	sigaction(SIGQUIT, &act, NULL);
145
	sigaction(SIGTERM, &act, NULL);
146
}
147
148
/*
149
 * Creates the privileged monitor process. It returns twice.
150
 * It returns 1 for the unprivileged slave process and 0 for the
151
 * user-privileged slave process after successful authentication.
152
 */
153
int
154
monitor_init(void)
155
{
156
	struct passwd *pw;
157
	int pair[2];
158
159
	if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, pair) == -1)
160
		fatalx("socketpair failed");
161
162
	fd_monitor = pair[0];
163
	fd_slave = pair[1];
164
165
	set_monitor_signals();
166
167
	slave_pid = fork();
168
	if (slave_pid == -1)
169
		fatalx("fork of unprivileged slave failed");
170
	if (slave_pid == 0) {
171
		/* Unprivileged slave */
172
		set_slave_signals();
173
174
		if ((pw = getpwnam(FTPD_PRIVSEP_USER)) == NULL)
175
			fatalx("privilege separation user %s not found",
176
			    FTPD_PRIVSEP_USER);
177
178
		if (chroot(pw->pw_dir) == -1)
179
			fatalx("chroot %s: %m", pw->pw_dir);
180
		if (chdir("/") == -1)
181
			fatalx("chdir /: %m");
182
183
		if (setgroups(1, &pw->pw_gid) == -1)
184
			fatalx("setgroups: %m");
185
		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
186
			fatalx("setresgid failed");
187
		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
188
			fatalx("setresuid failed");
189
190
		endpwent();
191
		close(fd_slave);
192
		return (1);
193
	}
194
195
	setproctitle("%s: [priv pre-auth]", remotehost);
196
197
	handle_cmds();
198
199
	/* User-privileged slave */
200
	return (0);
201
}
202
203
/*
204
 * Creates the user-privileged slave process. It is called
205
 * from the privileged monitor process and returns twice. It returns 0
206
 * for the user-privileged slave process and 1 for the monitor process.
207
 */
208
int
209
monitor_post_auth()
210
{
211
	slave_pid = fork();
212
	if (slave_pid == -1)
213
		fatalx("fork of user-privileged slave failed");
214
215
	snprintf(ttyline, sizeof(ttyline), "ftp%ld",
216
	    slave_pid == 0 ? (long)getpid() : (long)slave_pid);
217
218
	if (slave_pid == 0) {
219
		/* User privileged slave */
220
		close(fd_slave);
221
		set_slave_signals();
222
		return (0);
223
	}
224
225
	/* We have to keep stdout open, because reply() needs it. */
226
	if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
227
		fatalx("cannot open %s: %m", _PATH_DEVNULL);
228
	dup2(nullfd, STDIN_FILENO);
229
	dup2(nullfd, STDERR_FILENO);
230
	close(nullfd);
231
	close(fd_monitor);
232
233
	return (1);
234
}
235
236
/*
237
 * Handles commands received from the slave process. It will not return
238
 * except in one situation: After successful authentication it will
239
 * return as the user-privileged slave process.
240
 */
241
void
242
handle_cmds(void)
243
{
244
	enum monitor_command cmd;
245
	enum auth_ret auth;
246
	int err, s, slavequit, serrno, domain;
247
	pid_t preauth_slave_pid;
248
	size_t len;
249
	union sockunion sa;
250
	socklen_t salen;
251
	char *name, *pw;
252
253
	for (;;) {
254
		recv_data(fd_slave, &cmd, sizeof(cmd));
255
256
		switch (cmd) {
257
		case CMD_USER:
258
			debugmsg("CMD_USER received");
259
260
			recv_data(fd_slave, &len, sizeof(len));
261
			if (len == SIZE_MAX)
262
				fatalx("monitor received invalid user length");
263
			if ((name = malloc(len + 1)) == NULL)
264
				fatalx("malloc: %m");
265
			if (len > 0)
266
				recv_data(fd_slave, name, len);
267
			name[len] = '\0';
268
269
			user(name);
270
			free(name);
271
			break;
272
		case CMD_PASS:
273
			debugmsg("CMD_PASS received");
274
275
			recv_data(fd_slave, &len, sizeof(len));
276
			if (len == SIZE_MAX)
277
				fatalx("monitor received invalid pass length");
278
			if ((pw = malloc(len + 1)) == NULL)
279
				fatalx("malloc: %m");
280
			if (len > 0)
281
				recv_data(fd_slave, pw, len);
282
			pw[len] = '\0';
283
284
			preauth_slave_pid = slave_pid;
285
286
			auth = pass(pw);
287
			freezero(pw, len);
288
289
			switch (auth) {
290
			case AUTH_FAILED:
291
				/* Authentication failure */
292
				debugmsg("authentication failed");
293
				slavequit = 0;
294
				send_data(fd_slave, &slavequit,
295
				    sizeof(slavequit));
296
				break;
297
			case AUTH_SLAVE:
298
				/* User-privileged slave */
299
				debugmsg("user-privileged slave started");
300
				return;
301
				/* NOTREACHED */
302
			case AUTH_MONITOR:
303
				/* Post-auth monitor */
304
				debugmsg("monitor went into post-auth phase");
305
				state = POSTAUTH;
306
				setproctitle("%s: [priv post-auth]",
307
				    remotehost);
308
				slavequit = 1;
309
310
				send_data(fd_slave, &slavequit,
311
				    sizeof(slavequit));
312
313
				while (waitpid(preauth_slave_pid, NULL, 0) < 0 &&
314
				    errno == EINTR)
315
					;
316
				break;
317
			default:
318
				fatalx("bad return value from pass()");
319
				/* NOTREACHED */
320
			}
321
			break;
322
		case CMD_SOCKET:
323
			debugmsg("CMD_SOCKET received");
324
325
			if (state != POSTAUTH)
326
				fatalx("CMD_SOCKET received in invalid state");
327
328
			recv_data(fd_slave, &domain, sizeof(domain));
329
			if (domain != AF_INET && domain != AF_INET6)
330
				fatalx("monitor received invalid addr family");
331
332
			s = socket(domain, SOCK_STREAM, 0);
333
			serrno = errno;
334
335
			send_fd(fd_slave, s);
336
			if (s == -1)
337
				send_data(fd_slave, &serrno, sizeof(serrno));
338
			else
339
				close(s);
340
			break;
341
		case CMD_BIND:
342
			debugmsg("CMD_BIND received");
343
344
			if (state != POSTAUTH)
345
				fatalx("CMD_BIND received in invalid state");
346
347
			s = recv_fd(fd_slave);
348
349
			recv_data(fd_slave, &salen, sizeof(salen));
350
			if (salen == 0 || salen > sizeof(sa))
351
				fatalx("monitor received invalid sockaddr len");
352
353
			bzero(&sa, sizeof(sa));
354
			recv_data(fd_slave, &sa, salen);
355
356
			if (sa.su_si.si_len != salen)
357
				fatalx("monitor received invalid sockaddr len");
358
359
			if (sa.su_si.si_family != AF_INET &&
360
			    sa.su_si.si_family != AF_INET6)
361
				fatalx("monitor received invalid addr family");
362
363
			err = bind(s, (struct sockaddr *)&sa, salen);
364
			serrno = errno;
365
366
			if (s >= 0)
367
				close(s);
368
369
			send_data(fd_slave, &err, sizeof(err));
370
			if (err == -1)
371
				send_data(fd_slave, &serrno, sizeof(serrno));
372
			break;
373
		default:
374
			fatalx("monitor received unknown command %d", cmd);
375
			/* NOTREACHED */
376
		}
377
	}
378
}
379
380
void
381
sig_pass_to_slave(int signo)
382
{
383
	int olderrno = errno;
384
385
	if (slave_pid > 0)
386
		kill(slave_pid, signo);
387
388
	errno = olderrno;
389
}
390
391
/* ARGSUSED */
392
void
393
sig_chld(int signo)
394
{
395
	pid_t pid;
396
	int stat, olderrno = errno;
397
398
	do {
399
		pid = waitpid(slave_pid, &stat, WNOHANG);
400
		if (pid > 0)
401
			_exit(0);
402
	} while (pid == -1 && errno == EINTR);
403
404
	errno = olderrno;
405
}
406
407
void
408
kill_slave(char *reason)
409
{
410
	if (slave_pid > 0) {
411
		if (reason)
412
			syslog(LOG_NOTICE, "kill slave %d: %s",
413
			    slave_pid, reason);
414
		kill(slave_pid, SIGQUIT);
415
	}
416
}
417
418
void
419
fatalx(char *fmt, ...)
420
{
421
	va_list ap;
422
423
	va_start(ap, fmt);
424
	vsyslog(LOG_ERR, fmt, ap);
425
	va_end(ap);
426
427
	kill_slave("fatal error");
428
429
	_exit(0);
430
}
431
432
void
433
debugmsg(char *fmt, ...)
434
{
435
	va_list ap;
436
437
	if (debug) {
438
		va_start(ap, fmt);
439
		vsyslog(LOG_DEBUG, fmt, ap);
440
		va_end(ap);
441
	}
442
}
443
444
void
445
monitor_user(char *name)
446
{
447
	enum monitor_command cmd;
448
	size_t len;
449
450
	cmd = CMD_USER;
451
	send_data(fd_monitor, &cmd, sizeof(cmd));
452
453
	len = strlen(name);
454
	send_data(fd_monitor, &len, sizeof(len));
455
	if (len > 0)
456
		send_data(fd_monitor, name, len);
457
}
458
459
int
460
monitor_pass(char *pass)
461
{
462
	enum monitor_command cmd;
463
	int quitnow;
464
	size_t len;
465
466
	cmd = CMD_PASS;
467
	send_data(fd_monitor, &cmd, sizeof(cmd));
468
469
	len = strlen(pass);
470
	send_data(fd_monitor, &len, sizeof(len));
471
	if (len > 0)
472
		send_data(fd_monitor, pass, len);
473
474
	recv_data(fd_monitor, &quitnow, sizeof(quitnow));
475
476
	return (quitnow);
477
}
478
479
int
480
monitor_socket(int domain)
481
{
482
	enum monitor_command cmd;
483
	int s, serrno;
484
485
	cmd = CMD_SOCKET;
486
	send_data(fd_monitor, &cmd, sizeof(cmd));
487
	send_data(fd_monitor, &domain, sizeof(domain));
488
489
	s = recv_fd(fd_monitor);
490
	if (s == -1) {
491
		recv_data(fd_monitor, &serrno, sizeof(serrno));
492
		errno = serrno;
493
	}
494
495
	return (s);
496
}
497
498
int
499
monitor_bind(int s, struct sockaddr *name, socklen_t namelen)
500
{
501
	enum monitor_command cmd;
502
	int ret, serrno;
503
504
	cmd = CMD_BIND;
505
	send_data(fd_monitor, &cmd, sizeof(cmd));
506
507
	send_fd(fd_monitor, s);
508
	send_data(fd_monitor, &namelen, sizeof(namelen));
509
	send_data(fd_monitor, name, namelen);
510
511
	recv_data(fd_monitor, &ret, sizeof(ret));
512
	if (ret == -1) {
513
		recv_data(fd_monitor, &serrno, sizeof(serrno));
514
		errno = serrno;
515
	}
516
517
	return (ret);
518
}