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