1 1.60 kre /* $NetBSD: lpd.c,v 1.60 2023/04/26 18:25:02 kre Exp $ */ 2 1.7 mrg 3 1.1 cgd /* 4 1.4 cgd * Copyright (c) 1983, 1993, 1994 5 1.4 cgd * The Regents of the University of California. All rights reserved. 6 1.4 cgd * 7 1.1 cgd * 8 1.1 cgd * Redistribution and use in source and binary forms, with or without 9 1.1 cgd * modification, are permitted provided that the following conditions 10 1.1 cgd * are met: 11 1.1 cgd * 1. Redistributions of source code must retain the above copyright 12 1.1 cgd * notice, this list of conditions and the following disclaimer. 13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer in the 15 1.1 cgd * documentation and/or other materials provided with the distribution. 16 1.46 agc * 3. Neither the name of the University nor the names of its contributors 17 1.1 cgd * may be used to endorse or promote products derived from this software 18 1.1 cgd * without specific prior written permission. 19 1.1 cgd * 20 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 cgd * SUCH DAMAGE. 31 1.1 cgd */ 32 1.1 cgd 33 1.11 mikel #include <sys/cdefs.h> 34 1.11 mikel 35 1.1 cgd #ifndef lint 36 1.55 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\ 37 1.55 lukem The Regents of the University of California. All rights reserved."); 38 1.1 cgd #endif /* not lint */ 39 1.1 cgd 40 1.1 cgd #ifndef lint 41 1.10 mikel #if 0 42 1.12 mrg static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; 43 1.10 mikel #else 44 1.60 kre __RCSID("$NetBSD: lpd.c,v 1.60 2023/04/26 18:25:02 kre Exp $"); 45 1.10 mikel #endif 46 1.1 cgd #endif /* not lint */ 47 1.1 cgd 48 1.1 cgd /* 49 1.1 cgd * lpd -- line printer daemon. 50 1.1 cgd * 51 1.1 cgd * Listen for a connection and perform the requested operation. 52 1.1 cgd * Operations are: 53 1.1 cgd * \1printer\n 54 1.1 cgd * check the queue for jobs and print any found. 55 1.1 cgd * \2printer\n 56 1.1 cgd * receive a job from another machine and queue it. 57 1.1 cgd * \3printer [users ...] [jobs ...]\n 58 1.1 cgd * return the current state of the queue (short form). 59 1.1 cgd * \4printer [users ...] [jobs ...]\n 60 1.1 cgd * return the current state of the queue (long form). 61 1.1 cgd * \5printer person [users ...] [jobs ...]\n 62 1.1 cgd * remove jobs from the queue. 63 1.1 cgd * 64 1.1 cgd * Strategy to maintain protected spooling area: 65 1.1 cgd * 1. Spooling area is writable only by daemon and spooling group 66 1.1 cgd * 2. lpr runs setuid root and setgrp spooling group; it uses 67 1.1 cgd * root to access any file it wants (verifying things before 68 1.1 cgd * with an access call) and group id to know how it should 69 1.1 cgd * set up ownership of files in the spooling area. 70 1.1 cgd * 3. Files in spooling area are owned by root, group spooling 71 1.1 cgd * group, with mode 660. 72 1.1 cgd * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to 73 1.1 cgd * access files and printer. Users can't get to anything 74 1.1 cgd * w/o help of lpq and lprm programs. 75 1.1 cgd */ 76 1.1 cgd 77 1.4 cgd #include <sys/param.h> 78 1.4 cgd #include <sys/wait.h> 79 1.4 cgd #include <sys/types.h> 80 1.4 cgd #include <sys/socket.h> 81 1.4 cgd #include <sys/un.h> 82 1.4 cgd #include <sys/stat.h> 83 1.12 mrg #include <sys/file.h> 84 1.39 mycroft #include <sys/poll.h> 85 1.4 cgd #include <netinet/in.h> 86 1.4 cgd 87 1.18 mrg #include <err.h> 88 1.4 cgd #include <netdb.h> 89 1.4 cgd #include <unistd.h> 90 1.4 cgd #include <syslog.h> 91 1.4 cgd #include <signal.h> 92 1.4 cgd #include <errno.h> 93 1.4 cgd #include <fcntl.h> 94 1.4 cgd #include <dirent.h> 95 1.30 mjl #include <stdarg.h> 96 1.4 cgd #include <stdio.h> 97 1.4 cgd #include <stdlib.h> 98 1.4 cgd #include <string.h> 99 1.4 cgd #include <ctype.h> 100 1.11 mikel #include <arpa/inet.h> 101 1.11 mikel 102 1.38 itojun #ifdef LIBWRAP 103 1.38 itojun #include <tcpd.h> 104 1.38 itojun #endif 105 1.38 itojun 106 1.1 cgd #include "lp.h" 107 1.4 cgd #include "lp.local.h" 108 1.1 cgd #include "pathnames.h" 109 1.4 cgd #include "extern.h" 110 1.1 cgd 111 1.21 itojun /* XXX from libc/net/rcmd.c */ 112 1.53 yamt extern int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t, 113 1.35 wiz const char *, const char *); 114 1.21 itojun 115 1.38 itojun #ifdef LIBWRAP 116 1.38 itojun int allow_severity = LOG_AUTH|LOG_INFO; 117 1.38 itojun int deny_severity = LOG_AUTH|LOG_WARNING; 118 1.38 itojun #endif 119 1.38 itojun 120 1.1 cgd int lflag; /* log requests flag */ 121 1.18 mrg int rflag; /* allow of for remote printers */ 122 1.8 perry int sflag; /* secure (no inet) flag */ 123 1.1 cgd int from_remote; /* from remote socket */ 124 1.23 scw char **blist; /* list of addresses to bind(2) to */ 125 1.23 scw int blist_size; 126 1.23 scw int blist_addrs; 127 1.1 cgd 128 1.39 mycroft static void reapchild(int); 129 1.56 joerg __dead static void mcleanup(int); 130 1.39 mycroft static void doit(void); 131 1.39 mycroft static void startup(void); 132 1.39 mycroft static void chkhost(struct sockaddr *, int); 133 1.56 joerg __dead static void usage(void); 134 1.39 mycroft static struct pollfd *socksetup(int, int, const char *, int *); 135 1.57 is static void chkplushost(int, FILE *, char*); 136 1.1 cgd 137 1.5 hpeyerl uid_t uid, euid; 138 1.18 mrg int child_count; 139 1.5 hpeyerl 140 1.30 mjl #define LPD_NOPORTCHK 0001 /* skip reserved-port check */ 141 1.30 mjl 142 1.4 cgd int 143 1.30 mjl main(int argc, char **argv) 144 1.1 cgd { 145 1.52 christos struct sockaddr_storage frm; 146 1.52 christos socklen_t frmlen; 147 1.22 mrg sigset_t nmask, omask; 148 1.39 mycroft int lfd, errs, i, f, nfds; 149 1.39 mycroft struct pollfd *socks; 150 1.32 wiz int child_max = 32; /* more than enough to hose the system */ 151 1.30 mjl int options = 0, check_options = 0; 152 1.26 itojun struct servent *sp; 153 1.26 itojun const char *port = "printer"; 154 1.48 itojun char **newblist; 155 1.1 cgd 156 1.5 hpeyerl euid = geteuid(); /* these shouldn't be different */ 157 1.5 hpeyerl uid = getuid(); 158 1.1 cgd gethostname(host, sizeof(host)); 159 1.16 mrg host[sizeof(host) - 1] = '\0'; 160 1.52 christos setprogname(*argv); 161 1.1 cgd 162 1.13 mrg errs = 0; 163 1.34 hubertf while ((i = getopt(argc, argv, "b:dln:srw:W")) != -1) 164 1.13 mrg switch (i) { 165 1.23 scw case 'b': 166 1.23 scw if (blist_addrs >= blist_size) { 167 1.48 itojun newblist = realloc(blist, 168 1.48 itojun blist_size + sizeof(char *) * 4); 169 1.48 itojun if (newblist == NULL) 170 1.48 itojun err(1, "cant allocate bind addr list"); 171 1.48 itojun blist = newblist; 172 1.23 scw blist_size += sizeof(char *) * 4; 173 1.23 scw } 174 1.23 scw blist[blist_addrs++] = strdup(optarg); 175 1.23 scw break; 176 1.13 mrg case 'd': 177 1.13 mrg options |= SO_DEBUG; 178 1.13 mrg break; 179 1.13 mrg case 'l': 180 1.13 mrg lflag++; 181 1.14 mrg break; 182 1.18 mrg case 'n': 183 1.18 mrg child_max = atoi(optarg); 184 1.18 mrg if (child_max < 0 || child_max > 1024) 185 1.18 mrg errx(1, "invalid number of children: %s", 186 1.18 mrg optarg); 187 1.18 mrg break; 188 1.18 mrg case 'r': 189 1.18 mrg rflag++; 190 1.18 mrg break; 191 1.14 mrg case 's': 192 1.14 mrg sflag++; 193 1.13 mrg break; 194 1.18 mrg case 'w': 195 1.18 mrg wait_time = atoi(optarg); 196 1.18 mrg if (wait_time < 0) 197 1.59 andvar errx(1, "wait time must be positive: %s", 198 1.18 mrg optarg); 199 1.18 mrg if (wait_time < 30) 200 1.18 mrg warnx("warning: wait time less than 30 seconds"); 201 1.18 mrg break; 202 1.30 mjl case 'W':/* allow connections coming from a non-reserved port */ 203 1.30 mjl /* (done by some lpr-implementations for MS-Windows) */ 204 1.30 mjl check_options |= LPD_NOPORTCHK; 205 1.30 mjl break; 206 1.13 mrg default: 207 1.13 mrg errs++; 208 1.13 mrg } 209 1.13 mrg argc -= optind; 210 1.13 mrg argv += optind; 211 1.22 mrg if (errs) 212 1.13 mrg usage(); 213 1.1 cgd 214 1.22 mrg switch (argc) { 215 1.22 mrg case 1: 216 1.22 mrg if ((i = atoi(argv[0])) == 0) 217 1.22 mrg usage(); 218 1.22 mrg if (i < 0 || i > USHRT_MAX) 219 1.22 mrg errx(1, "port # %d is invalid", i); 220 1.22 mrg 221 1.26 itojun port = argv[0]; 222 1.22 mrg break; 223 1.22 mrg case 0: 224 1.26 itojun sp = getservbyname(port, "tcp"); 225 1.22 mrg if (sp == NULL) 226 1.26 itojun errx(1, "%s/tcp: unknown service", port); 227 1.22 mrg break; 228 1.22 mrg default: 229 1.22 mrg usage(); 230 1.22 mrg } 231 1.22 mrg 232 1.1 cgd #ifndef DEBUG 233 1.1 cgd /* 234 1.1 cgd * Set up standard environment by detaching from the parent. 235 1.1 cgd */ 236 1.1 cgd daemon(0, 0); 237 1.1 cgd #endif 238 1.1 cgd 239 1.1 cgd openlog("lpd", LOG_PID, LOG_LPR); 240 1.4 cgd syslog(LOG_INFO, "restarted"); 241 1.9 mrg (void)umask(0); 242 1.1 cgd lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644); 243 1.1 cgd if (lfd < 0) { 244 1.1 cgd syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 245 1.1 cgd exit(1); 246 1.1 cgd } 247 1.1 cgd if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 248 1.40 mycroft if (errno == EWOULDBLOCK) { /* active daemon present */ 249 1.40 mycroft syslog(LOG_ERR, "%s is locked; another lpd is running", 250 1.40 mycroft _PATH_MASTERLOCK); 251 1.1 cgd exit(0); 252 1.40 mycroft } 253 1.1 cgd syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 254 1.1 cgd exit(1); 255 1.1 cgd } 256 1.1 cgd ftruncate(lfd, 0); 257 1.1 cgd /* 258 1.1 cgd * write process id for others to know 259 1.1 cgd */ 260 1.9 mrg (void)snprintf(line, sizeof(line), "%u\n", getpid()); 261 1.1 cgd f = strlen(line); 262 1.1 cgd if (write(lfd, line, f) != f) { 263 1.1 cgd syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 264 1.1 cgd exit(1); 265 1.1 cgd } 266 1.1 cgd signal(SIGCHLD, reapchild); 267 1.1 cgd /* 268 1.1 cgd * Restart all the printers. 269 1.1 cgd */ 270 1.1 cgd startup(); 271 1.22 mrg 272 1.22 mrg sigemptyset(&nmask); 273 1.22 mrg sigaddset(&nmask, SIGHUP); 274 1.22 mrg sigaddset(&nmask, SIGINT); 275 1.22 mrg sigaddset(&nmask, SIGQUIT); 276 1.22 mrg sigaddset(&nmask, SIGTERM); 277 1.22 mrg sigprocmask(SIG_BLOCK, &nmask, &omask); 278 1.22 mrg 279 1.1 cgd signal(SIGHUP, mcleanup); 280 1.1 cgd signal(SIGINT, mcleanup); 281 1.1 cgd signal(SIGQUIT, mcleanup); 282 1.1 cgd signal(SIGTERM, mcleanup); 283 1.39 mycroft 284 1.39 mycroft socks = socksetup(PF_UNSPEC, options, port, &nfds); 285 1.39 mycroft 286 1.22 mrg sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 287 1.1 cgd 288 1.24 scw if (blist != NULL) { 289 1.24 scw for (i = 0; i < blist_addrs; i++) 290 1.24 scw free(blist[i]); 291 1.23 scw free(blist); 292 1.24 scw } 293 1.23 scw 294 1.1 cgd /* 295 1.1 cgd * Main loop: accept, do a request, continue. 296 1.1 cgd */ 297 1.52 christos memset(&frm, 0, sizeof(frm)); 298 1.1 cgd for (;;) { 299 1.41 mycroft int rv, s; 300 1.18 mrg /* "short" so it overflows in about 2 hours */ 301 1.39 mycroft struct timespec sleeptime = {10, 0}; 302 1.18 mrg 303 1.18 mrg while (child_max < child_count) { 304 1.18 mrg syslog(LOG_WARNING, 305 1.39 mycroft "too many children, sleeping for %ld seconds", 306 1.42 lukem (long)sleeptime.tv_sec); 307 1.39 mycroft nanosleep(&sleeptime, NULL); 308 1.39 mycroft sleeptime.tv_sec <<= 1; 309 1.39 mycroft if (sleeptime.tv_sec <= 0) { 310 1.18 mrg syslog(LOG_CRIT, "sleeptime overflowed! help!"); 311 1.39 mycroft sleeptime.tv_sec = 10; 312 1.18 mrg } 313 1.18 mrg } 314 1.1 cgd 315 1.39 mycroft rv = poll(socks, nfds, INFTIM); 316 1.39 mycroft if (rv <= 0) { 317 1.39 mycroft if (rv < 0 && errno != EINTR) 318 1.39 mycroft syslog(LOG_WARNING, "poll: %m"); 319 1.1 cgd continue; 320 1.1 cgd } 321 1.51 lukem s = -1; 322 1.39 mycroft for (i = 0; i < nfds; i++) 323 1.39 mycroft if (socks[i].revents & POLLIN) { 324 1.52 christos frmlen = sizeof(frm); 325 1.41 mycroft s = accept(socks[i].fd, 326 1.52 christos (struct sockaddr *)&frm, &frmlen); 327 1.39 mycroft break; 328 1.39 mycroft } 329 1.1 cgd if (s < 0) { 330 1.1 cgd if (errno != EINTR) 331 1.1 cgd syslog(LOG_WARNING, "accept: %m"); 332 1.1 cgd continue; 333 1.1 cgd } 334 1.18 mrg 335 1.18 mrg switch (fork()) { 336 1.18 mrg case 0: 337 1.54 garbled signal(SIGCHLD, SIG_DFL); 338 1.1 cgd signal(SIGHUP, SIG_IGN); 339 1.1 cgd signal(SIGINT, SIG_IGN); 340 1.1 cgd signal(SIGQUIT, SIG_IGN); 341 1.1 cgd signal(SIGTERM, SIG_IGN); 342 1.39 mycroft for (i = 0; i < nfds; i++) 343 1.39 mycroft (void)close(socks[i].fd); 344 1.44 thorpej dup2(s, STDOUT_FILENO); 345 1.9 mrg (void)close(s); 346 1.52 christos if (frm.ss_family != AF_LOCAL) { 347 1.20 itojun /* for both AF_INET and AF_INET6 */ 348 1.1 cgd from_remote = 1; 349 1.52 christos chkhost((struct sockaddr *)&frm, check_options); 350 1.1 cgd } else 351 1.1 cgd from_remote = 0; 352 1.1 cgd doit(); 353 1.1 cgd exit(0); 354 1.18 mrg case -1: 355 1.18 mrg syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds..."); 356 1.18 mrg sleep(10); 357 1.18 mrg continue; 358 1.18 mrg default: 359 1.18 mrg child_count++; 360 1.1 cgd } 361 1.9 mrg (void)close(s); 362 1.1 cgd } 363 1.1 cgd } 364 1.1 cgd 365 1.57 is /* 366 1.57 is * If there was a forward/backward name resolution mismatch, check 367 1.57 is * that there's a '+' entry in fhost. 368 1.57 is */ 369 1.57 is 370 1.57 is void 371 1.57 is chkplushost(int good, FILE *fhost, char *hst) 372 1.57 is { 373 1.57 is int c1, c2, c3; 374 1.57 is 375 1.57 is if (good) { 376 1.57 is return; 377 1.57 is } 378 1.57 is 379 1.57 is rewind(fhost); 380 1.57 is while (EOF != (c1 = fgetc(fhost))) { 381 1.57 is if (c1 == '+') { 382 1.57 is c2 = fgetc(fhost); 383 1.57 is if (c2 == ' ' || c2 == '\t' || c2 == '\n') { 384 1.57 is return; 385 1.57 is } 386 1.57 is } 387 1.57 is do { 388 1.57 is c3 = fgetc(fhost); 389 1.57 is } while (c3 != EOF && c3 != '\n'); 390 1.57 is } 391 1.57 is fatal("address for your hostname (%s) not matched", hst); 392 1.57 is } 393 1.57 is 394 1.4 cgd static void 395 1.30 mjl reapchild(int signo) 396 1.1 cgd { 397 1.60 kre int status; 398 1.1 cgd 399 1.60 kre while (wait3(&status, WNOHANG, 0) > 0) 400 1.18 mrg child_count--; 401 1.1 cgd } 402 1.1 cgd 403 1.4 cgd static void 404 1.30 mjl mcleanup(int signo) 405 1.1 cgd { 406 1.1 cgd if (lflag) 407 1.1 cgd syslog(LOG_INFO, "exiting"); 408 1.1 cgd unlink(_PATH_SOCKETNAME); 409 1.1 cgd exit(0); 410 1.1 cgd } 411 1.1 cgd 412 1.1 cgd /* 413 1.1 cgd * Stuff for handling job specifications 414 1.1 cgd */ 415 1.1 cgd char *user[MAXUSERS]; /* users to process */ 416 1.1 cgd int users; /* # of users in user array */ 417 1.1 cgd int requ[MAXREQUESTS]; /* job number of spool entries */ 418 1.1 cgd int requests; /* # of spool requests */ 419 1.1 cgd char *person; /* name of person doing lprm */ 420 1.1 cgd 421 1.20 itojun char fromb[NI_MAXHOST]; /* buffer for client's machine name */ 422 1.4 cgd char cbuf[BUFSIZ]; /* command line buffer */ 423 1.52 christos const char *cmdnames[] = { 424 1.1 cgd "null", 425 1.1 cgd "printjob", 426 1.1 cgd "recvjob", 427 1.1 cgd "displayq short", 428 1.1 cgd "displayq long", 429 1.1 cgd "rmjob" 430 1.1 cgd }; 431 1.1 cgd 432 1.4 cgd static void 433 1.30 mjl doit(void) 434 1.1 cgd { 435 1.13 mrg char *cp; 436 1.13 mrg int n; 437 1.1 cgd 438 1.1 cgd for (;;) { 439 1.1 cgd cp = cbuf; 440 1.1 cgd do { 441 1.1 cgd if (cp >= &cbuf[sizeof(cbuf) - 1]) 442 1.1 cgd fatal("Command line too long"); 443 1.31 mjl if ((n = read(STDOUT_FILENO, cp, 1)) != 1) { 444 1.1 cgd if (n < 0) 445 1.1 cgd fatal("Lost connection"); 446 1.1 cgd return; 447 1.1 cgd } 448 1.1 cgd } while (*cp++ != '\n'); 449 1.1 cgd *--cp = '\0'; 450 1.1 cgd cp = cbuf; 451 1.1 cgd if (lflag) { 452 1.18 mrg if (*cp >= '\1' && *cp <= '\5') { 453 1.1 cgd syslog(LOG_INFO, "%s requests %s %s", 454 1.10 mikel from, cmdnames[(int)*cp], cp+1); 455 1.18 mrg setproctitle("serving %s: %s %s", from, 456 1.18 mrg cmdnames[(int)*cp], cp+1); 457 1.18 mrg } 458 1.1 cgd else 459 1.1 cgd syslog(LOG_INFO, "bad request (%d) from %s", 460 1.1 cgd *cp, from); 461 1.1 cgd } 462 1.1 cgd switch (*cp++) { 463 1.1 cgd case '\1': /* check the queue and print any jobs there */ 464 1.1 cgd printer = cp; 465 1.29 mrg if (*printer == '\0') 466 1.29 mrg printer = DEFLP; 467 1.1 cgd printjob(); 468 1.1 cgd break; 469 1.1 cgd case '\2': /* receive files to be queued */ 470 1.1 cgd if (!from_remote) { 471 1.1 cgd syslog(LOG_INFO, "illegal request (%d)", *cp); 472 1.1 cgd exit(1); 473 1.1 cgd } 474 1.1 cgd printer = cp; 475 1.29 mrg if (*printer == '\0') 476 1.29 mrg printer = DEFLP; 477 1.1 cgd recvjob(); 478 1.1 cgd break; 479 1.1 cgd case '\3': /* display the queue (short form) */ 480 1.1 cgd case '\4': /* display the queue (long form) */ 481 1.1 cgd printer = cp; 482 1.29 mrg if (*printer == '\0') 483 1.29 mrg printer = DEFLP; 484 1.1 cgd while (*cp) { 485 1.1 cgd if (*cp != ' ') { 486 1.1 cgd cp++; 487 1.1 cgd continue; 488 1.1 cgd } 489 1.1 cgd *cp++ = '\0'; 490 1.50 dsl while (isspace((unsigned char)*cp)) 491 1.1 cgd cp++; 492 1.1 cgd if (*cp == '\0') 493 1.1 cgd break; 494 1.50 dsl if (isdigit((unsigned char)*cp)) { 495 1.1 cgd if (requests >= MAXREQUESTS) 496 1.1 cgd fatal("Too many requests"); 497 1.1 cgd requ[requests++] = atoi(cp); 498 1.1 cgd } else { 499 1.1 cgd if (users >= MAXUSERS) 500 1.1 cgd fatal("Too many users"); 501 1.1 cgd user[users++] = cp; 502 1.1 cgd } 503 1.1 cgd } 504 1.1 cgd displayq(cbuf[0] - '\3'); 505 1.1 cgd exit(0); 506 1.1 cgd case '\5': /* remove a job from the queue */ 507 1.1 cgd if (!from_remote) { 508 1.1 cgd syslog(LOG_INFO, "illegal request (%d)", *cp); 509 1.1 cgd exit(1); 510 1.1 cgd } 511 1.1 cgd printer = cp; 512 1.29 mrg if (*printer == '\0') 513 1.29 mrg printer = DEFLP; 514 1.1 cgd while (*cp && *cp != ' ') 515 1.1 cgd cp++; 516 1.1 cgd if (!*cp) 517 1.1 cgd break; 518 1.1 cgd *cp++ = '\0'; 519 1.1 cgd person = cp; 520 1.1 cgd while (*cp) { 521 1.1 cgd if (*cp != ' ') { 522 1.1 cgd cp++; 523 1.1 cgd continue; 524 1.1 cgd } 525 1.1 cgd *cp++ = '\0'; 526 1.50 dsl while (isspace((unsigned char)*cp)) 527 1.1 cgd cp++; 528 1.1 cgd if (*cp == '\0') 529 1.1 cgd break; 530 1.50 dsl if (isdigit((unsigned char)*cp)) { 531 1.1 cgd if (requests >= MAXREQUESTS) 532 1.1 cgd fatal("Too many requests"); 533 1.1 cgd requ[requests++] = atoi(cp); 534 1.1 cgd } else { 535 1.1 cgd if (users >= MAXUSERS) 536 1.1 cgd fatal("Too many users"); 537 1.1 cgd user[users++] = cp; 538 1.1 cgd } 539 1.1 cgd } 540 1.1 cgd rmjob(); 541 1.1 cgd break; 542 1.1 cgd } 543 1.1 cgd fatal("Illegal service request"); 544 1.1 cgd } 545 1.1 cgd } 546 1.1 cgd 547 1.1 cgd /* 548 1.1 cgd * Make a pass through the printcap database and start printing any 549 1.1 cgd * files left from the last time the machine went down. 550 1.1 cgd */ 551 1.4 cgd static void 552 1.30 mjl startup(void) 553 1.1 cgd { 554 1.4 cgd char *buf; 555 1.13 mrg char *cp; 556 1.1 cgd 557 1.1 cgd /* 558 1.1 cgd * Restart the daemons. 559 1.1 cgd */ 560 1.4 cgd while (cgetnext(&buf, printcapdb) > 0) { 561 1.12 mrg if (ckqueue(buf) <= 0) { 562 1.12 mrg free(buf); 563 1.12 mrg continue; /* no work to do for this printer */ 564 1.12 mrg } 565 1.1 cgd for (cp = buf; *cp; cp++) 566 1.1 cgd if (*cp == '|' || *cp == ':') { 567 1.1 cgd *cp = '\0'; 568 1.1 cgd break; 569 1.1 cgd } 570 1.12 mrg if (lflag) 571 1.12 mrg syslog(LOG_INFO, "work for %s", buf); 572 1.18 mrg switch (fork()) { 573 1.18 mrg case -1: 574 1.1 cgd syslog(LOG_WARNING, "startup: cannot fork"); 575 1.4 cgd mcleanup(0); 576 1.18 mrg case 0: 577 1.4 cgd printer = buf; 578 1.18 mrg setproctitle("working on printer %s", printer); 579 1.4 cgd cgetclose(); 580 1.1 cgd printjob(); 581 1.12 mrg /* NOTREACHED */ 582 1.18 mrg default: 583 1.18 mrg child_count++; 584 1.18 mrg free(buf); 585 1.1 cgd } 586 1.12 mrg } 587 1.12 mrg } 588 1.12 mrg 589 1.1 cgd #define DUMMY ":nobody::" 590 1.1 cgd 591 1.1 cgd /* 592 1.1 cgd * Check to see if the from host has access to the line printer. 593 1.1 cgd */ 594 1.4 cgd static void 595 1.30 mjl chkhost(struct sockaddr *f, int check_opts) 596 1.1 cgd { 597 1.20 itojun struct addrinfo hints, *res, *r; 598 1.13 mrg FILE *hostf; 599 1.38 itojun int good = 0; 600 1.52 christos char hst[NI_MAXHOST], ip[NI_MAXHOST]; 601 1.20 itojun char serv[NI_MAXSERV]; 602 1.20 itojun int error; 603 1.38 itojun #ifdef LIBWRAP 604 1.38 itojun struct request_info req; 605 1.38 itojun #endif 606 1.20 itojun 607 1.20 itojun error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 608 1.20 itojun NI_NUMERICSERV); 609 1.30 mjl if (error) 610 1.37 grant fatal("Malformed from address: %s", gai_strerror(error)); 611 1.4 cgd 612 1.30 mjl if (!(check_opts & LPD_NOPORTCHK) && 613 1.30 mjl atoi(serv) >= IPPORT_RESERVED) 614 1.30 mjl fatal("Connect from invalid port (%s)", serv); 615 1.30 mjl 616 1.4 cgd /* Need real hostname for temporary filenames */ 617 1.52 christos error = getnameinfo(f, f->sa_len, hst, sizeof(hst), NULL, 0, 618 1.20 itojun NI_NAMEREQD); 619 1.20 itojun if (error) { 620 1.52 christos error = getnameinfo(f, f->sa_len, hst, sizeof(hst), NULL, 0, 621 1.20 itojun NI_NUMERICHOST); 622 1.20 itojun if (error) 623 1.20 itojun fatal("Host name for your address unknown"); 624 1.20 itojun else 625 1.52 christos fatal("Host name for your address (%s) unknown", hst); 626 1.20 itojun } 627 1.1 cgd 628 1.52 christos (void)strlcpy(fromb, hst, sizeof(fromb)); 629 1.1 cgd from = fromb; 630 1.1 cgd 631 1.20 itojun /* need address in stringform for comparison (no DNS lookup here) */ 632 1.52 christos error = getnameinfo(f, f->sa_len, hst, sizeof(hst), NULL, 0, 633 1.20 itojun NI_NUMERICHOST); 634 1.20 itojun if (error) 635 1.20 itojun fatal("Cannot print address"); 636 1.20 itojun 637 1.13 mrg /* Check for spoof, ala rlogind */ 638 1.57 is good = 0; 639 1.20 itojun memset(&hints, 0, sizeof(hints)); 640 1.20 itojun hints.ai_family = PF_UNSPEC; 641 1.20 itojun hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 642 1.20 itojun error = getaddrinfo(fromb, NULL, &hints, &res); 643 1.57 is if (!error) { 644 1.57 is for (r = res; good == 0 && r; r = r->ai_next) { 645 1.57 is error = getnameinfo(r->ai_addr, r->ai_addrlen, 646 1.57 is ip, sizeof(ip), NULL, 0, NI_NUMERICHOST); 647 1.57 is if (!error && !strcmp(hst, ip)) 648 1.57 is good = 1; 649 1.57 is } 650 1.57 is if (res) 651 1.57 is freeaddrinfo(res); 652 1.20 itojun } 653 1.57 is 654 1.57 is /* complain about !good later in chkplushost if needed. */ 655 1.38 itojun 656 1.18 mrg setproctitle("serving %s", from); 657 1.38 itojun 658 1.38 itojun #ifdef LIBWRAP 659 1.44 thorpej request_init(&req, RQ_DAEMON, "lpd", RQ_CLIENT_SIN, f, 660 1.44 thorpej RQ_FILE, STDOUT_FILENO, NULL); 661 1.38 itojun fromhost(&req); 662 1.38 itojun if (!hosts_access(&req)) 663 1.38 itojun goto denied; 664 1.38 itojun #endif 665 1.38 itojun 666 1.1 cgd hostf = fopen(_PATH_HOSTSEQUIV, "r"); 667 1.1 cgd if (hostf) { 668 1.21 itojun if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 669 1.57 is chkplushost(good, hostf, hst); 670 1.9 mrg (void)fclose(hostf); 671 1.1 cgd return; 672 1.1 cgd } 673 1.9 mrg (void)fclose(hostf); 674 1.1 cgd } 675 1.38 itojun hostf = fopen(_PATH_HOSTSLPD, "r"); 676 1.38 itojun if (hostf) { 677 1.38 itojun if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 678 1.57 is chkplushost(good, hostf, hst); 679 1.38 itojun (void)fclose(hostf); 680 1.38 itojun return; 681 1.38 itojun } 682 1.38 itojun (void)fclose(hostf); 683 1.1 cgd } 684 1.38 itojun #ifdef LIBWRAP 685 1.38 itojun denied: 686 1.38 itojun #endif 687 1.1 cgd fatal("Your host does not have line printer access"); 688 1.4 cgd /*NOTREACHED*/ 689 1.13 mrg } 690 1.13 mrg 691 1.30 mjl 692 1.13 mrg static void 693 1.30 mjl usage(void) 694 1.13 mrg { 695 1.13 mrg 696 1.52 christos (void)fprintf(stderr, 697 1.52 christos "Usage: %s [-dlrsW] [-b bind-address] [-n maxchild] " 698 1.28 simonb "[-w maxwait] [port]\n", getprogname()); 699 1.13 mrg exit(1); 700 1.20 itojun } 701 1.20 itojun 702 1.20 itojun /* setup server socket for specified address family */ 703 1.20 itojun /* if af is PF_UNSPEC more than one socket may be returned */ 704 1.20 itojun /* the returned list is dynamically allocated, so caller needs to free it */ 705 1.39 mycroft struct pollfd * 706 1.39 mycroft socksetup(int af, int options, const char *port, int *nfds) 707 1.20 itojun { 708 1.39 mycroft struct sockaddr_un un; 709 1.20 itojun struct addrinfo hints, *res, *r; 710 1.39 mycroft int error, s, blidx = 0, n; 711 1.48 itojun struct pollfd *socks, *newsocks; 712 1.20 itojun const int on = 1; 713 1.20 itojun 714 1.39 mycroft *nfds = 0; 715 1.39 mycroft 716 1.48 itojun socks = malloc(1 * sizeof(socks[0])); 717 1.39 mycroft if (!socks) { 718 1.39 mycroft syslog(LOG_ERR, "couldn't allocate memory for sockets"); 719 1.39 mycroft mcleanup(0); 720 1.39 mycroft } 721 1.39 mycroft 722 1.39 mycroft s = socket(AF_LOCAL, SOCK_STREAM, 0); 723 1.39 mycroft if (s < 0) { 724 1.39 mycroft syslog(LOG_ERR, "socket(): %m"); 725 1.39 mycroft exit(1); 726 1.39 mycroft } 727 1.39 mycroft memset(&un, 0, sizeof(un)); 728 1.39 mycroft un.sun_family = AF_LOCAL; 729 1.39 mycroft strncpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path) - 1); 730 1.39 mycroft un.sun_len = SUN_LEN(&un); 731 1.39 mycroft (void)umask(07); 732 1.39 mycroft (void)unlink(_PATH_SOCKETNAME); 733 1.39 mycroft if (bind(s, (struct sockaddr *)&un, un.sun_len) < 0) { 734 1.39 mycroft syslog(LOG_ERR, "bind(): %m"); 735 1.39 mycroft exit(1); 736 1.39 mycroft } 737 1.39 mycroft (void)umask(0); 738 1.39 mycroft listen(s, 5); 739 1.39 mycroft socks[*nfds].fd = s; 740 1.39 mycroft socks[*nfds].events = POLLIN; 741 1.39 mycroft (*nfds)++; 742 1.39 mycroft 743 1.39 mycroft if (sflag && !blist_addrs) 744 1.39 mycroft return (socks); 745 1.39 mycroft 746 1.23 scw do { 747 1.23 scw memset(&hints, 0, sizeof(hints)); 748 1.23 scw hints.ai_flags = AI_PASSIVE; 749 1.23 scw hints.ai_family = af; 750 1.23 scw hints.ai_socktype = SOCK_STREAM; 751 1.23 scw error = getaddrinfo((blist_addrs == 0) ? NULL : blist[blidx], 752 1.26 itojun port ? port : "printer", &hints, &res); 753 1.23 scw if (error) { 754 1.23 scw if (blist_addrs) 755 1.23 scw syslog(LOG_ERR, "%s: %s", blist[blidx], 756 1.25 itojun gai_strerror(error)); 757 1.23 scw else 758 1.25 itojun syslog(LOG_ERR, "%s", gai_strerror(error)); 759 1.23 scw mcleanup(0); 760 1.23 scw } 761 1.20 itojun 762 1.23 scw /* Count max number of sockets we may open */ 763 1.39 mycroft for (r = res, n = 0; r; r = r->ai_next, n++) 764 1.23 scw ; 765 1.49 itojun newsocks = realloc(socks, (*nfds + n) * sizeof(socks[0])); 766 1.48 itojun if (!newsocks) { 767 1.23 scw syslog(LOG_ERR, "couldn't allocate memory for sockets"); 768 1.23 scw mcleanup(0); 769 1.20 itojun } 770 1.48 itojun socks = newsocks; 771 1.23 scw 772 1.23 scw for (r = res; r; r = r->ai_next) { 773 1.39 mycroft s = socket(r->ai_family, r->ai_socktype, 774 1.39 mycroft r->ai_protocol); 775 1.39 mycroft if (s < 0) { 776 1.23 scw syslog(LOG_DEBUG, "socket(): %m"); 777 1.23 scw continue; 778 1.23 scw } 779 1.23 scw if (options & SO_DEBUG) 780 1.39 mycroft if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 781 1.23 scw &on, sizeof(on)) < 0) { 782 1.23 scw syslog(LOG_ERR, 783 1.23 scw "setsockopt (SO_DEBUG): %m"); 784 1.39 mycroft close(s); 785 1.23 scw continue; 786 1.23 scw } 787 1.39 mycroft if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &on, 788 1.38 itojun sizeof(on)) < 0) { 789 1.38 itojun syslog(LOG_ERR, 790 1.38 itojun "setsockopt (SO_REUSEPORT): %m"); 791 1.43 itojun close(s); 792 1.43 itojun continue; 793 1.43 itojun } 794 1.43 itojun if (r->ai_family == AF_INET6 && setsockopt(s, 795 1.43 itojun IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { 796 1.43 itojun syslog(LOG_ERR, 797 1.43 itojun "setsockopt (IPV6_V6ONLY): %m"); 798 1.39 mycroft close(s); 799 1.38 itojun continue; 800 1.38 itojun } 801 1.39 mycroft if (bind(s, r->ai_addr, r->ai_addrlen) < 0) { 802 1.23 scw syslog(LOG_DEBUG, "bind(): %m"); 803 1.39 mycroft close(s); 804 1.20 itojun continue; 805 1.20 itojun } 806 1.39 mycroft listen(s, 5); 807 1.39 mycroft socks[*nfds].fd = s; 808 1.39 mycroft socks[*nfds].events = POLLIN; 809 1.39 mycroft (*nfds)++; 810 1.20 itojun } 811 1.20 itojun 812 1.23 scw if (res) 813 1.23 scw freeaddrinfo(res); 814 1.23 scw } while (++blidx < blist_addrs); 815 1.20 itojun 816 1.39 mycroft return (socks); 817 1.1 cgd } 818