xref: /openbsd/usr.sbin/lpd/engine.c (revision 73471bf0)
1 /*	$OpenBSD: engine.c,v 1.2 2018/09/05 17:32:56 eric 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
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 priviledges. */
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
83 engine_shutdown()
84 {
85 	lpr_shutdown();
86 
87 	log_debug("exiting");
88 
89 	exit(0);
90 }
91 
92 static void
93 engine_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg)
94 {
95 	struct lp_printer lp;
96 
97 	if (imsg == NULL) {
98 		log_debug("%s: imsg connection lost", __func__);
99 		event_loopexit(NULL);
100 		return;
101 	}
102 
103 	if (log_getverbose() > LOGLEVEL_IMSG)
104 		log_imsg(proc, imsg);
105 
106 	switch (imsg->hdr.type) {
107 	case IMSG_SOCK_FRONTEND:
108 		m_end(proc);
109 
110 		if (imsg->fd == -1)
111 			fatalx("failed to receive frontend socket");
112 
113 		p_frontend = proc_attach(PROC_FRONTEND, imsg->fd);
114 		proc_setcallback(p_frontend, engine_dispatch_frontend, NULL);
115 		proc_enable(p_frontend);
116 		break;
117 
118 	case IMSG_CONF_START:
119 		m_end(proc);
120 		break;
121 
122 	case IMSG_CONF_END:
123 		m_end(proc);
124 
125 		/* Fork a printer process for every queue. */
126 		while (lp_scanprinters(&lp) == 1) {
127 			lpr_printjob(lp.lp_name);
128 			lp_clearprinter(&lp);
129 		}
130 		break;
131 
132 	default:
133 		fatalx("%s: unexpected imsg %s", __func__,
134 		    log_fmt_imsgtype(imsg->hdr.type));
135 	}
136 }
137 
138 static void
139 engine_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg)
140 {
141 	if (imsg == NULL) {
142 		log_debug("%s: imsg connection lost", __func__);
143 		event_loopexit(NULL);
144 		return;
145 	}
146 
147 	if (log_getverbose() > LOGLEVEL_IMSG)
148 		log_imsg(proc, imsg);
149 
150 	switch (imsg->hdr.type) {
151 	case IMSG_GETADDRINFO:
152 	case IMSG_GETNAMEINFO:
153 		resolver_dispatch_request(proc, imsg);
154 		break;
155 
156 	case IMSG_LPR_ALLOWEDHOST:
157 	case IMSG_LPR_DISPLAYQ:
158 	case IMSG_LPR_PRINTJOB:
159 	case IMSG_LPR_RECVJOB:
160 	case IMSG_LPR_RECVJOB_CLEAR:
161 	case IMSG_LPR_RECVJOB_CF:
162 	case IMSG_LPR_RECVJOB_DF:
163 	case IMSG_LPR_RECVJOB_COMMIT:
164 	case IMSG_LPR_RECVJOB_ROLLBACK:
165 	case IMSG_LPR_RMJOB:
166 		lpr_dispatch_frontend(proc, imsg);
167 		break;
168 
169 	default:
170 		fatalx("%s: unexpected imsg %s", __func__,
171 		    log_fmt_imsgtype(imsg->hdr.type));
172 	}
173 }
174