1 /* $OpenBSD: lpd.c,v 1.2 2019/06/28 13:32:48 deraadt 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 <sys/types.h> 20 #include <sys/stat.h> 21 #include <sys/un.h> 22 #include <sys/wait.h> 23 24 #include <errno.h> 25 #include <getopt.h> 26 #include <pwd.h> 27 #include <stdlib.h> 28 #include <stdio.h> 29 #include <signal.h> 30 #include <string.h> 31 #include <syslog.h> 32 #include <unistd.h> 33 34 #include "lpd.h" 35 36 #include "log.h" 37 #include "proc.h" 38 39 struct lpd_conf *env; 40 struct imsgproc *p_control; 41 struct imsgproc *p_engine; 42 struct imsgproc *p_frontend; 43 struct imsgproc *p_priv; 44 45 static void priv_dispatch_control(struct imsgproc *, struct imsg *, void *); 46 static void priv_dispatch_engine(struct imsgproc *, struct imsg *, void *); 47 static void priv_dispatch_frontend(struct imsgproc *, struct imsg *, void *); 48 static void priv_dispatch_printer(struct imsgproc *, struct imsg *, void *); 49 static void priv_open_listener(struct listener *); 50 static void priv_send_config(void); 51 static void priv_sighandler(int, short, void *); 52 static void priv_shutdown(void); 53 static void priv_run_printer(const char *); 54 55 static char **saved_argv; 56 static int saved_argc; 57 58 static void 59 usage(void) 60 { 61 extern char *__progname; 62 63 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 64 __progname); 65 exit(1); 66 } 67 68 int 69 main(int argc, char **argv) 70 { 71 struct listener *l; 72 struct event evt_sigchld, evt_sigint, evt_sigterm, evt_sighup; 73 const char *conffile = LPD_CONFIG, *reexec = NULL; 74 int sp[2], ch, debug = 0, nflag = 0, verbose = 1; 75 76 saved_argv = argv; 77 saved_argc = argc; 78 79 log_init(1, LOG_LPR); 80 log_setverbose(0); 81 82 while ((ch = getopt(argc, argv, "D:df:nvX:")) != -1) { 83 switch (ch) { 84 case 'D': 85 if (cmdline_symset(optarg) < 0) 86 log_warnx("could not parse macro definition %s", 87 optarg); 88 break; 89 case 'd': 90 debug = 1; 91 break; 92 case 'f': 93 conffile = optarg; 94 break; 95 case 'n': 96 nflag = 1; 97 break; 98 case 'v': 99 verbose++; 100 break; 101 case 'X': 102 reexec = optarg; 103 break; 104 default: 105 usage(); 106 } 107 } 108 109 argv += optind; 110 argc -= optind; 111 112 if (argc || *argv) 113 usage(); 114 115 if (reexec) { 116 if (!strcmp(reexec, "control")) 117 control(debug, verbose); 118 if (!strcmp(reexec, "engine")) 119 engine(debug, verbose); 120 if (!strcmp(reexec, "frontend")) 121 frontend(debug, verbose); 122 if (!strncmp(reexec, "printer:", 8)) 123 printer(debug, verbose, strchr(reexec, ':') + 1); 124 fatalx("unknown process %s", reexec); 125 } 126 127 /* Parse config file. */ 128 env = parse_config(conffile, verbose); 129 if (env == NULL) 130 exit(1); 131 132 if (nflag) { 133 fprintf(stderr, "configuration OK\n"); 134 exit(0); 135 } 136 137 /* Check for root privileges. */ 138 if (geteuid()) 139 fatalx("need root privileges"); 140 141 /* Check for assigned daemon user. */ 142 if (getpwnam(LPD_USER) == NULL) 143 fatalx("unknown user %s", LPD_USER); 144 145 log_init(debug, LOG_LPR); 146 log_setverbose(verbose); 147 log_procinit("priv"); 148 setproctitle("priv"); 149 150 if (!debug) 151 if (daemon(1, 0) == -1) 152 fatal("daemon"); 153 154 log_info("startup"); 155 156 TAILQ_FOREACH(l, &env->listeners, entry) 157 priv_open_listener(l); 158 159 event_init(); 160 161 signal_set(&evt_sigint, SIGINT, priv_sighandler, NULL); 162 signal_add(&evt_sigint, NULL); 163 signal_set(&evt_sigterm, SIGTERM, priv_sighandler, NULL); 164 signal_add(&evt_sigterm, NULL); 165 signal_set(&evt_sigchld, SIGCHLD, priv_sighandler, NULL); 166 signal_add(&evt_sigchld, NULL); 167 signal_set(&evt_sighup, SIGHUP, priv_sighandler, NULL); 168 signal_add(&evt_sighup, NULL); 169 signal(SIGPIPE, SIG_IGN); 170 171 /* Fork and exec unpriviledged processes. */ 172 argv = calloc(saved_argc + 3, sizeof(*argv)); 173 if (argv == NULL) 174 fatal("calloc"); 175 for (argc = 0; argc < saved_argc; argc++) 176 argv[argc] = saved_argv[argc]; 177 argv[argc++] = "-X"; 178 argv[argc++] = ""; 179 argv[argc++] = NULL; 180 181 argv[argc - 2] = "control"; 182 p_control = proc_exec(PROC_CONTROL, argv); 183 if (p_control == NULL) 184 fatalx("cannot exec control process"); 185 proc_setcallback(p_control, priv_dispatch_control, NULL); 186 proc_enable(p_control); 187 188 argv[argc - 2] = "engine"; 189 p_engine = proc_exec(PROC_ENGINE, argv); 190 if (p_engine == NULL) 191 fatalx("cannot exec engine process"); 192 proc_setcallback(p_engine, priv_dispatch_engine, NULL); 193 proc_enable(p_engine); 194 195 argv[argc - 2] = "frontend"; 196 p_frontend = proc_exec(PROC_FRONTEND, argv); 197 if (p_frontend == NULL) 198 fatalx("cannot exec frontend process"); 199 proc_setcallback(p_frontend, priv_dispatch_frontend, NULL); 200 proc_enable(p_frontend); 201 202 /* Connect processes. */ 203 if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, PF_UNSPEC, sp) == -1) 204 fatal("socketpair"); 205 m_compose(p_engine, IMSG_SOCK_FRONTEND, 0, 0, sp[1], NULL, 0); 206 m_compose(p_frontend, IMSG_SOCK_ENGINE, 0, 0, sp[0], NULL, 0); 207 208 priv_send_config(); 209 210 if (pledge("stdio sendfd proc exec", NULL) == -1) 211 fatal("pledge"); 212 213 event_dispatch(); 214 215 priv_shutdown(); 216 217 return (0); 218 } 219 220 static void 221 priv_sighandler(int sig, short ev, void *arg) 222 { 223 pid_t pid; 224 int status; 225 226 switch (sig) { 227 case SIGTERM: 228 case SIGINT: 229 event_loopbreak(); 230 break; 231 case SIGCHLD: 232 do { 233 pid = waitpid(-1, &status, WNOHANG); 234 if (pid <= 0) 235 continue; 236 if (WIFSIGNALED(status)) 237 log_warnx("process %d terminated by signal %d", 238 (int)pid, WTERMSIG(status)); 239 else if (WIFEXITED(status) && WEXITSTATUS(status)) 240 log_warnx("process %d exited with status %d", 241 (int)pid, WEXITSTATUS(status)); 242 else if (WIFEXITED(status)) 243 log_debug("process %d exited normally", 244 (int)pid); 245 else 246 /* WIFSTOPPED or WIFCONTINUED */ 247 continue; 248 } while (pid > 0 || (pid == -1 && errno == EINTR)); 249 break; 250 default: 251 fatalx("signal %d", sig); 252 } 253 } 254 255 static void 256 priv_shutdown(void) 257 { 258 pid_t pid; 259 260 proc_free(p_control); 261 proc_free(p_engine); 262 proc_free(p_frontend); 263 264 do { 265 pid = waitpid(WAIT_MYPGRP, NULL, 0); 266 } while (pid != -1 || (pid == -1 && errno == EINTR)); 267 268 log_info("exiting"); 269 270 exit(0); 271 } 272 273 static void 274 priv_open_listener(struct listener *l) 275 { 276 struct sockaddr_un *su; 277 struct sockaddr *sa; 278 const char *path; 279 mode_t old_umask; 280 int opt, sock, r; 281 282 sa = (struct sockaddr *)&l->ss; 283 284 sock = socket(sa->sa_family, SOCK_STREAM | SOCK_NONBLOCK, 0); 285 if (sock == -1) { 286 if (errno == EAFNOSUPPORT) { 287 log_warn("%s: socket", __func__); 288 return; 289 } 290 fatal("%s: socket", __func__); 291 } 292 293 switch (sa->sa_family) { 294 case AF_LOCAL: 295 su = (struct sockaddr_un *)sa; 296 path = su->sun_path; 297 if (connect(sock, sa, sa->sa_len) == 0) 298 fatalx("%s already in use", path); 299 300 if (unlink(path) == -1) 301 if (errno != ENOENT) 302 fatal("unlink: %s", path); 303 304 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 305 r = bind(sock, sa, sizeof(*su)); 306 (void)umask(old_umask); 307 308 if (r == -1) 309 fatal("bind: %s", path); 310 break; 311 312 case AF_INET: 313 case AF_INET6: 314 opt = 1; 315 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, 316 sizeof(opt)) == -1) 317 fatal("setsockopt: %s", log_fmt_sockaddr(sa)); 318 319 if (bind(sock, sa, sa->sa_len) == -1) 320 fatal("bind: %s", log_fmt_sockaddr(sa)); 321 break; 322 323 default: 324 fatalx("bad address family %d", sa->sa_family); 325 } 326 327 l->sock = sock; 328 } 329 330 static void 331 priv_send_config(void) 332 { 333 struct listener *l; 334 335 m_compose(p_control, IMSG_CONF_START, 0, 0, -1, NULL, 0); 336 m_compose(p_control, IMSG_CONF_END, 0, 0, -1, NULL, 0); 337 338 m_compose(p_engine, IMSG_CONF_START, 0, 0, -1, NULL, 0); 339 m_compose(p_engine, IMSG_CONF_END, 0, 0, -1, NULL, 0); 340 341 m_compose(p_frontend, IMSG_CONF_START, 0, 0, -1, NULL, 0); 342 TAILQ_FOREACH(l, &env->listeners, entry) { 343 m_create(p_frontend, IMSG_CONF_LISTENER, 0, 0, l->sock); 344 m_add_int(p_frontend, l->proto); 345 m_add_sockaddr(p_frontend, (struct sockaddr *)(&l->ss)); 346 m_close(p_frontend); 347 } 348 m_compose(p_frontend, IMSG_CONF_END, 0, 0, -1, NULL, 0); 349 } 350 351 static void 352 priv_dispatch_control(struct imsgproc *proc, struct imsg *imsg, void *arg) 353 { 354 if (imsg == NULL) 355 fatalx("%s: imsg connection lost", __func__); 356 357 if (log_getverbose() > LOGLEVEL_IMSG) 358 log_imsg(proc, imsg); 359 360 switch (imsg->hdr.type) { 361 default: 362 fatalx("%s: unexpected imsg %s", __func__, 363 log_fmt_imsgtype(imsg->hdr.type)); 364 } 365 } 366 367 static void 368 priv_dispatch_engine(struct imsgproc *proc, struct imsg *imsg, void *arg) 369 { 370 const char *prn; 371 372 if (imsg == NULL) 373 fatalx("%s: imsg connection lost", __func__); 374 375 if (log_getverbose() > LOGLEVEL_IMSG) 376 log_imsg(proc, imsg); 377 378 switch (imsg->hdr.type) { 379 case IMSG_LPR_PRINTJOB: 380 m_get_string(proc, &prn); 381 m_end(proc); 382 priv_run_printer(prn); 383 break; 384 default: 385 fatalx("%s: unexpected imsg %s", __func__, 386 log_fmt_imsgtype(imsg->hdr.type)); 387 } 388 } 389 390 static void 391 priv_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg) 392 { 393 if (imsg == NULL) 394 fatalx("%s: imsg connection lost", __func__); 395 396 if (log_getverbose() > LOGLEVEL_IMSG) 397 log_imsg(proc, imsg); 398 399 switch (imsg->hdr.type) { 400 default: 401 fatalx("%s: unexpected imsg %s", __func__, 402 log_fmt_imsgtype(imsg->hdr.type)); 403 } 404 } 405 406 static void 407 priv_dispatch_printer(struct imsgproc *proc, struct imsg *imsg, void *arg) 408 { 409 if (imsg == NULL) { 410 log_debug("printer process ended, pid=%d, printer=%s", 411 proc_getpid(proc), proc_gettitle(proc)); 412 proc_free(proc); 413 return; 414 } 415 416 if (log_getverbose() > LOGLEVEL_IMSG) 417 log_imsg(proc, imsg); 418 419 switch (imsg->hdr.type) { 420 default: 421 fatalx("%s: unexpected imsg %s", __func__, 422 log_fmt_imsgtype(imsg->hdr.type)); 423 } 424 } 425 426 static void 427 priv_run_printer(const char *prn) 428 { 429 struct imsgproc *p; 430 char **argv, *buf; 431 int argc; 432 433 if (asprintf(&buf, "printer:%s", prn) == -1) { 434 log_warn("%s: asprintf", __func__); 435 return; 436 } 437 438 argv = calloc(saved_argc + 4, sizeof(*argv)); 439 if (argv == NULL) { 440 log_warn("%s: calloc", __func__); 441 free(buf); 442 return; 443 } 444 for (argc = 0; argc < saved_argc; argc++) 445 argv[argc] = saved_argv[argc]; 446 argv[argc++] = "-X"; 447 argv[argc++] = buf; 448 argv[argc++] = NULL; 449 450 p = proc_exec(PROC_PRINTER, argv); 451 if (p == NULL) 452 log_warnx("%s: cannot exec printer process", __func__); 453 else { 454 proc_settitle(p, prn); 455 proc_setcallback(p, priv_dispatch_printer, p); 456 proc_enable(p); 457 } 458 459 free(argv); 460 free(buf); 461 } 462