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