xref: /openbsd/libexec/ftpd/monitor.c (revision 5b133f3f)
1 /*	$OpenBSD: monitor.c,v 1.31 2023/03/08 04:43:05 guenther 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
send_data(int sock,void * buf,size_t len)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
recv_data(int sock,void * buf,size_t len)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
set_monitor_signals(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
monitor_init(void)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
monitor_post_auth(void)209 monitor_post_auth(void)
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)) == -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
handle_cmds(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 				if (pledge("stdio rpath wpath cpath inet recvfd"
299 				    " sendfd proc tty getpw", NULL) == -1)
300 					fatalx("pledge");
301 				/* User-privileged slave */
302 				debugmsg("user-privileged slave started");
303 				return;
304 				/* NOTREACHED */
305 			case AUTH_MONITOR:
306 				if (pledge("stdio inet sendfd recvfd proc",
307 				    NULL) == -1)
308 					fatalx("pledge");
309 				/* Post-auth monitor */
310 				debugmsg("monitor went into post-auth phase");
311 				state = POSTAUTH;
312 				setproctitle("%s: [priv post-auth]",
313 				    remotehost);
314 				slavequit = 1;
315 
316 				send_data(fd_slave, &slavequit,
317 				    sizeof(slavequit));
318 
319 				while (waitpid(preauth_slave_pid, NULL, 0) == -1 &&
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.su_si.si_len != salen)
363 				fatalx("monitor received invalid sockaddr len");
364 
365 			if (sa.su_si.si_family != AF_INET &&
366 			    sa.su_si.si_family != AF_INET6)
367 				fatalx("monitor received invalid addr family");
368 
369 			err = bind(s, (struct sockaddr *)&sa, salen);
370 			serrno = errno;
371 
372 			if (s >= 0)
373 				close(s);
374 
375 			send_data(fd_slave, &err, sizeof(err));
376 			if (err == -1)
377 				send_data(fd_slave, &serrno, sizeof(serrno));
378 			break;
379 		default:
380 			fatalx("monitor received unknown command %d", cmd);
381 			/* NOTREACHED */
382 		}
383 	}
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 void
sig_chld(int signo)398 sig_chld(int signo)
399 {
400 	pid_t pid;
401 	int stat, olderrno = errno;
402 
403 	do {
404 		pid = waitpid(slave_pid, &stat, WNOHANG);
405 		if (pid > 0)
406 			_exit(0);
407 	} while (pid == -1 && errno == EINTR);
408 
409 	errno = olderrno;
410 }
411 
412 void
kill_slave(char * reason)413 kill_slave(char *reason)
414 {
415 	if (slave_pid > 0) {
416 		if (reason)
417 			syslog(LOG_NOTICE, "kill slave %d: %s",
418 			    slave_pid, reason);
419 		kill(slave_pid, SIGQUIT);
420 	}
421 }
422 
423 void
fatalx(char * fmt,...)424 fatalx(char *fmt, ...)
425 {
426 	va_list ap;
427 
428 	va_start(ap, fmt);
429 	vsyslog(LOG_ERR, fmt, ap);
430 	va_end(ap);
431 
432 	kill_slave("fatal error");
433 
434 	_exit(0);
435 }
436 
437 void
debugmsg(char * fmt,...)438 debugmsg(char *fmt, ...)
439 {
440 	va_list ap;
441 
442 	if (debug) {
443 		va_start(ap, fmt);
444 		vsyslog(LOG_DEBUG, fmt, ap);
445 		va_end(ap);
446 	}
447 }
448 
449 void
monitor_user(char * name)450 monitor_user(char *name)
451 {
452 	enum monitor_command cmd;
453 	size_t len;
454 
455 	cmd = CMD_USER;
456 	send_data(fd_monitor, &cmd, sizeof(cmd));
457 
458 	len = strlen(name);
459 	send_data(fd_monitor, &len, sizeof(len));
460 	if (len > 0)
461 		send_data(fd_monitor, name, len);
462 }
463 
464 int
monitor_pass(char * pass)465 monitor_pass(char *pass)
466 {
467 	enum monitor_command cmd;
468 	int quitnow;
469 	size_t len;
470 
471 	cmd = CMD_PASS;
472 	send_data(fd_monitor, &cmd, sizeof(cmd));
473 
474 	len = strlen(pass);
475 	send_data(fd_monitor, &len, sizeof(len));
476 	if (len > 0)
477 		send_data(fd_monitor, pass, len);
478 
479 	recv_data(fd_monitor, &quitnow, sizeof(quitnow));
480 
481 	return (quitnow);
482 }
483 
484 int
monitor_socket(int domain)485 monitor_socket(int domain)
486 {
487 	enum monitor_command cmd;
488 	int s, serrno;
489 
490 	cmd = CMD_SOCKET;
491 	send_data(fd_monitor, &cmd, sizeof(cmd));
492 	send_data(fd_monitor, &domain, sizeof(domain));
493 
494 	s = recv_fd(fd_monitor);
495 	if (s == -1) {
496 		recv_data(fd_monitor, &serrno, sizeof(serrno));
497 		errno = serrno;
498 	}
499 
500 	return (s);
501 }
502 
503 int
monitor_bind(int s,struct sockaddr * name,socklen_t namelen)504 monitor_bind(int s, struct sockaddr *name, socklen_t namelen)
505 {
506 	enum monitor_command cmd;
507 	int ret, serrno;
508 
509 	cmd = CMD_BIND;
510 	send_data(fd_monitor, &cmd, sizeof(cmd));
511 
512 	send_fd(fd_monitor, s);
513 	send_data(fd_monitor, &namelen, sizeof(namelen));
514 	send_data(fd_monitor, name, namelen);
515 
516 	recv_data(fd_monitor, &ret, sizeof(ret));
517 	if (ret == -1) {
518 		recv_data(fd_monitor, &serrno, sizeof(serrno));
519 		errno = serrno;
520 	}
521 
522 	return (ret);
523 }
524