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