xref: /openbsd/usr.sbin/lpd/engine.c (revision af27b3cc)
1 /*	$OpenBSD: engine.c,v 1.4 2024/11/21 13:34:51 claudio Exp $	*/
2 
3 /*
4  * Copyright (c) 2017 Eric Faurot <eric@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 <pwd.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <syslog.h>
23 #include <unistd.h>
24 
25 #include "lpd.h"
26 #include "lp.h"
27 
28 #include "log.h"
29 #include "proc.h"
30 
31 static void engine_shutdown(void);
32 static void engine_dispatch_priv(struct imsgproc *, struct imsg *, void *);
33 static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *);
34 
35 char *lpd_hostname;
36 
37 void
engine(int debug,int verbose)38 engine(int debug, int verbose)
39 {
40 	struct passwd *pw;
41 
42 	/* Early initialisation. */
43 	log_init(debug, LOG_LPR);
44 	log_setverbose(verbose);
45 	log_procinit("engine");
46 	setproctitle("engine");
47 
48 	if ((lpd_hostname = malloc(HOST_NAME_MAX+1)) == NULL)
49 		fatal("%s: malloc", __func__);
50 	gethostname(lpd_hostname, HOST_NAME_MAX + 1);
51 
52 	/* Drop privileges. */
53 	if ((pw = getpwnam(LPD_USER)) == NULL)
54 		fatal("%s: getpwnam: %s", __func__, LPD_USER);
55 
56 	if (setgroups(1, &pw->pw_gid) ||
57 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
58 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
59 		fatal("%s: cannot drop privileges", __func__);
60 
61 	/* We need proc for kill(2) in lp_getcurrtask(). */
62 	if (pledge("stdio rpath wpath cpath flock dns sendfd recvfd proc",
63 	    NULL) == -1)
64 		fatal("%s: pledge", __func__);
65 
66 	event_init();
67 
68 	signal(SIGPIPE, SIG_IGN);
69 
70 	/* Setup parent imsg socket. */
71 	p_priv = proc_attach(PROC_PRIV, 3);
72 	if (p_priv == NULL)
73 		fatal("%s: proc_attach", __func__);
74 	proc_setcallback(p_priv, engine_dispatch_priv, NULL);
75 	proc_enable(p_priv);
76 
77 	event_dispatch();
78 
79 	engine_shutdown();
80 }
81 
82 static void
engine_shutdown()83 engine_shutdown()
84 {
85 	lpr_shutdown();
86 
87 	log_debug("exiting");
88 
89 	exit(0);
90 }
91 
92 static void
engine_dispatch_priv(struct imsgproc * proc,struct imsg * imsg,void * arg)93 engine_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg)
94 {
95 	struct lp_printer lp;
96 	int fd;
97 
98 	if (imsg == NULL) {
99 		log_debug("%s: imsg connection lost", __func__);
100 		event_loopexit(NULL);
101 		return;
102 	}
103 
104 	if (log_getverbose() > LOGLEVEL_IMSG)
105 		log_imsg(proc, imsg);
106 
107 	switch (imsg->hdr.type) {
108 	case IMSG_SOCK_FRONTEND:
109 		m_end(proc);
110 
111 		if ((fd = imsg_get_fd(imsg)) == -1)
112 			fatalx("failed to receive frontend socket");
113 
114 		p_frontend = proc_attach(PROC_FRONTEND, fd);
115 		proc_setcallback(p_frontend, engine_dispatch_frontend, NULL);
116 		proc_enable(p_frontend);
117 		break;
118 
119 	case IMSG_CONF_START:
120 		m_end(proc);
121 		break;
122 
123 	case IMSG_CONF_END:
124 		m_end(proc);
125 
126 		/* Fork a printer process for every queue. */
127 		while (lp_scanprinters(&lp) == 1) {
128 			lpr_printjob(lp.lp_name);
129 			lp_clearprinter(&lp);
130 		}
131 		break;
132 
133 	default:
134 		fatalx("%s: unexpected imsg %s", __func__,
135 		    log_fmt_imsgtype(imsg->hdr.type));
136 	}
137 }
138 
139 static void
engine_dispatch_frontend(struct imsgproc * proc,struct imsg * imsg,void * arg)140 engine_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg)
141 {
142 	if (imsg == NULL) {
143 		log_debug("%s: imsg connection lost", __func__);
144 		event_loopexit(NULL);
145 		return;
146 	}
147 
148 	if (log_getverbose() > LOGLEVEL_IMSG)
149 		log_imsg(proc, imsg);
150 
151 	switch (imsg->hdr.type) {
152 	case IMSG_GETADDRINFO:
153 	case IMSG_GETNAMEINFO:
154 		resolver_dispatch_request(proc, imsg);
155 		break;
156 
157 	case IMSG_LPR_ALLOWEDHOST:
158 	case IMSG_LPR_DISPLAYQ:
159 	case IMSG_LPR_PRINTJOB:
160 	case IMSG_LPR_RECVJOB:
161 	case IMSG_LPR_RECVJOB_CLEAR:
162 	case IMSG_LPR_RECVJOB_CF:
163 	case IMSG_LPR_RECVJOB_DF:
164 	case IMSG_LPR_RECVJOB_COMMIT:
165 	case IMSG_LPR_RECVJOB_ROLLBACK:
166 	case IMSG_LPR_RMJOB:
167 		lpr_dispatch_frontend(proc, imsg);
168 		break;
169 
170 	default:
171 		fatalx("%s: unexpected imsg %s", __func__,
172 		    log_fmt_imsgtype(imsg->hdr.type));
173 	}
174 }
175