109static void reapchild __P((int)); 110static void mcleanup __P((int)); 111static void doit __P((void)); 112static void startup __P((void)); 113static void chkhost __P((struct sockaddr_in *)); 114static int ckqueue __P((struct printer *)); 115static void usage __P((void)); 116/* From rcmd.c: */ 117int __ivaliduser __P((FILE *, u_long, const char *, 118 const char *)); 119 120uid_t uid, euid; 121 122int 123main(argc, argv) 124 int argc; 125 char **argv; 126{ 127 int f, funix, finet, options, fromlen, i, errs; 128 fd_set defreadfds; 129 struct sockaddr_un un, fromunix; 130 struct sockaddr_in sin, frominet; 131 int lfd; 132 sigset_t omask, nmask; 133 struct servent *sp, serv; 134 135 euid = geteuid(); /* these shouldn't be different */ 136 uid = getuid(); 137 options = 0; 138 gethostname(host, sizeof(host)); 139 140 name = "lpd"; 141 142 if (euid != 0) 143 errx(EX_NOPERM,"must run as root"); 144 145 errs = 0; 146 while ((i = getopt(argc, argv, "dl")) != -1) 147 switch (i) { 148 case 'd': 149 options |= SO_DEBUG; 150 break; 151 case 'l': 152 lflag++; 153 break; 154 default: 155 errs++; 156 } 157 argc -= optind; 158 argv += optind; 159 if (errs) 160 usage(); 161 162 if (argc == 1) { 163 if ((i = atoi(argv[0])) == 0) 164 usage(); 165 if (i < 0 || i > USHRT_MAX) 166 errx(EX_USAGE, "port # %d is invalid", i); 167 168 serv.s_port = htons(i); 169 sp = &serv; 170 argc--; 171 } else { 172 sp = getservbyname("printer", "tcp"); 173 if (sp == NULL) 174 errx(EX_OSFILE, "printer/tcp: unknown service"); 175 } 176 177 if (argc != 0) 178 usage(); 179 180 /* 181 * We run chkprintcap right away to catch any errors and blat them 182 * to stderr while we still have it open, rather than sending them 183 * to syslog and leaving the user wondering why lpd started and 184 * then stopped. There should probably be a command-line flag to 185 * ignore errors from chkprintcap. 186 */ 187 { 188 pid_t pid; 189 int status; 190 pid = fork(); 191 if (pid < 0) { 192 err(EX_OSERR, "cannot fork"); 193 } else if (pid == 0) { /* child */ 194 execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); 195 err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); 196 } 197 if (waitpid(pid, &status, 0) < 0) { 198 err(EX_OSERR, "cannot wait"); 199 } 200 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 201 errx(EX_OSFILE, "%d errors in printcap file, exiting", 202 WEXITSTATUS(status)); 203 } 204 205#ifndef DEBUG 206 /* 207 * Set up standard environment by detaching from the parent. 208 */ 209 daemon(0, 0); 210#endif 211 212 openlog("lpd", LOG_PID, LOG_LPR); 213 syslog(LOG_INFO, "restarted"); 214 (void) umask(0); 215 /* 216 * NB: This depends on O_NONBLOCK semantics doing the right thing; 217 * i.e., applying only to the O_EXLOCK and not to the rest of the 218 * open/creation. As of 1997-12-02, this is the case for commonly- 219 * used filesystems. There are other places in this code which 220 * make the same assumption. 221 */ 222 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 223 LOCK_FILE_MODE); 224 if (lfd < 0) { 225 if (errno == EWOULDBLOCK) /* active deamon present */ 226 exit(0); 227 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 228 exit(1); 229 } 230 fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ 231 ftruncate(lfd, 0); 232 /* 233 * write process id for others to know 234 */ 235 sprintf(line, "%u\n", getpid()); 236 f = strlen(line); 237 if (write(lfd, line, f) != f) { 238 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 239 exit(1); 240 } 241 signal(SIGCHLD, reapchild); 242 /* 243 * Restart all the printers. 244 */ 245 startup(); 246 (void) unlink(_PATH_SOCKETNAME); 247 funix = socket(AF_UNIX, SOCK_STREAM, 0); 248 if (funix < 0) { 249 syslog(LOG_ERR, "socket: %m"); 250 exit(1); 251 } 252 253 sigemptyset(&nmask); 254 sigaddset(&nmask, SIGHUP); 255 sigaddset(&nmask, SIGINT); 256 sigaddset(&nmask, SIGQUIT); 257 sigaddset(&nmask, SIGTERM); 258 sigprocmask(SIG_BLOCK, &nmask, &omask); 259 260 (void) umask(07); 261 signal(SIGHUP, mcleanup); 262 signal(SIGINT, mcleanup); 263 signal(SIGQUIT, mcleanup); 264 signal(SIGTERM, mcleanup); 265 memset(&un, 0, sizeof(un)); 266 un.sun_family = AF_UNIX; 267 strcpy(un.sun_path, _PATH_SOCKETNAME); 268#ifndef SUN_LEN 269#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 270#endif 271 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 272 syslog(LOG_ERR, "ubind: %m"); 273 exit(1); 274 } 275 (void) umask(0); 276 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 277 FD_ZERO(&defreadfds); 278 FD_SET(funix, &defreadfds); 279 listen(funix, 5); 280 finet = socket(AF_INET, SOCK_STREAM, 0); 281 if (finet >= 0) { 282 if (options & SO_DEBUG) 283 if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) { 284 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 285 mcleanup(0); 286 } 287 memset(&sin, 0, sizeof(sin)); 288 sin.sin_family = AF_INET; 289 sin.sin_port = sp->s_port; 290 if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 291 syslog(LOG_ERR, "bind: %m"); 292 mcleanup(0); 293 } 294 FD_SET(finet, &defreadfds); 295 listen(finet, 5); 296 } 297 /* 298 * Main loop: accept, do a request, continue. 299 */ 300 memset(&frominet, 0, sizeof(frominet)); 301 memset(&fromunix, 0, sizeof(fromunix)); 302 /* 303 * XXX - should be redone for multi-protocol 304 */ 305 for (;;) { 306 int domain, nfds, s; 307 fd_set readfds; 308 309 FD_COPY(&defreadfds, &readfds); 310 nfds = select(20, &readfds, 0, 0, 0); 311 if (nfds <= 0) { 312 if (nfds < 0 && errno != EINTR) 313 syslog(LOG_WARNING, "select: %m"); 314 continue; 315 } 316 if (FD_ISSET(funix, &readfds)) { 317 domain = AF_UNIX, fromlen = sizeof(fromunix); 318 s = accept(funix, 319 (struct sockaddr *)&fromunix, &fromlen); 320 } else /* if (FD_ISSET(finet, &readfds)) */ { 321 domain = AF_INET, fromlen = sizeof(frominet); 322 s = accept(finet, 323 (struct sockaddr *)&frominet, &fromlen); 324 if (frominet.sin_port == htons(20)) { 325 close(s); 326 continue; 327 } 328 } 329 if (s < 0) { 330 if (errno != EINTR) 331 syslog(LOG_WARNING, "accept: %m"); 332 continue; 333 } 334 if (fork() == 0) { 335 signal(SIGCHLD, SIG_IGN); 336 signal(SIGHUP, SIG_IGN); 337 signal(SIGINT, SIG_IGN); 338 signal(SIGQUIT, SIG_IGN); 339 signal(SIGTERM, SIG_IGN); 340 (void) close(funix); 341 (void) close(finet); 342 dup2(s, 1); 343 (void) close(s); 344 if (domain == AF_INET) { 345 from_remote = 1; 346 chkhost(&frominet); 347 } else 348 from_remote = 0; 349 doit(); 350 exit(0); 351 } 352 (void) close(s); 353 } 354} 355 356static void 357reapchild(signo) 358 int signo; 359{ 360 union wait status; 361 362 while (wait3((int *)&status, WNOHANG, 0) > 0) 363 ; 364} 365 366static void 367mcleanup(signo) 368 int signo; 369{ 370 if (lflag) 371 syslog(LOG_INFO, "exiting"); 372 unlink(_PATH_SOCKETNAME); 373 exit(0); 374} 375 376/* 377 * Stuff for handling job specifications 378 */ 379char *user[MAXUSERS]; /* users to process */ 380int users; /* # of users in user array */ 381int requ[MAXREQUESTS]; /* job number of spool entries */ 382int requests; /* # of spool requests */ 383char *person; /* name of person doing lprm */ 384 385char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */ 386char cbuf[BUFSIZ]; /* command line buffer */ 387char *cmdnames[] = { 388 "null", 389 "printjob", 390 "recvjob", 391 "displayq short", 392 "displayq long", 393 "rmjob" 394}; 395 396static void 397doit() 398{ 399 char *cp, *printer; 400 int n; 401 int status; 402 struct printer myprinter, *pp = &myprinter; 403 404 init_printer(&myprinter); 405 406 for (;;) { 407 cp = cbuf; 408 do { 409 if (cp >= &cbuf[sizeof(cbuf) - 1]) 410 fatal(0, "Command line too long"); 411 if ((n = read(1, cp, 1)) != 1) { 412 if (n < 0) 413 fatal(0, "Lost connection"); 414 return; 415 } 416 } while (*cp++ != '\n'); 417 *--cp = '\0'; 418 cp = cbuf; 419 if (lflag) { 420 if (*cp >= '\1' && *cp <= '\5') 421 syslog(LOG_INFO, "%s requests %s %s", 422 from, cmdnames[(u_char)*cp], cp+1); 423 else 424 syslog(LOG_INFO, "bad request (%d) from %s", 425 *cp, from); 426 } 427 switch (*cp++) { 428 case CMD_CHECK_QUE: /* check the queue, print any jobs there */ 429 startprinting(cp); 430 break; 431 case CMD_TAKE_THIS: /* receive files to be queued */ 432 if (!from_remote) { 433 syslog(LOG_INFO, "illegal request (%d)", *cp); 434 exit(1); 435 } 436 recvjob(cp); 437 break; 438 case CMD_SHOWQ_SHORT: /* display the queue (short form) */ 439 case CMD_SHOWQ_LONG: /* display the queue (long form) */ 440 /* XXX - this all needs to be redone. */ 441 printer = cp; 442 while (*cp) { 443 if (*cp != ' ') { 444 cp++; 445 continue; 446 } 447 *cp++ = '\0'; 448 while (isspace(*cp)) 449 cp++; 450 if (*cp == '\0') 451 break; 452 if (isdigit(*cp)) { 453 if (requests >= MAXREQUESTS) 454 fatal(0, "Too many requests"); 455 requ[requests++] = atoi(cp); 456 } else { 457 if (users >= MAXUSERS) 458 fatal(0, "Too many users"); 459 user[users++] = cp; 460 } 461 } 462 status = getprintcap(printer, pp); 463 if (status < 0) 464 fatal(pp, pcaperr(status)); 465 displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); 466 exit(0); 467 case CMD_RMJOB: /* remove a job from the queue */ 468 if (!from_remote) { 469 syslog(LOG_INFO, "illegal request (%d)", *cp); 470 exit(1); 471 } 472 printer = cp; 473 while (*cp && *cp != ' ') 474 cp++; 475 if (!*cp) 476 break; 477 *cp++ = '\0'; 478 person = cp; 479 while (*cp) { 480 if (*cp != ' ') { 481 cp++; 482 continue; 483 } 484 *cp++ = '\0'; 485 while (isspace(*cp)) 486 cp++; 487 if (*cp == '\0') 488 break; 489 if (isdigit(*cp)) { 490 if (requests >= MAXREQUESTS) 491 fatal(0, "Too many requests"); 492 requ[requests++] = atoi(cp); 493 } else { 494 if (users >= MAXUSERS) 495 fatal(0, "Too many users"); 496 user[users++] = cp; 497 } 498 } 499 rmjob(printer); 500 break; 501 } 502 fatal(0, "Illegal service request"); 503 } 504} 505 506/* 507 * Make a pass through the printcap database and start printing any 508 * files left from the last time the machine went down. 509 */ 510static void 511startup() 512{ 513 int pid, status, more; 514 struct printer myprinter, *pp = &myprinter; 515 516 more = firstprinter(pp, &status); 517 if (status) 518 goto errloop; 519 while (more) { 520 if (ckqueue(pp) <= 0) { 521 goto next; 522 } 523 if (lflag) 524 syslog(LOG_INFO, "work for %s", pp->printer); 525 if ((pid = fork()) < 0) { 526 syslog(LOG_WARNING, "startup: cannot fork"); 527 mcleanup(0); 528 } 529 if (pid == 0) { 530 lastprinter(); 531 printjob(pp); 532 /* NOTREACHED */ 533 } 534 do { 535next: 536 more = nextprinter(pp, &status); 537errloop: 538 if (status) 539 syslog(LOG_WARNING, 540 "printcap for %s has errors, skipping", 541 pp->printer ? pp->printer : "<???>"); 542 } while (more && status); 543 } 544} 545 546/* 547 * Make sure there's some work to do before forking off a child 548 */ 549static int 550ckqueue(pp) 551 struct printer *pp; 552{ 553 register struct dirent *d; 554 DIR *dirp; 555 char *spooldir; 556 557 spooldir = pp->spool_dir; 558 if ((dirp = opendir(spooldir)) == NULL) 559 return (-1); 560 while ((d = readdir(dirp)) != NULL) { 561 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 562 continue; /* daemon control files only */ 563 closedir(dirp); 564 return (1); /* found something */ 565 } 566 closedir(dirp); 567 return (0); 568} 569 570#define DUMMY ":nobody::" 571 572/* 573 * Check to see if the from host has access to the line printer. 574 */ 575static void 576chkhost(f) 577 struct sockaddr_in *f; 578{ 579 register struct hostent *hp; 580 register FILE *hostf; 581 int first = 1; 582 int good = 0; 583 584 /* Need real hostname for temporary filenames */ 585 hp = gethostbyaddr((char *)&f->sin_addr, 586 sizeof(struct in_addr), f->sin_family); 587 if (hp == NULL) 588 fatal(0, "Host name for your address (%s) unknown", 589 inet_ntoa(f->sin_addr)); 590 591 (void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1); 592 from[sizeof(fromb) - 1] = '\0'; 593 from = fromb; 594 595 /* Check for spoof, ala rlogind */ 596 hp = gethostbyname(fromb); 597 if (!hp) 598 fatal(0, "hostname for your address (%s) unknown", 599 inet_ntoa(f->sin_addr)); 600 for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) { 601 if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr, 602 sizeof(f->sin_addr))) 603 good = 1; 604 } 605 if (good == 0) 606 fatal(0, "address for your hostname (%s) not matched", 607 inet_ntoa(f->sin_addr)); 608 609 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 610again: 611 if (hostf) { 612 if (__ivaliduser(hostf, f->sin_addr.s_addr, 613 DUMMY, DUMMY) == 0) { 614 (void) fclose(hostf); 615 return; 616 } 617 (void) fclose(hostf); 618 } 619 if (first == 1) { 620 first = 0; 621 hostf = fopen(_PATH_HOSTSLPD, "r"); 622 goto again; 623 } 624 fatal(0, "Your host does not have line printer access"); 625 /*NOTREACHED*/ 626} 627 628static void 629usage() 630{ 631 fprintf(stderr, "usage: lpd [-dl] [port#]\n"); 632 exit(EX_USAGE); 633}
| 110static void reapchild __P((int)); 111static void mcleanup __P((int)); 112static void doit __P((void)); 113static void startup __P((void)); 114static void chkhost __P((struct sockaddr_in *)); 115static int ckqueue __P((struct printer *)); 116static void usage __P((void)); 117/* From rcmd.c: */ 118int __ivaliduser __P((FILE *, u_long, const char *, 119 const char *)); 120 121uid_t uid, euid; 122 123int 124main(argc, argv) 125 int argc; 126 char **argv; 127{ 128 int f, funix, finet, options, fromlen, i, errs; 129 fd_set defreadfds; 130 struct sockaddr_un un, fromunix; 131 struct sockaddr_in sin, frominet; 132 int lfd; 133 sigset_t omask, nmask; 134 struct servent *sp, serv; 135 136 euid = geteuid(); /* these shouldn't be different */ 137 uid = getuid(); 138 options = 0; 139 gethostname(host, sizeof(host)); 140 141 name = "lpd"; 142 143 if (euid != 0) 144 errx(EX_NOPERM,"must run as root"); 145 146 errs = 0; 147 while ((i = getopt(argc, argv, "dl")) != -1) 148 switch (i) { 149 case 'd': 150 options |= SO_DEBUG; 151 break; 152 case 'l': 153 lflag++; 154 break; 155 default: 156 errs++; 157 } 158 argc -= optind; 159 argv += optind; 160 if (errs) 161 usage(); 162 163 if (argc == 1) { 164 if ((i = atoi(argv[0])) == 0) 165 usage(); 166 if (i < 0 || i > USHRT_MAX) 167 errx(EX_USAGE, "port # %d is invalid", i); 168 169 serv.s_port = htons(i); 170 sp = &serv; 171 argc--; 172 } else { 173 sp = getservbyname("printer", "tcp"); 174 if (sp == NULL) 175 errx(EX_OSFILE, "printer/tcp: unknown service"); 176 } 177 178 if (argc != 0) 179 usage(); 180 181 /* 182 * We run chkprintcap right away to catch any errors and blat them 183 * to stderr while we still have it open, rather than sending them 184 * to syslog and leaving the user wondering why lpd started and 185 * then stopped. There should probably be a command-line flag to 186 * ignore errors from chkprintcap. 187 */ 188 { 189 pid_t pid; 190 int status; 191 pid = fork(); 192 if (pid < 0) { 193 err(EX_OSERR, "cannot fork"); 194 } else if (pid == 0) { /* child */ 195 execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); 196 err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); 197 } 198 if (waitpid(pid, &status, 0) < 0) { 199 err(EX_OSERR, "cannot wait"); 200 } 201 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 202 errx(EX_OSFILE, "%d errors in printcap file, exiting", 203 WEXITSTATUS(status)); 204 } 205 206#ifndef DEBUG 207 /* 208 * Set up standard environment by detaching from the parent. 209 */ 210 daemon(0, 0); 211#endif 212 213 openlog("lpd", LOG_PID, LOG_LPR); 214 syslog(LOG_INFO, "restarted"); 215 (void) umask(0); 216 /* 217 * NB: This depends on O_NONBLOCK semantics doing the right thing; 218 * i.e., applying only to the O_EXLOCK and not to the rest of the 219 * open/creation. As of 1997-12-02, this is the case for commonly- 220 * used filesystems. There are other places in this code which 221 * make the same assumption. 222 */ 223 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 224 LOCK_FILE_MODE); 225 if (lfd < 0) { 226 if (errno == EWOULDBLOCK) /* active deamon present */ 227 exit(0); 228 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 229 exit(1); 230 } 231 fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ 232 ftruncate(lfd, 0); 233 /* 234 * write process id for others to know 235 */ 236 sprintf(line, "%u\n", getpid()); 237 f = strlen(line); 238 if (write(lfd, line, f) != f) { 239 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 240 exit(1); 241 } 242 signal(SIGCHLD, reapchild); 243 /* 244 * Restart all the printers. 245 */ 246 startup(); 247 (void) unlink(_PATH_SOCKETNAME); 248 funix = socket(AF_UNIX, SOCK_STREAM, 0); 249 if (funix < 0) { 250 syslog(LOG_ERR, "socket: %m"); 251 exit(1); 252 } 253 254 sigemptyset(&nmask); 255 sigaddset(&nmask, SIGHUP); 256 sigaddset(&nmask, SIGINT); 257 sigaddset(&nmask, SIGQUIT); 258 sigaddset(&nmask, SIGTERM); 259 sigprocmask(SIG_BLOCK, &nmask, &omask); 260 261 (void) umask(07); 262 signal(SIGHUP, mcleanup); 263 signal(SIGINT, mcleanup); 264 signal(SIGQUIT, mcleanup); 265 signal(SIGTERM, mcleanup); 266 memset(&un, 0, sizeof(un)); 267 un.sun_family = AF_UNIX; 268 strcpy(un.sun_path, _PATH_SOCKETNAME); 269#ifndef SUN_LEN 270#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 271#endif 272 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 273 syslog(LOG_ERR, "ubind: %m"); 274 exit(1); 275 } 276 (void) umask(0); 277 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 278 FD_ZERO(&defreadfds); 279 FD_SET(funix, &defreadfds); 280 listen(funix, 5); 281 finet = socket(AF_INET, SOCK_STREAM, 0); 282 if (finet >= 0) { 283 if (options & SO_DEBUG) 284 if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) { 285 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 286 mcleanup(0); 287 } 288 memset(&sin, 0, sizeof(sin)); 289 sin.sin_family = AF_INET; 290 sin.sin_port = sp->s_port; 291 if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 292 syslog(LOG_ERR, "bind: %m"); 293 mcleanup(0); 294 } 295 FD_SET(finet, &defreadfds); 296 listen(finet, 5); 297 } 298 /* 299 * Main loop: accept, do a request, continue. 300 */ 301 memset(&frominet, 0, sizeof(frominet)); 302 memset(&fromunix, 0, sizeof(fromunix)); 303 /* 304 * XXX - should be redone for multi-protocol 305 */ 306 for (;;) { 307 int domain, nfds, s; 308 fd_set readfds; 309 310 FD_COPY(&defreadfds, &readfds); 311 nfds = select(20, &readfds, 0, 0, 0); 312 if (nfds <= 0) { 313 if (nfds < 0 && errno != EINTR) 314 syslog(LOG_WARNING, "select: %m"); 315 continue; 316 } 317 if (FD_ISSET(funix, &readfds)) { 318 domain = AF_UNIX, fromlen = sizeof(fromunix); 319 s = accept(funix, 320 (struct sockaddr *)&fromunix, &fromlen); 321 } else /* if (FD_ISSET(finet, &readfds)) */ { 322 domain = AF_INET, fromlen = sizeof(frominet); 323 s = accept(finet, 324 (struct sockaddr *)&frominet, &fromlen); 325 if (frominet.sin_port == htons(20)) { 326 close(s); 327 continue; 328 } 329 } 330 if (s < 0) { 331 if (errno != EINTR) 332 syslog(LOG_WARNING, "accept: %m"); 333 continue; 334 } 335 if (fork() == 0) { 336 signal(SIGCHLD, SIG_IGN); 337 signal(SIGHUP, SIG_IGN); 338 signal(SIGINT, SIG_IGN); 339 signal(SIGQUIT, SIG_IGN); 340 signal(SIGTERM, SIG_IGN); 341 (void) close(funix); 342 (void) close(finet); 343 dup2(s, 1); 344 (void) close(s); 345 if (domain == AF_INET) { 346 from_remote = 1; 347 chkhost(&frominet); 348 } else 349 from_remote = 0; 350 doit(); 351 exit(0); 352 } 353 (void) close(s); 354 } 355} 356 357static void 358reapchild(signo) 359 int signo; 360{ 361 union wait status; 362 363 while (wait3((int *)&status, WNOHANG, 0) > 0) 364 ; 365} 366 367static void 368mcleanup(signo) 369 int signo; 370{ 371 if (lflag) 372 syslog(LOG_INFO, "exiting"); 373 unlink(_PATH_SOCKETNAME); 374 exit(0); 375} 376 377/* 378 * Stuff for handling job specifications 379 */ 380char *user[MAXUSERS]; /* users to process */ 381int users; /* # of users in user array */ 382int requ[MAXREQUESTS]; /* job number of spool entries */ 383int requests; /* # of spool requests */ 384char *person; /* name of person doing lprm */ 385 386char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */ 387char cbuf[BUFSIZ]; /* command line buffer */ 388char *cmdnames[] = { 389 "null", 390 "printjob", 391 "recvjob", 392 "displayq short", 393 "displayq long", 394 "rmjob" 395}; 396 397static void 398doit() 399{ 400 char *cp, *printer; 401 int n; 402 int status; 403 struct printer myprinter, *pp = &myprinter; 404 405 init_printer(&myprinter); 406 407 for (;;) { 408 cp = cbuf; 409 do { 410 if (cp >= &cbuf[sizeof(cbuf) - 1]) 411 fatal(0, "Command line too long"); 412 if ((n = read(1, cp, 1)) != 1) { 413 if (n < 0) 414 fatal(0, "Lost connection"); 415 return; 416 } 417 } while (*cp++ != '\n'); 418 *--cp = '\0'; 419 cp = cbuf; 420 if (lflag) { 421 if (*cp >= '\1' && *cp <= '\5') 422 syslog(LOG_INFO, "%s requests %s %s", 423 from, cmdnames[(u_char)*cp], cp+1); 424 else 425 syslog(LOG_INFO, "bad request (%d) from %s", 426 *cp, from); 427 } 428 switch (*cp++) { 429 case CMD_CHECK_QUE: /* check the queue, print any jobs there */ 430 startprinting(cp); 431 break; 432 case CMD_TAKE_THIS: /* receive files to be queued */ 433 if (!from_remote) { 434 syslog(LOG_INFO, "illegal request (%d)", *cp); 435 exit(1); 436 } 437 recvjob(cp); 438 break; 439 case CMD_SHOWQ_SHORT: /* display the queue (short form) */ 440 case CMD_SHOWQ_LONG: /* display the queue (long form) */ 441 /* XXX - this all needs to be redone. */ 442 printer = cp; 443 while (*cp) { 444 if (*cp != ' ') { 445 cp++; 446 continue; 447 } 448 *cp++ = '\0'; 449 while (isspace(*cp)) 450 cp++; 451 if (*cp == '\0') 452 break; 453 if (isdigit(*cp)) { 454 if (requests >= MAXREQUESTS) 455 fatal(0, "Too many requests"); 456 requ[requests++] = atoi(cp); 457 } else { 458 if (users >= MAXUSERS) 459 fatal(0, "Too many users"); 460 user[users++] = cp; 461 } 462 } 463 status = getprintcap(printer, pp); 464 if (status < 0) 465 fatal(pp, pcaperr(status)); 466 displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); 467 exit(0); 468 case CMD_RMJOB: /* remove a job from the queue */ 469 if (!from_remote) { 470 syslog(LOG_INFO, "illegal request (%d)", *cp); 471 exit(1); 472 } 473 printer = cp; 474 while (*cp && *cp != ' ') 475 cp++; 476 if (!*cp) 477 break; 478 *cp++ = '\0'; 479 person = cp; 480 while (*cp) { 481 if (*cp != ' ') { 482 cp++; 483 continue; 484 } 485 *cp++ = '\0'; 486 while (isspace(*cp)) 487 cp++; 488 if (*cp == '\0') 489 break; 490 if (isdigit(*cp)) { 491 if (requests >= MAXREQUESTS) 492 fatal(0, "Too many requests"); 493 requ[requests++] = atoi(cp); 494 } else { 495 if (users >= MAXUSERS) 496 fatal(0, "Too many users"); 497 user[users++] = cp; 498 } 499 } 500 rmjob(printer); 501 break; 502 } 503 fatal(0, "Illegal service request"); 504 } 505} 506 507/* 508 * Make a pass through the printcap database and start printing any 509 * files left from the last time the machine went down. 510 */ 511static void 512startup() 513{ 514 int pid, status, more; 515 struct printer myprinter, *pp = &myprinter; 516 517 more = firstprinter(pp, &status); 518 if (status) 519 goto errloop; 520 while (more) { 521 if (ckqueue(pp) <= 0) { 522 goto next; 523 } 524 if (lflag) 525 syslog(LOG_INFO, "work for %s", pp->printer); 526 if ((pid = fork()) < 0) { 527 syslog(LOG_WARNING, "startup: cannot fork"); 528 mcleanup(0); 529 } 530 if (pid == 0) { 531 lastprinter(); 532 printjob(pp); 533 /* NOTREACHED */ 534 } 535 do { 536next: 537 more = nextprinter(pp, &status); 538errloop: 539 if (status) 540 syslog(LOG_WARNING, 541 "printcap for %s has errors, skipping", 542 pp->printer ? pp->printer : "<???>"); 543 } while (more && status); 544 } 545} 546 547/* 548 * Make sure there's some work to do before forking off a child 549 */ 550static int 551ckqueue(pp) 552 struct printer *pp; 553{ 554 register struct dirent *d; 555 DIR *dirp; 556 char *spooldir; 557 558 spooldir = pp->spool_dir; 559 if ((dirp = opendir(spooldir)) == NULL) 560 return (-1); 561 while ((d = readdir(dirp)) != NULL) { 562 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 563 continue; /* daemon control files only */ 564 closedir(dirp); 565 return (1); /* found something */ 566 } 567 closedir(dirp); 568 return (0); 569} 570 571#define DUMMY ":nobody::" 572 573/* 574 * Check to see if the from host has access to the line printer. 575 */ 576static void 577chkhost(f) 578 struct sockaddr_in *f; 579{ 580 register struct hostent *hp; 581 register FILE *hostf; 582 int first = 1; 583 int good = 0; 584 585 /* Need real hostname for temporary filenames */ 586 hp = gethostbyaddr((char *)&f->sin_addr, 587 sizeof(struct in_addr), f->sin_family); 588 if (hp == NULL) 589 fatal(0, "Host name for your address (%s) unknown", 590 inet_ntoa(f->sin_addr)); 591 592 (void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1); 593 from[sizeof(fromb) - 1] = '\0'; 594 from = fromb; 595 596 /* Check for spoof, ala rlogind */ 597 hp = gethostbyname(fromb); 598 if (!hp) 599 fatal(0, "hostname for your address (%s) unknown", 600 inet_ntoa(f->sin_addr)); 601 for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) { 602 if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr, 603 sizeof(f->sin_addr))) 604 good = 1; 605 } 606 if (good == 0) 607 fatal(0, "address for your hostname (%s) not matched", 608 inet_ntoa(f->sin_addr)); 609 610 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 611again: 612 if (hostf) { 613 if (__ivaliduser(hostf, f->sin_addr.s_addr, 614 DUMMY, DUMMY) == 0) { 615 (void) fclose(hostf); 616 return; 617 } 618 (void) fclose(hostf); 619 } 620 if (first == 1) { 621 first = 0; 622 hostf = fopen(_PATH_HOSTSLPD, "r"); 623 goto again; 624 } 625 fatal(0, "Your host does not have line printer access"); 626 /*NOTREACHED*/ 627} 628 629static void 630usage() 631{ 632 fprintf(stderr, "usage: lpd [-dl] [port#]\n"); 633 exit(EX_USAGE); 634}
|