xref: /openbsd-src/usr.sbin/lpd/control.c (revision 12690b15432155c8cdd2d0cd268bc11c914fd725)
1*12690b15Sbluhm /*	$OpenBSD: control.c,v 1.3 2024/03/22 19:14:28 bluhm Exp $	*/
23b188dabSeric 
33b188dabSeric /*
43b188dabSeric  * Copyright (c) 2017 Eric Faurot <eric@openbsd.org>
53b188dabSeric  *
63b188dabSeric  * Permission to use, copy, modify, and distribute this software for any
73b188dabSeric  * purpose with or without fee is hereby granted, provided that the above
83b188dabSeric  * copyright notice and this permission notice appear in all copies.
93b188dabSeric  *
103b188dabSeric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113b188dabSeric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123b188dabSeric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133b188dabSeric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143b188dabSeric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153b188dabSeric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163b188dabSeric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173b188dabSeric  */
183b188dabSeric 
193b188dabSeric #include <sys/types.h>
203b188dabSeric #include <sys/queue.h>
213b188dabSeric #include <sys/stat.h>
223b188dabSeric #include <sys/socket.h>
233b188dabSeric #include <sys/un.h>
243b188dabSeric 
253b188dabSeric #include <errno.h>
263b188dabSeric #include <event.h>
273b188dabSeric #include <imsg.h>
28*12690b15Sbluhm #include <paths.h>
293b188dabSeric #include <pwd.h>
303b188dabSeric #include <signal.h>
313b188dabSeric #include <stdlib.h>
323b188dabSeric #include <string.h>
333b188dabSeric #include <syslog.h>
343b188dabSeric #include <unistd.h>
353b188dabSeric 
363b188dabSeric #include "lpd.h"
373b188dabSeric 
383b188dabSeric #include "log.h"
393b188dabSeric #include "proc.h"
403b188dabSeric 
413b188dabSeric #define	CONTROL_BACKLOG	5
423b188dabSeric 
433b188dabSeric static void control_init(const char *);
443b188dabSeric static void control_listen(void);
453b188dabSeric static void control_pause(void);
463b188dabSeric static void control_resume(void);
473b188dabSeric static void control_accept(int, short, void *);
483b188dabSeric static void control_close(struct imsgproc *);
493b188dabSeric static void control_dispatch_priv(struct imsgproc *, struct imsg *, void *);
503b188dabSeric static void control_dispatch_client(struct imsgproc *, struct imsg *, void *);
513b188dabSeric 
523b188dabSeric static struct {
533b188dabSeric 	struct event	evt;
543b188dabSeric 	int		fd;
553b188dabSeric 	int		pause;
563b188dabSeric } ctl;
573b188dabSeric 
583b188dabSeric void
control(int debug,int verbose)593b188dabSeric control(int debug, int verbose)
603b188dabSeric {
613b188dabSeric 	struct passwd *pw;
623b188dabSeric 
633b188dabSeric 	/* Early initialisation. */
643b188dabSeric 	log_init(debug, LOG_DAEMON);
653b188dabSeric 	log_setverbose(verbose);
663b188dabSeric 	log_procinit("control");
673b188dabSeric 	setproctitle("control");
683b188dabSeric 
693b188dabSeric 	control_init(LPD_SOCKET);
703b188dabSeric 
713a50f0a9Sjmc 	/* Drop privileges. */
723b188dabSeric 	if ((pw = getpwnam(LPD_USER)) == NULL)
733b188dabSeric 		fatalx("unknown user " LPD_USER);
743b188dabSeric 
75*12690b15Sbluhm 	if (chroot(_PATH_VAREMPTY) == -1)
76*12690b15Sbluhm 		fatal("%s: chroot", __func__);
77*12690b15Sbluhm 	if (chdir("/") == -1)
78*12690b15Sbluhm 		fatal("%s: chdir", __func__);
79*12690b15Sbluhm 
803b188dabSeric 	if (setgroups(1, &pw->pw_gid) ||
813b188dabSeric 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
823b188dabSeric 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
833b188dabSeric 		fatal("cannot drop privileges");
843b188dabSeric 
853b188dabSeric 	if (pledge("stdio unix recvfd sendfd", NULL) == -1)
863b188dabSeric 		fatal("%s: pledge", __func__);
873b188dabSeric 
883b188dabSeric 	event_init();
893b188dabSeric 
903b188dabSeric 	signal(SIGPIPE, SIG_IGN);
913b188dabSeric 
923b188dabSeric 	/* Setup imsg socket with parent. */
933b188dabSeric 	p_priv = proc_attach(PROC_PRIV, 3);
943b188dabSeric 	if (p_priv == NULL)
953b188dabSeric 		fatal("%s: proc_attach", __func__);
963b188dabSeric 	proc_setcallback(p_priv, control_dispatch_priv, NULL);
973b188dabSeric 	proc_enable(p_priv);
983b188dabSeric 
993b188dabSeric 	event_dispatch();
1003b188dabSeric 
1013b188dabSeric 	exit(0);
1023b188dabSeric }
1033b188dabSeric 
1043b188dabSeric static void
control_init(const char * path)1053b188dabSeric control_init(const char *path)
1063b188dabSeric {
1073b188dabSeric 	struct sockaddr_un sun;
1083b188dabSeric 	mode_t old_umask;
1093b188dabSeric 	int fd;
1103b188dabSeric 
1113b188dabSeric 	fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
1123b188dabSeric 	if (fd == -1)
1133b188dabSeric 		fatal("%s: socket", __func__);
1143b188dabSeric 
1153b188dabSeric 	memset(&sun, 0, sizeof(sun));
1163b188dabSeric 	sun.sun_family = AF_UNIX;
1173b188dabSeric 	strlcpy(sun.sun_path, LPD_SOCKET, sizeof(sun.sun_path));
1183b188dabSeric 
1193b188dabSeric 	if ((unlink(path) == -1) && (errno != ENOENT))
1203b188dabSeric 		fatal("%s: unlink: %s", __func__, path);
1213b188dabSeric 
1223b188dabSeric 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
1233b188dabSeric 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
1243b188dabSeric 		fatal("%s: bind: %s", __func__, path);
1253b188dabSeric 	umask(old_umask);
1263b188dabSeric 
1273b188dabSeric 	if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1)
1283b188dabSeric 		fatal("%s: chmod: %s", __func__, path);
1293b188dabSeric 
1303b188dabSeric 	ctl.fd = fd;
1313b188dabSeric }
1323b188dabSeric 
1333b188dabSeric static void
control_listen(void)1343b188dabSeric control_listen(void)
1353b188dabSeric {
1363b188dabSeric 	if (listen(ctl.fd, CONTROL_BACKLOG) == -1)
1373b188dabSeric 		fatal("%s: listen", __func__);
1383b188dabSeric 
1393b188dabSeric 	ctl.pause = 0;
1403b188dabSeric 	control_resume();
1413b188dabSeric }
1423b188dabSeric 
1433b188dabSeric static void
control_pause(void)1443b188dabSeric control_pause(void)
1453b188dabSeric {
1463b188dabSeric 	struct timeval tv;
1473b188dabSeric 
1483b188dabSeric 	event_del(&ctl.evt);
1493b188dabSeric 
1503b188dabSeric 	tv.tv_sec = 1;
1513b188dabSeric 	tv.tv_usec = 0;
1523b188dabSeric 
1533b188dabSeric 	evtimer_set(&ctl.evt, control_accept, NULL);
1543b188dabSeric 	evtimer_add(&ctl.evt, &tv);
1553b188dabSeric 	ctl.pause = 1;
1563b188dabSeric }
1573b188dabSeric 
1583b188dabSeric static void
control_resume(void)1593b188dabSeric control_resume(void)
1603b188dabSeric {
1613b188dabSeric 	if (ctl.pause) {
1623b188dabSeric 		evtimer_del(&ctl.evt);
1633b188dabSeric 		ctl.pause = 0;
1643b188dabSeric 	}
1653b188dabSeric 	event_set(&ctl.evt, ctl.fd, EV_READ | EV_PERSIST, control_accept, NULL);
1663b188dabSeric 	event_add(&ctl.evt, NULL);
1673b188dabSeric }
1683b188dabSeric 
1693b188dabSeric static void
control_accept(int fd,short event,void * arg)1703b188dabSeric control_accept(int fd, short event, void *arg)
1713b188dabSeric {
1723b188dabSeric 	struct imsgproc *proc;
1733b188dabSeric 	int sock;
1743b188dabSeric 
1753b188dabSeric 	if (ctl.pause) {
1763b188dabSeric 		ctl.pause = 0;
1773b188dabSeric 		control_resume();
1783b188dabSeric 		return;
1793b188dabSeric 	}
1803b188dabSeric 
1813b188dabSeric 	sock = accept4(ctl.fd, NULL, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK);
1823b188dabSeric 	if (sock == -1) {
1833b188dabSeric 		if (errno == ENFILE || errno == EMFILE)
1843b188dabSeric 			control_pause();
1853b188dabSeric 		else if (errno != EWOULDBLOCK && errno != EINTR &&
1863b188dabSeric 		    errno != ECONNABORTED)
1873b188dabSeric 			log_warn("%s: accept4", __func__);
1883b188dabSeric 		return;
1893b188dabSeric 	}
1903b188dabSeric 
1913b188dabSeric 	proc = proc_attach(PROC_CLIENT, sock);
1923b188dabSeric 	if (proc == NULL) {
1933b188dabSeric 		log_warn("%s: proc_attach", __func__);
1943b188dabSeric 		close(sock);
1953b188dabSeric 		return;
1963b188dabSeric 	}
1973b188dabSeric 	proc_setcallback(proc, control_dispatch_client, NULL);
1983b188dabSeric 	proc_enable(proc);
1993b188dabSeric }
2003b188dabSeric 
2013b188dabSeric static void
control_close(struct imsgproc * proc)2023b188dabSeric control_close(struct imsgproc *proc)
2033b188dabSeric {
2043b188dabSeric 	proc_free(proc);
2053b188dabSeric 
2063b188dabSeric 	if (ctl.pause)
2073b188dabSeric 		control_resume();
2083b188dabSeric }
2093b188dabSeric 
2103b188dabSeric static void
control_dispatch_priv(struct imsgproc * proc,struct imsg * imsg,void * arg)2113b188dabSeric control_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg)
2123b188dabSeric {
2133b188dabSeric 	if (imsg == NULL) {
2143b188dabSeric 		log_debug("%s: imsg connection lost", __func__);
2153b188dabSeric 		event_loopexit(NULL);
2163b188dabSeric 		return;
2173b188dabSeric 	}
2183b188dabSeric 
2193b188dabSeric 	if (log_getverbose() > LOGLEVEL_IMSG)
2203b188dabSeric 		log_imsg(proc, imsg);
2213b188dabSeric 
2223b188dabSeric 	switch (imsg->hdr.type) {
2233b188dabSeric 	case IMSG_CONF_START:
2243b188dabSeric 		m_end(proc);
2253b188dabSeric 		break;
2263b188dabSeric 
2273b188dabSeric 	case IMSG_CONF_END:
2283b188dabSeric 		m_end(proc);
2293b188dabSeric 		control_listen();
2303b188dabSeric 		break;
2313b188dabSeric 
2323b188dabSeric 	default:
2333b188dabSeric 		fatalx("%s: unexpected imsg %s", __func__,
2343b188dabSeric 		    log_fmt_imsgtype(imsg->hdr.type));
2353b188dabSeric 	}
2363b188dabSeric }
2373b188dabSeric 
2383b188dabSeric static void
control_dispatch_client(struct imsgproc * proc,struct imsg * imsg,void * arg)2393b188dabSeric control_dispatch_client(struct imsgproc *proc, struct imsg *imsg, void *arg)
2403b188dabSeric {
2413b188dabSeric 	if (imsg == NULL) {
2423b188dabSeric 		control_close(proc);
2433b188dabSeric 		return;
2443b188dabSeric 	}
2453b188dabSeric 
2463b188dabSeric 	if (log_getverbose() > LOGLEVEL_IMSG)
2473b188dabSeric 		log_imsg(proc, imsg);
2483b188dabSeric 
2493b188dabSeric 	switch (imsg->hdr.type) {
2503b188dabSeric 	default:
2513b188dabSeric 		log_debug("%s: error handling imsg %d", __func__,
2523b188dabSeric 		    imsg->hdr.type);
2533b188dabSeric 	}
2543b188dabSeric }
255