1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)lpd.c 5.8 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 /* 19 * lpd -- line printer daemon. 20 * 21 * Listen for a connection and perform the requested operation. 22 * Operations are: 23 * \1printer\n 24 * check the queue for jobs and print any found. 25 * \2printer\n 26 * receive a job from another machine and queue it. 27 * \3printer [users ...] [jobs ...]\n 28 * return the current state of the queue (short form). 29 * \4printer [users ...] [jobs ...]\n 30 * return the current state of the queue (long form). 31 * \5printer person [users ...] [jobs ...]\n 32 * remove jobs from the queue. 33 * 34 * Strategy to maintain protected spooling area: 35 * 1. Spooling area is writable only by daemon and spooling group 36 * 2. lpr runs setuid root and setgrp spooling group; it uses 37 * root to access any file it wants (verifying things before 38 * with an access call) and group id to know how it should 39 * set up ownership of files in the spooling area. 40 * 3. Files in spooling area are owned by root, group spooling 41 * group, with mode 660. 42 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to 43 * access files and printer. Users can't get to anything 44 * w/o help of lpq and lprm programs. 45 */ 46 47 #include "lp.h" 48 #include "pathnames.h" 49 50 int lflag; /* log requests flag */ 51 52 int reapchild(); 53 int mcleanup(); 54 55 main(argc, argv) 56 int argc; 57 char **argv; 58 { 59 int f, funix, finet, options, defreadfds, fromlen; 60 struct sockaddr_un sun, fromunix; 61 struct sockaddr_in sin, frominet; 62 int omask, lfd; 63 64 gethostname(host, sizeof(host)); 65 name = argv[0]; 66 67 while (--argc > 0) { 68 argv++; 69 if (argv[0][0] == '-') 70 switch (argv[0][1]) { 71 case 'd': 72 options |= SO_DEBUG; 73 break; 74 case 'l': 75 lflag++; 76 break; 77 } 78 } 79 80 #ifndef DEBUG 81 /* 82 * Set up standard environment by detaching from the parent. 83 */ 84 if (fork()) 85 exit(0); 86 for (f = 0; f < 5; f++) 87 (void) close(f); 88 (void) open(_PATH_DEVNULL, O_RDONLY); 89 (void) open(_PATH_DEVNULL, O_WRONLY); 90 (void) dup(1); 91 f = open(_PATH_TTY, O_RDWR); 92 if (f > 0) { 93 ioctl(f, TIOCNOTTY, 0); 94 (void) close(f); 95 } 96 #endif 97 98 openlog("lpd", LOG_PID, LOG_LPR); 99 (void) umask(0); 100 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644); 101 if (lfd < 0) { 102 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 103 exit(1); 104 } 105 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 106 if (errno == EWOULDBLOCK) /* active deamon present */ 107 exit(0); 108 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 109 exit(1); 110 } 111 ftruncate(lfd, 0); 112 /* 113 * write process id for others to know 114 */ 115 sprintf(line, "%u\n", getpid()); 116 f = strlen(line); 117 if (write(lfd, line, f) != f) { 118 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 119 exit(1); 120 } 121 signal(SIGCHLD, reapchild); 122 /* 123 * Restart all the printers. 124 */ 125 startup(); 126 (void) unlink(_PATH_SOCKETNAME); 127 funix = socket(AF_UNIX, SOCK_STREAM, 0); 128 if (funix < 0) { 129 syslog(LOG_ERR, "socket: %m"); 130 exit(1); 131 } 132 #define mask(s) (1 << ((s) - 1)) 133 omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM)); 134 signal(SIGHUP, mcleanup); 135 signal(SIGINT, mcleanup); 136 signal(SIGQUIT, mcleanup); 137 signal(SIGTERM, mcleanup); 138 sun.sun_family = AF_UNIX; 139 strcpy(sun.sun_path, _PATH_SOCKETNAME); 140 if (bind(funix, &sun, strlen(sun.sun_path) + 2) < 0) { 141 syslog(LOG_ERR, "ubind: %m"); 142 exit(1); 143 } 144 sigsetmask(omask); 145 defreadfds = 1 << funix; 146 listen(funix, 5); 147 finet = socket(AF_INET, SOCK_STREAM, 0); 148 if (finet >= 0) { 149 struct servent *sp; 150 151 if (options & SO_DEBUG) 152 if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) { 153 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 154 mcleanup(); 155 } 156 sp = getservbyname("printer", "tcp"); 157 if (sp == NULL) { 158 syslog(LOG_ERR, "printer/tcp: unknown service"); 159 mcleanup(); 160 } 161 sin.sin_family = AF_INET; 162 sin.sin_port = sp->s_port; 163 if (bind(finet, &sin, sizeof(sin), 0) < 0) { 164 syslog(LOG_ERR, "bind: %m"); 165 mcleanup(); 166 } 167 defreadfds |= 1 << finet; 168 listen(finet, 5); 169 } 170 /* 171 * Main loop: accept, do a request, continue. 172 */ 173 for (;;) { 174 int domain, nfds, s, readfds = defreadfds; 175 176 nfds = select(20, &readfds, 0, 0, 0); 177 if (nfds <= 0) { 178 if (nfds < 0 && errno != EINTR) 179 syslog(LOG_WARNING, "select: %m"); 180 continue; 181 } 182 if (readfds & (1 << funix)) { 183 domain = AF_UNIX, fromlen = sizeof(fromunix); 184 s = accept(funix, &fromunix, &fromlen); 185 } else if (readfds & (1 << finet)) { 186 domain = AF_INET, fromlen = sizeof(frominet); 187 s = accept(finet, &frominet, &fromlen); 188 } 189 if (s < 0) { 190 if (errno != EINTR) 191 syslog(LOG_WARNING, "accept: %m"); 192 continue; 193 } 194 if (fork() == 0) { 195 signal(SIGCHLD, SIG_IGN); 196 signal(SIGHUP, SIG_IGN); 197 signal(SIGINT, SIG_IGN); 198 signal(SIGQUIT, SIG_IGN); 199 signal(SIGTERM, SIG_IGN); 200 (void) close(funix); 201 (void) close(finet); 202 dup2(s, 1); 203 (void) close(s); 204 if (domain == AF_INET) 205 chkhost(&frominet); 206 doit(); 207 exit(0); 208 } 209 (void) close(s); 210 } 211 } 212 213 reapchild() 214 { 215 union wait status; 216 217 while (wait3(&status, WNOHANG, 0) > 0) 218 ; 219 } 220 221 mcleanup() 222 { 223 if (lflag) 224 syslog(LOG_INFO, "exiting"); 225 unlink(_PATH_SOCKETNAME); 226 exit(0); 227 } 228 229 /* 230 * Stuff for handling job specifications 231 */ 232 char *user[MAXUSERS]; /* users to process */ 233 int users; /* # of users in user array */ 234 int requ[MAXREQUESTS]; /* job number of spool entries */ 235 int requests; /* # of spool requests */ 236 char *person; /* name of person doing lprm */ 237 238 char fromb[32]; /* buffer for client's machine name */ 239 char cbuf[BUFSIZ]; /* command line buffer */ 240 char *cmdnames[] = { 241 "null", 242 "printjob", 243 "recvjob", 244 "displayq short", 245 "displayq long", 246 "rmjob" 247 }; 248 249 doit() 250 { 251 register char *cp; 252 register int n; 253 254 for (;;) { 255 cp = cbuf; 256 do { 257 if (cp >= &cbuf[sizeof(cbuf) - 1]) 258 fatal("Command line too long"); 259 if ((n = read(1, cp, 1)) != 1) { 260 if (n < 0) 261 fatal("Lost connection"); 262 return; 263 } 264 } while (*cp++ != '\n'); 265 *--cp = '\0'; 266 cp = cbuf; 267 if (lflag) { 268 if (*cp >= '\1' && *cp <= '\5') 269 syslog(LOG_INFO, "%s requests %s %s", 270 from, cmdnames[*cp], cp+1); 271 else 272 syslog(LOG_INFO, "bad request (%d) from %s", 273 *cp, from); 274 } 275 switch (*cp++) { 276 case '\1': /* check the queue and print any jobs there */ 277 printer = cp; 278 printjob(); 279 break; 280 case '\2': /* receive files to be queued */ 281 printer = cp; 282 recvjob(); 283 break; 284 case '\3': /* display the queue (short form) */ 285 case '\4': /* display the queue (long form) */ 286 printer = cp; 287 while (*cp) { 288 if (*cp != ' ') { 289 cp++; 290 continue; 291 } 292 *cp++ = '\0'; 293 while (isspace(*cp)) 294 cp++; 295 if (*cp == '\0') 296 break; 297 if (isdigit(*cp)) { 298 if (requests >= MAXREQUESTS) 299 fatal("Too many requests"); 300 requ[requests++] = atoi(cp); 301 } else { 302 if (users >= MAXUSERS) 303 fatal("Too many users"); 304 user[users++] = cp; 305 } 306 } 307 displayq(cbuf[0] - '\3'); 308 exit(0); 309 case '\5': /* remove a job from the queue */ 310 printer = cp; 311 while (*cp && *cp != ' ') 312 cp++; 313 if (!*cp) 314 break; 315 *cp++ = '\0'; 316 person = cp; 317 while (*cp) { 318 if (*cp != ' ') { 319 cp++; 320 continue; 321 } 322 *cp++ = '\0'; 323 while (isspace(*cp)) 324 cp++; 325 if (*cp == '\0') 326 break; 327 if (isdigit(*cp)) { 328 if (requests >= MAXREQUESTS) 329 fatal("Too many requests"); 330 requ[requests++] = atoi(cp); 331 } else { 332 if (users >= MAXUSERS) 333 fatal("Too many users"); 334 user[users++] = cp; 335 } 336 } 337 rmjob(); 338 break; 339 } 340 fatal("Illegal service request"); 341 } 342 } 343 344 /* 345 * Make a pass through the printcap database and start printing any 346 * files left from the last time the machine went down. 347 */ 348 startup() 349 { 350 char buf[BUFSIZ]; 351 register char *cp; 352 int pid; 353 354 printer = buf; 355 356 /* 357 * Restart the daemons. 358 */ 359 while (getprent(buf) > 0) { 360 for (cp = buf; *cp; cp++) 361 if (*cp == '|' || *cp == ':') { 362 *cp = '\0'; 363 break; 364 } 365 if ((pid = fork()) < 0) { 366 syslog(LOG_WARNING, "startup: cannot fork"); 367 mcleanup(); 368 } 369 if (!pid) { 370 endprent(); 371 printjob(); 372 } 373 } 374 } 375 376 #define DUMMY ":nobody::" 377 378 /* 379 * Check to see if the from host has access to the line printer. 380 */ 381 chkhost(f) 382 struct sockaddr_in *f; 383 { 384 register struct hostent *hp; 385 register FILE *hostf; 386 register char *cp, *sp; 387 char ahost[50]; 388 int first = 1; 389 extern char *inet_ntoa(); 390 int baselen = -1; 391 392 f->sin_port = ntohs(f->sin_port); 393 if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED) 394 fatal("Malformed from address"); 395 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family); 396 if (hp == 0) 397 fatal("Host name for your address (%s) unknown", 398 inet_ntoa(f->sin_addr)); 399 400 strcpy(fromb, hp->h_name); 401 from = fromb; 402 if (!strcmp(from, host)) 403 return; 404 405 sp = fromb; 406 cp = ahost; 407 while (*sp) { 408 if (*sp == '.') { 409 if (baselen == -1) 410 baselen = sp - fromb; 411 *cp++ = *sp++; 412 } else { 413 *cp++ = isupper(*sp) ? tolower(*sp++) : *sp++; 414 } 415 } 416 *cp = '\0'; 417 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 418 again: 419 if (hostf) { 420 if (!_validuser(hostf, ahost, DUMMY, DUMMY, baselen)) { 421 (void) fclose(hostf); 422 return; 423 } 424 (void) fclose(hostf); 425 } 426 if (first == 1) { 427 first = 0; 428 hostf = fopen(_PATH_HOSTSLPD, "r"); 429 goto again; 430 } 431 fatal("Your host does not have line printer access"); 432 } 433