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 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 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 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 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