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