1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2016 by Delphix. All rights reserved. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #include <pwd.h> 31 #include <zone.h> 32 #if defined PS_FAULTED 33 #undef PS_FAULTED 34 #endif /* PS_FAULTED */ 35 #include <dial.h> 36 37 #include <stdlib.h> 38 #include "limits.h" 39 #include "stdarg.h" 40 #include "wait.h" 41 #include "dial.h" 42 #include "lpsched.h" 43 #include <syslog.h> 44 #include "tsol/label.h" 45 46 #define Done(EC,ERRNO) done(((EC) << 8),ERRNO) 47 48 #define STRLCAT(dst, src, size) \ 49 if (strlcat((dst), (src), (size)) >= (size)) { \ 50 errno = EINVAL; \ 51 return (-1); \ 52 } 53 54 static MESG * ChildMd; 55 56 static int ChildPid; 57 static int WaitedChildPid; 58 static int do_undial; 59 60 static char argbuf[ARG_MAX]; 61 62 static long key; 63 64 static void sigtrap ( int ); 65 static void done ( int , int ); 66 static void cool_heels ( void ); 67 static void addenv (char ***envp, char * , char * ); 68 static void trap_fault_signals ( void ); 69 static void ignore_fault_signals ( void ); 70 static void child_mallocfail ( void ); 71 static void Fork2 ( void ); 72 73 static int Fork1 ( EXEC * ); 74 75 static void 76 relock(void) 77 { 78 struct flock l; 79 80 l.l_type = F_WRLCK; 81 l.l_whence = 1; 82 l.l_start = 0; 83 l.l_len = 0; 84 (void)Fcntl (lock_fd, F_SETLK, &l); 85 return; 86 } 87 88 static char *_exec_name(int type) 89 { 90 static char *_names[] = { 91 "", "EX_INTERF", "EX_SLOWF", "EX_ALERT", "EX_FALERT", "EX_PALERT", 92 "EX_NOTIFY", "EX_FAULT_MESSAGE", "EX_FORM_MESSAGE", NULL }; 93 94 if ((type < 0) || (type > EX_FORM_MESSAGE)) 95 return ("BAD_EXEC_TYPE"); 96 else 97 return (_names[type]); 98 } 99 100 /* 101 * This function replaces characters in a string that might be used 102 * to exploit a security hole. Replace command seperators (`, &, ;, |, ^), 103 * output redirection (>, |), variable expansion ($), and character 104 * escape (\). 105 * 106 * Bugid 4141687 107 * Add ( ) < * ? [ 108 * Bugid 4139071 109 * Remove \ 110 */ 111 void clean_string(char *ptr) 112 { 113 char *cp; 114 wchar_t wc; 115 size_t len; 116 117 for (cp = ptr; *cp != NULL; ) { 118 if ((len = mbtowc(&wc, cp, MB_CUR_MAX)) == -1) { 119 cp++; 120 continue; 121 } 122 123 if (len == 1 && 124 ((wc == L'`') || (wc == L'&') || (wc == L';') || 125 (wc == L'|') || (wc == L'>') || (wc == L'^') || 126 (wc == L'$') || (wc == L'(') || (wc == L')') || 127 (wc == L'<') || (wc == L'*') || (wc == L'?') || 128 (wc == L'['))) 129 *cp = '_'; 130 cp += len; 131 } 132 } 133 134 enum trust {TRUSTED, UNTRUSTED}; 135 136 static char *arg_string(enum trust type, char *fmt, ...) __PRINTFLIKE(2); 137 138 /* PRINTFLIKE2 */ 139 static char * 140 arg_string(enum trust type, char *fmt, ...) 141 { 142 char buf[BUFSIZ]; 143 va_list args; 144 145 va_start(args, fmt); 146 (void) vsnprintf(buf, sizeof(buf), fmt, args); 147 va_end(args); 148 149 /* 150 * If the string contains data from an untrusted origin (user supplied), 151 * clean it up in case one of our progeny is a shell script and isn't 152 * careful about checking its input. 153 */ 154 if (type == UNTRUSTED) 155 clean_string(buf); 156 157 return (strdup(buf)); 158 } 159 160 /* stolen from libc/gen/port/gen/execvp.c */ 161 static const char * 162 execat(const char *s1, const char *s2, char *si) 163 { 164 char *s; 165 int cnt = PATH_MAX + 1; /* number of characters in s2 */ 166 167 s = si; 168 while (*s1 && *s1 != ':') { 169 if (cnt > 0) { 170 *s++ = *s1++; 171 cnt--; 172 } else 173 s1++; 174 } 175 if (si != s && cnt > 0) { 176 *s++ = '/'; 177 cnt--; 178 } 179 while (*s2 && cnt > 0) { 180 *s++ = *s2++; 181 cnt--; 182 } 183 *s = '\0'; 184 return (*s1 ? ++s1: 0); 185 } 186 187 /* 188 * Similiar to execvp(), execpt you can supply an environment and we always 189 * use /bin/sh for shell scripts. The PATH searched is the PATH in the 190 * current environment, not the environment in the argument list. 191 * This was pretty much stolen from libc/gen/port/execvp.c 192 */ 193 static int 194 execvpe(char *name, char *const argv[], char *const envp[]) 195 { 196 char *path; 197 char fname[PATH_MAX+2]; 198 char *newargs[256]; 199 int i; 200 const char *cp; 201 unsigned etxtbsy = 1; 202 int eacces = 0; 203 204 if (*name == '\0') { 205 errno = ENOENT; 206 return (-1); 207 } 208 209 if ((path = getenv("PATH")) == NULL) 210 path = "/usr/bin:/bin"; 211 212 cp = strchr(name, '/')? (const char *)"": path; 213 214 do { 215 cp = execat(cp, name, fname); 216 retry: 217 /* 218 * 4025035 and 4038378 219 * if a filename begins with a "-" prepend "./" so that 220 * the shell can't interpret it as an option 221 */ 222 if (*fname == '-') { 223 size_t size = strlen(fname) + 1; 224 if ((size + 2) > sizeof (fname)) { 225 errno = E2BIG; 226 return (-1); 227 } 228 (void) memmove(fname + 2, fname, size); 229 fname[0] = '.'; 230 fname[1] = '/'; 231 } 232 (void) execve(fname, argv, envp); 233 switch (errno) { 234 case ENOEXEC: 235 newargs[0] = "sh"; 236 newargs[1] = fname; 237 for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) { 238 if (i >= 254) { 239 errno = E2BIG; 240 return (-1); 241 } 242 } 243 (void) execve("/bin/sh", newargs, envp); 244 return (-1); 245 case ETXTBSY: 246 if (++etxtbsy > 5) 247 return (-1); 248 (void) sleep(etxtbsy); 249 goto retry; 250 case EACCES: 251 ++eacces; 252 break; 253 case ENOMEM: 254 case E2BIG: 255 case EFAULT: 256 return (-1); 257 } 258 } while (cp); 259 if (eacces) 260 errno = EACCES; 261 return (-1); 262 } 263 264 static char time_buf[50]; 265 266 /** 267 ** exec() - FORK AND EXEC CHILD PROCESS 268 **/ 269 270 /*VARARGS1*/ 271 int 272 exec(int type, ...) 273 { 274 va_list args; 275 276 int i; 277 int procuid; 278 int procgid; 279 int ret; 280 int fr_flg; 281 282 char *cp; 283 char *infile; 284 char *outfile; 285 char *errfile; 286 char *sep; 287 288 char **listp; 289 char **file_list; 290 char *printerName; 291 char *printerNameToShow; 292 static char nameBuf[100]; 293 char *clean_title; 294 295 PSTATUS *printer; 296 297 RSTATUS *request; 298 299 FSTATUS *form; 300 301 EXEC *ep; 302 303 PWSTATUS *pwheel; 304 time_t now; 305 struct passwd *pwp; 306 #ifdef LP_USE_PAPI_ATTR 307 struct stat tmpBuf; 308 char tmpName[BUFSIZ]; 309 char *path = NULL; 310 #endif 311 char *av[ARG_MAX]; 312 char **envp = NULL; 313 int ac = 0; 314 char *mail_zonename = NULL; 315 char *slabel = NULL; 316 int setid = 1; 317 char *ridno = NULL, *tmprid = NULL; 318 319 syslog(LOG_DEBUG, "exec(%s)", _exec_name(type)); 320 321 memset(av, 0, sizeof (*av)); 322 323 va_start (args, type); 324 325 switch (type) { 326 327 case EX_INTERF: 328 printer = va_arg(args, PSTATUS *); 329 request = printer->request; 330 ep = printer->exec; 331 break; 332 333 case EX_FAULT_MESSAGE: 334 printer = va_arg(args, PSTATUS *); 335 request = va_arg(args, RSTATUS *); 336 if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) { 337 return(0); 338 } 339 ep = printer->fault_exec; 340 printerName = (printer->printer && printer->printer->name 341 ? printer->printer->name : "??"); 342 snprintf(nameBuf, sizeof (nameBuf), 343 "%s (on %s)\n", printerName, Local_System); 344 345 printerNameToShow = nameBuf; 346 347 (void) time(&now); 348 (void) strftime(time_buf, sizeof (time_buf), 349 NULL, localtime(&now)); 350 break; 351 352 case EX_SLOWF: 353 request = va_arg(args, RSTATUS *); 354 ep = request->exec; 355 break; 356 357 case EX_NOTIFY: 358 request = va_arg(args, RSTATUS *); 359 if (request->request->actions & ACT_NOTIFY) { 360 errno = EINVAL; 361 return (-1); 362 } 363 ep = request->exec; 364 break; 365 366 case EX_ALERT: 367 printer = va_arg(args, PSTATUS *); 368 if (!(printer->printer->fault_alert.shcmd)) { 369 errno = EINVAL; 370 return(-1); 371 } 372 ep = printer->alert->exec; 373 break; 374 375 case EX_PALERT: 376 pwheel = va_arg(args, PWSTATUS *); 377 ep = pwheel->alert->exec; 378 break; 379 380 case EX_FORM_MESSAGE: 381 (void) time(&now); 382 (void) strftime(time_buf, sizeof (time_buf), 383 NULL, localtime(&now)); 384 385 /*FALLTHRU*/ 386 case EX_FALERT: 387 form = va_arg(args, FSTATUS *); 388 ep = form->alert->exec; 389 break; 390 391 default: 392 errno = EINVAL; 393 return(-1); 394 395 } 396 va_end (args); 397 398 if (!ep || (ep->pid > 0)) { 399 errno = EBUSY; 400 return(-1); 401 } 402 403 ep->flags = 0; 404 405 key = ep->key = getkey(); 406 407 switch ((ep->pid = Fork1(ep))) { 408 409 case -1: 410 relock (); 411 return(-1); 412 413 case 0: 414 /* 415 * We want to be able to tell our parent how we died. 416 */ 417 lp_alloc_fail_handler = child_mallocfail; 418 break; 419 420 default: 421 switch(type) { 422 423 case EX_INTERF: 424 request->request->outcome |= RS_PRINTING; 425 break; 426 427 case EX_NOTIFY: 428 request->request->outcome |= RS_NOTIFYING; 429 break; 430 431 case EX_SLOWF: 432 request->request->outcome |= RS_FILTERING; 433 request->request->outcome &= ~RS_REFILTER; 434 break; 435 436 } 437 return(0); 438 439 } 440 441 for (i = 0; i < NSIG; i++) 442 (void)signal (i, SIG_DFL); 443 (void)signal (SIGALRM, SIG_IGN); 444 (void)signal (SIGTERM, sigtrap); 445 446 closelog(); 447 for (i = 0; i < OpenMax; i++) 448 if (i != ChildMd->writefd) 449 Close (i); 450 openlog("lpsched", LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR); 451 452 setpgrp(); 453 454 /* Set a default path */ 455 addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin"); 456 /* copy locale related variables */ 457 addenv (&envp, "TZ", getenv("TZ")); 458 addenv (&envp, "LANG", getenv("LANG")); 459 addenv (&envp, "LC_ALL", getenv("LC_ALL")); 460 addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE")); 461 addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE")); 462 addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES")); 463 addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY")); 464 addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC")); 465 addenv (&envp, "LC_TIME", getenv("LC_TIME")); 466 467 sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key); 468 addenv (&envp, "SPOOLER_KEY", cp); 469 470 #if defined(DEBUG) 471 addenv (&envp, "LPDEBUG", (debug? "1" : "0")); 472 #endif 473 474 /* 475 * Open the standard input, standard output, and standard error. 476 */ 477 switch (type) { 478 479 case EX_SLOWF: 480 case EX_INTERF: 481 /* 482 * stdin: /dev/null 483 * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF) 484 * stderr: req# 485 */ 486 infile = 0; 487 outfile = 0; 488 errfile = makereqerr(request); 489 break; 490 491 case EX_NOTIFY: 492 /* 493 * stdin: req# 494 * stdout: /dev/null 495 * stderr: /dev/null 496 */ 497 infile = makereqerr(request); 498 outfile = 0; 499 errfile = 0; 500 501 break; 502 503 case EX_ALERT: 504 case EX_FALERT: 505 case EX_PALERT: 506 case EX_FAULT_MESSAGE: 507 case EX_FORM_MESSAGE: 508 /* 509 * stdin: /dev/null 510 * stdout: /dev/null 511 * stderr: /dev/null 512 */ 513 infile = 0; 514 outfile = 0; 515 errfile = 0; 516 break; 517 518 } 519 520 if (infile) { 521 if (Open(infile, O_RDONLY) == -1) 522 Done (EXEC_EXIT_NOPEN, errno); 523 } else { 524 if (Open("/dev/null", O_RDONLY) == -1) 525 Done (EXEC_EXIT_NOPEN, errno); 526 } 527 528 if (outfile) { 529 if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) 530 Done (EXEC_EXIT_NOPEN, errno); 531 } else { 532 /* 533 * If EX_INTERF, this is still needed to cause the 534 * standard error channel to be #2. 535 */ 536 if (Open("/dev/null", O_WRONLY) == -1) 537 Done (EXEC_EXIT_NOPEN, errno); 538 } 539 540 if (errfile) { 541 if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) 542 Done (EXEC_EXIT_NOPEN, errno); 543 } else { 544 if (Open("/dev/null", O_WRONLY) == -1) 545 Done (EXEC_EXIT_NOPEN, errno); 546 } 547 548 switch (type) { 549 550 case EX_INTERF: 551 /* 552 * Opening a ``port'' can be dangerous to our health: 553 * 554 * - Hangups can occur if the line is dropped. 555 * - The printer may send an interrupt. 556 * - A FIFO may be closed, generating SIGPIPE. 557 * 558 * We catch these so we can complain nicely. 559 */ 560 trap_fault_signals (); 561 562 (void)Close (1); 563 564 procuid = request->secure->uid; 565 procgid = request->secure->gid; 566 567 if (printer->printer->dial_info) 568 { 569 ret = open_dialup(request->printer_type, 570 printer->printer); 571 if (ret == 0) 572 do_undial = 1; 573 } 574 else 575 { 576 ret = open_direct(request->printer_type, 577 printer->printer); 578 do_undial = 0; 579 /* this is a URI */ 580 if (is_printer_uri(printer->printer->device) == 0) 581 addenv(&envp, "DEVICE_URI", 582 printer->printer->device); 583 } 584 addenv(&envp, "DEVICE_URI", 585 printer->printer->device); 586 if (ret != 0) 587 Done (ret, errno); 588 589 if (!(request->request->outcome & RS_FILTERED)) 590 file_list = request->request->file_list; 591 592 else { 593 register int count = 0; 594 register char * num = BIGGEST_REQID_S; 595 register char * prefix; 596 597 prefix = makestr( 598 Lp_Temp, 599 "/F", 600 getreqno(request->secure->req_id), 601 "-", 602 (char *)0 603 ); 604 605 file_list = (char **)Malloc( 606 (lenlist(request->request->file_list) + 1) 607 * sizeof(char *) 608 ); 609 610 for ( 611 listp = request->request->file_list; 612 *listp; 613 listp++ 614 ) { 615 sprintf (num, "%d", count + 1); 616 file_list[count] = makestr( 617 prefix, 618 num, 619 (char *)0 620 ); 621 count++; 622 } 623 file_list[count] = 0; 624 } 625 626 #ifdef LP_USE_PAPI_ATTR 627 /* 628 * Check if the PAPI job attribute file exists, if it does 629 * pass the file's pathname to the printer interface script 630 * in an environment variable. This file is created when 631 * print jobs are submitted via the PAPI interface. 632 */ 633 snprintf(tmpName, sizeof (tmpName), "%s-%s", 634 getreqno(request->secure->req_id), LP_PAPIATTRNAME); 635 path = makepath(Lp_Temp, tmpName, (char *)0); 636 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 637 { 638 /* 639 * IPP job attribute file exists for this job so 640 * set the environment variable 641 */ 642 addenv(&envp, "ATTRPATH", path); 643 } 644 Free(path); 645 646 /* 647 * now set environment variable for the printer's PostScript 648 * Printer Description (PPD) file, this is used by the filter 649 * when forming the print data for this printer. 650 */ 651 if ((request->printer != NULL) && 652 (request->printer->printer != NULL) && 653 (request->printer->printer->name != NULL)) 654 { 655 snprintf(tmpName, sizeof (tmpName), "%s.ppd", 656 request->printer->printer->name); 657 path = makepath(ETCDIR, "ppd", tmpName, (char *)0); 658 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 659 { 660 addenv(&envp, "PPD", path); 661 } 662 Free(path); 663 } 664 #endif 665 666 if (request->printer_type) 667 addenv(&envp, "TERM", request->printer_type); 668 669 if (!(printer->printer->daisy)) { 670 register char * chset = 0; 671 register char * csp; 672 673 if ( 674 request->form 675 && request->form->form->chset 676 && request->form->form->mandatory 677 && !STREQU(NAME_ANY, request->form->form->chset) 678 ) 679 chset = request->form->form->chset; 680 681 else if ( 682 request->request->charset 683 && !STREQU(NAME_ANY, request->request->charset) 684 ) 685 chset = request->request->charset; 686 687 if (chset) { 688 csp = search_cslist( 689 chset, 690 printer->printer->char_sets 691 ); 692 693 /* 694 * The "strtok()" below wrecks the string 695 * for future use, but this is a child 696 * process where it won't be needed again. 697 */ 698 addenv (&envp, "CHARSET", 699 (csp? strtok(csp, "=") : chset) 700 ); 701 } 702 } 703 704 if (request->fast) 705 addenv(&envp, "FILTER", request->fast); 706 707 /* 708 * Add the sensitivity label to the environment for 709 * banner page and header/footer processing 710 */ 711 712 if (is_system_labeled() && request->secure->slabel != NULL) 713 addenv(&envp, "SLABEL", request->secure->slabel); 714 715 /* 716 * Add the system name to the user name (ala system!user) 717 * unless it is already there. RFS users may have trouble 718 * here, sorry! 719 */ 720 cp = strchr(request->secure->user, '@'); 721 722 allTraysWithForm(printer, request->form); 723 724 /* 725 * Fix for 4137389 726 * Remove double quotes from title string. 727 */ 728 fr_flg = 1; 729 clean_title = strdup(NB(request->request->title)); 730 if (clean_title == NULL) { 731 /* 732 * strdup failed. We're probably hosed 733 * but try setting clean_title 734 * to original title and continuing. 735 */ 736 clean_title = NB(request->request->title); 737 fr_flg = 0; 738 } else if (strcmp(clean_title, "") != 0) { 739 char *ct_p; 740 741 for (ct_p = clean_title; *ct_p != NULL; ct_p++) { 742 if (*ct_p == '"') 743 *ct_p = ' '; 744 } 745 } 746 747 av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces, 748 printer->printer->name); 749 /* 750 * Read the options field of the request 751 * In case of remote lpd request 752 * the options field will have 753 * job-id-requested. This is the 754 * id sent by the client 755 */ 756 if (request->request->options != NULL) { 757 char *options = NULL, *temp = NULL; 758 options = temp = strdup(request->request->options); 759 760 /* 761 * Search for job-id-requested in 762 * options string 763 */ 764 options = strstr(options, "job-id-requested"); 765 if (options != NULL) { 766 /* 767 * Extract the ridno from the string 768 * job-id-requested=xxx 769 * In this case ridno = xxx 770 */ 771 if (STRNEQU(options, "job-id-requested=", 17)) { 772 ridno = strdup(options + 17); 773 tmprid = strstr(ridno, " "); 774 if (ridno != NULL) { 775 /* 776 * Read job-id-requested 777 * successfully 778 */ 779 tmprid = strstr(ridno, " "); 780 if (tmprid != NULL) 781 *tmprid = '\0'; 782 783 setid = 0; 784 } else 785 /* 786 * could not read 787 * ridno from the string 788 * job-id-requested=xxx 789 */ 790 setid = 1; 791 } else 792 /* 793 * could not read 794 * ridno from the string 795 * job-id-requested=xxx 796 */ 797 setid = 1; 798 } else 799 /* 800 * No job-id-requested in 801 * request options 802 */ 803 setid = 1; 804 805 if (temp != NULL) 806 free(temp); 807 808 } else 809 /* 810 * options field in request structure 811 * not set 812 */ 813 setid = 1; 814 815 816 /* 817 * setid = 1 means the job-id-requested attribute 818 * is not set so read the request->secure->req_id 819 */ 820 if (setid) 821 av[ac++] = arg_string(TRUSTED, "%s", 822 request->secure->req_id); 823 else { 824 /* 825 * From request->secure->req_id extract the 826 * printer-name. 827 * request->secure->req_id = <printer-name>-<req_id> 828 * The final req-id will be 829 * <printer-name>-<ridno> 830 */ 831 char *r1 = NULL, *r2 = NULL, *tmp = NULL; 832 r1 = r2 = tmp = strdup(request->secure->req_id); 833 r2 = strrchr(r1, '-'); 834 if (r2 != NULL) { 835 char *r3 = NULL; 836 int lr1 = strlen(r1); 837 int lr2 = strlen(r2); 838 r1[lr1 - lr2 + 1] = '\0'; 839 840 /* 841 * Now r1 = <printer-name>- 842 */ 843 lr1 = strlen(r1); 844 lr2 = strlen(ridno); 845 846 r3 = (char *)malloc(lr1+lr2+1); 847 if (r3 != NULL) { 848 strcpy(r3, r1); 849 strcat(r3, ridno); 850 /* 851 * Here r3 = <printer-name>-<ridno> 852 */ 853 av[ac++] = arg_string(TRUSTED, 854 "%s", r3); 855 free(r3); 856 } else 857 av[ac++] = arg_string(TRUSTED, "%s", 858 request->secure->req_id); 859 860 } else 861 av[ac++] = arg_string(TRUSTED, "%s", 862 request->secure->req_id); 863 864 if (tmp != NULL) 865 free(tmp); 866 867 if (ridno != NULL) 868 free(ridno); 869 } 870 871 av[ac++] = arg_string(UNTRUSTED, "%s", request->request->user); 872 av[ac++] = arg_string(TRUSTED, "%s", clean_title); 873 av[ac++] = arg_string(TRUSTED, "%d", request->copies); 874 875 if (fr_flg) 876 free (clean_title); 877 878 sep = ""; 879 880 /* 881 * Do the administrator defined key=value pair options 882 */ 883 884 argbuf[0] = '\0'; 885 886 if (printer->printer->options) { 887 char **tmp = printer->printer->options; 888 while(*tmp != NULL) { 889 STRLCAT(argbuf, sep, sizeof (argbuf)); 890 sep = " "; 891 STRLCAT(argbuf, *tmp++, sizeof (argbuf)); 892 } 893 } 894 895 /* 896 * Do the administrator defined ``stty'' stuff before 897 * the user's -o options, to allow the user to override. 898 */ 899 if (printer->printer->stty) { 900 STRLCAT (argbuf, sep, sizeof (argbuf)); 901 sep = " "; 902 STRLCAT (argbuf, "stty='", sizeof (argbuf)); 903 STRLCAT (argbuf, printer->printer->stty, 904 sizeof (argbuf)); 905 STRLCAT (argbuf, "'", sizeof (argbuf)); 906 } 907 908 /* 909 * Do all of the user's options except the cpi/lpi/etc. 910 * stuff, which is done separately. 911 */ 912 if (request->request->options) { 913 listp = dashos(request->request->options); 914 while (*listp) { 915 if ( 916 !STRNEQU(*listp, "cpi=", 4) 917 && !STRNEQU(*listp, "lpi=", 4) 918 && !STRNEQU(*listp, "width=", 6) 919 && !STRNEQU(*listp, "length=", 7) 920 ) { 921 STRLCAT (argbuf, sep, sizeof (argbuf)); 922 sep = " "; 923 STRLCAT (argbuf, *listp, 924 sizeof (argbuf)); 925 } 926 listp++; 927 } 928 } 929 930 /* 931 * The "pickfilter()" routine (from "validate()") 932 * stored the cpi/lpi/etc. stuff that should be 933 * used for this request. It chose form over user, 934 * and user over printer. 935 */ 936 if (request->cpi) { 937 STRLCAT (argbuf, sep, sizeof (argbuf)); 938 sep = " "; 939 STRLCAT (argbuf, "cpi=", sizeof (argbuf)); 940 STRLCAT (argbuf, request->cpi, sizeof (argbuf)); 941 } 942 if (request->lpi) { 943 STRLCAT (argbuf, sep, sizeof (argbuf)); 944 sep = " "; 945 STRLCAT (argbuf, "lpi=", sizeof (argbuf)); 946 STRLCAT (argbuf, request->lpi, sizeof (argbuf)); 947 } 948 if (request->pwid) { 949 STRLCAT (argbuf, sep, sizeof (argbuf)); 950 sep = " "; 951 STRLCAT (argbuf, "width=", sizeof (argbuf)); 952 STRLCAT (argbuf, request->pwid, sizeof (argbuf)); 953 } 954 if (request->plen) { 955 STRLCAT (argbuf, sep, sizeof (argbuf)); 956 sep = " "; 957 STRLCAT (argbuf, "length=", sizeof (argbuf)); 958 STRLCAT (argbuf, request->plen, sizeof (argbuf)); 959 } 960 961 /* 962 * Do the ``raw'' bit last, to ensure it gets 963 * done. If the user doesn't want this, then they 964 * can do the correct thing using -o stty= 965 * and leaving out the -r option. 966 */ 967 if (request->request->actions & ACT_RAW) { 968 STRLCAT (argbuf, sep, sizeof (argbuf)); 969 sep = " "; 970 STRLCAT (argbuf, "stty=-opost", sizeof (argbuf)); 971 } 972 973 974 /* the "options" */ 975 av[ac++] = arg_string(UNTRUSTED, "%s", argbuf); 976 977 for (listp = file_list; *listp; listp++) 978 av[ac++] = arg_string(TRUSTED, "%s", *listp); 979 980 (void)chfiles (file_list, procuid, procgid); 981 982 break; 983 984 985 case EX_SLOWF: 986 if (request->slow) 987 addenv(&envp, "FILTER", request->slow); 988 989 procuid = request->secure->uid; 990 procgid = request->secure->gid; 991 992 cp = _alloc_files( 993 lenlist(request->request->file_list), 994 getreqno(request->secure->req_id), 995 procuid, procgid); 996 997 av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter); 998 av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_Temp, cp); 999 for (listp = request->request->file_list; *listp; listp++) 1000 av[ac++] = arg_string(TRUSTED, "%s", *listp); 1001 1002 (void)chfiles (request->request->file_list, procuid, procgid); 1003 1004 #ifdef LP_USE_PAPI_ATTR 1005 /* 1006 * Check if the PAPI job attribute file exists, if it does 1007 * pass the file's pathname to the slow-filters in an 1008 * environment variable. Note: this file is created when 1009 * print jobs are submitted via the PAPI interface. 1010 */ 1011 snprintf(tmpName, sizeof (tmpName), "%s-%s", 1012 getreqno(request->secure->req_id), LP_PAPIATTRNAME); 1013 path = makepath(Lp_Temp, tmpName, (char *)0); 1014 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 1015 { 1016 /* 1017 * IPP job attribute file exists for this job so 1018 * set the environment variable 1019 */ 1020 addenv(&envp, "ATTRPATH", path); 1021 } 1022 Free(path); 1023 1024 1025 /* 1026 * now set environment variable for the printer's PostScript 1027 * Printer Description (PPD) file, this is used by the filter 1028 * when forming the print data for this printer. 1029 */ 1030 if ((request->printer != NULL) && 1031 (request->printer->printer != NULL) && 1032 (request->printer->printer->name != NULL)) 1033 { 1034 snprintf(tmpName, sizeof (tmpName), "%s.ppd", 1035 request->printer->printer->name); 1036 path = makepath(ETCDIR, "ppd", tmpName, (char *)0); 1037 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 1038 { 1039 addenv(&envp, "PPD", path); 1040 } 1041 Free(path); 1042 } 1043 #endif 1044 break; 1045 1046 case EX_ALERT: 1047 procuid = Lp_Uid; 1048 procgid = Lp_Gid; 1049 (void)Chown (printer->alert->msgfile, procuid, procgid); 1050 1051 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, 1052 printer->printer->name, ALERTSHFILE); 1053 av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); 1054 1055 break; 1056 1057 case EX_PALERT: 1058 procuid = Lp_Uid; 1059 procgid = Lp_Gid; 1060 (void)Chown (pwheel->alert->msgfile, procuid, procgid); 1061 1062 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels, 1063 pwheel->pwheel->name, ALERTSHFILE); 1064 av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); 1065 1066 break; 1067 1068 case EX_FALERT: 1069 procuid = Lp_Uid; 1070 procgid = Lp_Gid; 1071 (void)Chown (form->alert->msgfile, procuid, procgid); 1072 1073 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, 1074 form->form->name, ALERTSHFILE); 1075 av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); 1076 1077 break; 1078 1079 case EX_FORM_MESSAGE: 1080 procuid = Lp_Uid; 1081 procgid = Lp_Gid; 1082 1083 av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults); 1084 av[ac++] = arg_string(TRUSTED, "%s", form->form->name); 1085 av[ac++] = arg_string(TRUSTED, "%s", time_buf); 1086 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, 1087 form->form->name, FORMMESSAGEFILE); 1088 1089 break; 1090 1091 case EX_FAULT_MESSAGE: 1092 procuid = Lp_Uid; 1093 procgid = Lp_Gid; 1094 1095 av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults); 1096 av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow); 1097 av[ac++] = arg_string(TRUSTED, "%s", time_buf); 1098 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, 1099 printerName, FAULTMESSAGEFILE); 1100 1101 break; 1102 1103 case EX_NOTIFY: 1104 if (request->request->alert) { 1105 procuid = request->secure->uid; 1106 procgid = request->secure->gid; 1107 1108 av[ac++] = arg_string(TRUSTED, "%s", 1109 request->request->alert); 1110 } else { 1111 char *user = strdup(request->request->user); 1112 clean_string(user); 1113 slabel = request->secure->slabel; 1114 1115 if (request->request->actions & ACT_WRITE) { 1116 av[ac++] = arg_string(TRUSTED, "%s", BINWRITE); 1117 snprintf(argbuf, sizeof (argbuf), 1118 "%s %s || %s %s", 1119 BINWRITE, user, 1120 BINMAIL, user 1121 ); 1122 av[ac++] = arg_string(TRUSTED, "/bin/sh"); 1123 av[ac++] = arg_string(TRUSTED, "-c"); 1124 av[ac++] = arg_string(TRUSTED, "%s", argbuf); 1125 } else if ((getzoneid() == GLOBAL_ZONEID) && 1126 is_system_labeled() && (slabel != NULL)) { 1127 /* 1128 * If in the global zone and the system is 1129 * labeled, mail is handled via a local 1130 * labeled zone that is the same label as 1131 * the request. 1132 */ 1133 if ((mail_zonename = 1134 get_labeled_zonename(slabel)) == 1135 (char *)-1) { 1136 /* 1137 * Cannot find labeled zone, just 1138 * return 0. 1139 */ 1140 return(0); 1141 } 1142 } 1143 if (mail_zonename == NULL) { 1144 procuid = Lp_Uid; 1145 procgid = Lp_Gid; 1146 av[ac++] = arg_string(TRUSTED, "%s", BINMAIL); 1147 av[ac++] = arg_string(UNTRUSTED, "%s", user); 1148 } else { 1149 procuid = getuid(); 1150 procgid = getgid(); 1151 av[ac++] = arg_string(TRUSTED, "%s", 1152 "/usr/sbin/zlogin"); 1153 av[ac++] = arg_string(TRUSTED, "%s", 1154 mail_zonename); 1155 av[ac++] = arg_string(TRUSTED, "%s", 1156 BINMAIL); 1157 av[ac++] = arg_string(UNTRUSTED, "%s", 1158 user); 1159 Free(mail_zonename); 1160 } 1161 1162 free(user); 1163 } 1164 break; 1165 } 1166 1167 av[ac++] = NULL; 1168 1169 Fork2 (); 1170 /* only the child returns */ 1171 1172 /* 1173 * Correctly set up the supplemental group list 1174 * for proper file access (before execl the interface program) 1175 */ 1176 1177 pwp = getpwuid(procuid); 1178 if (pwp == NULL) { 1179 note("getpwuid(%d) call failed\n", procuid); 1180 } else if (initgroups(pwp->pw_name, procgid) < 0) { 1181 note("initgroups() call failed %d\n", errno); 1182 } 1183 1184 setgid (procgid); 1185 setuid (procuid); 1186 1187 /* 1188 * The shell doesn't allow the "trap" builtin to set a trap 1189 * for a signal ignored when the shell is started. Thus, don't 1190 * turn off signals in the last child! 1191 */ 1192 1193 #ifdef DEBUG 1194 for (i = 0; av[i] != NULL; i++) 1195 note("exec(%s): av[%d] = %s", _exec_name(type), i, av[i]); 1196 for (i = 0; envp[i] != NULL; i++) 1197 note("exec(%s): envp[%d] = %s", _exec_name(type), i, envp[i]); 1198 #endif 1199 1200 execvpe(av[0], av, envp); 1201 Done (EXEC_EXIT_NEXEC, errno); 1202 /*NOTREACHED*/ 1203 return (0); 1204 } 1205 1206 /** 1207 ** addenv() - ADD A VARIABLE TO THE ENVIRONMENT 1208 **/ 1209 1210 static void 1211 addenv(char ***envp, char *name, char *value) 1212 { 1213 register char * cp; 1214 1215 if ((name == NULL) || (value == NULL)) 1216 return; 1217 1218 if ((cp = makestr(name, "=", value, (char *)0))) 1219 addlist(envp, cp); 1220 return; 1221 } 1222 1223 /** 1224 ** Fork1() - FORK FIRST CHILD, SET UP CONNECTION TO IT 1225 **/ 1226 1227 static int 1228 Fork1(EXEC *ep) 1229 { 1230 int pid; 1231 int fds[2]; 1232 1233 if (pipe(fds) == -1) { 1234 note("Failed to create pipe for child process (%s).\n", PERROR); 1235 errno = EAGAIN ; 1236 return(-1); 1237 } 1238 1239 ep->md = mconnect((char *)0, fds[0], fds[1]); 1240 1241 switch (pid = fork()) { 1242 1243 case -1: 1244 mdisconnect(ep->md); 1245 close(fds[0]); 1246 close(fds[1]); 1247 ep->md = 0; 1248 return (-1); 1249 1250 case 0: 1251 ChildMd = mconnect(NULL, fds[1], fds[1]); 1252 return (0); 1253 1254 default: 1255 mlistenadd(ep->md, POLLIN); 1256 return (pid); 1257 } 1258 } 1259 1260 /** 1261 ** Fork2() - FORK SECOND CHILD AND WAIT FOR IT 1262 **/ 1263 1264 static void 1265 Fork2(void) 1266 { 1267 switch ((ChildPid = fork())) { 1268 1269 case -1: 1270 Done (EXEC_EXIT_NFORK, errno); 1271 /*NOTREACHED*/ 1272 1273 case 0: 1274 return; 1275 1276 default: 1277 /* 1278 * Delay calling "ignore_fault_signals()" as long 1279 * as possible, to give the child a chance to exec 1280 * the interface program and turn on traps. 1281 */ 1282 1283 cool_heels (); 1284 /*NOTREACHED*/ 1285 1286 } 1287 } 1288 1289 1290 /** 1291 ** cool_heels() - WAIT FOR CHILD TO "DIE" 1292 **/ 1293 1294 static void 1295 cool_heels(void) 1296 { 1297 int status; 1298 1299 /* 1300 * At this point our only job is to wait for the child process. 1301 * If we hang out for a bit longer, that's okay. 1302 * By delaying before turning off the fault signals, 1303 * we increase the chance that the child process has completed 1304 * its exec and has turned on the fault traps. Nonetheless, 1305 * we can't guarantee a zero chance of missing a fault. 1306 * (We don't want to keep trapping the signals because the 1307 * interface program is likely to have a better way to handle 1308 * them; this process provides only rudimentary handling.) 1309 * 1310 * Note that on a very busy system, or with a very fast interface 1311 * program, the tables could be turned: Our sleep below (coupled 1312 * with a delay in the kernel scheduling us) may cause us to 1313 * detect the fault instead of the interface program. 1314 * 1315 * What we need is a way to synchronize with the child process. 1316 */ 1317 sleep (1); 1318 ignore_fault_signals (); 1319 1320 WaitedChildPid = 0; 1321 while ((WaitedChildPid = wait(&status)) != ChildPid) 1322 ; 1323 1324 if ( 1325 EXITED(status) > EXEC_EXIT_USER 1326 && EXITED(status) != EXEC_EXIT_FAULT 1327 ) 1328 Done (EXEC_EXIT_EXIT, EXITED(status)); 1329 1330 done (status, 0); /* Don't use Done() */ 1331 /*NOTREACHED*/ 1332 } 1333 1334 1335 /** 1336 ** trap_fault_signals() - TRAP SIGNALS THAT CAN OCCUR ON PRINTER FAULT 1337 ** ignore_fault_signals() - IGNORE SAME 1338 **/ 1339 1340 static void 1341 trap_fault_signals(void) 1342 { 1343 signal (SIGHUP, sigtrap); 1344 signal (SIGINT, sigtrap); 1345 signal (SIGQUIT, sigtrap); 1346 signal (SIGPIPE, sigtrap); 1347 return; 1348 } 1349 1350 static void 1351 ignore_fault_signals(void) 1352 { 1353 signal (SIGHUP, SIG_IGN); 1354 signal (SIGINT, SIG_IGN); 1355 signal (SIGQUIT, SIG_IGN); 1356 signal (SIGPIPE, SIG_IGN); 1357 return; 1358 } 1359 1360 /** 1361 ** sigtrap() - TRAP VARIOUS SIGNALS 1362 **/ 1363 1364 static void 1365 sigtrap(int sig) 1366 { 1367 signal (sig, SIG_IGN); 1368 switch (sig) { 1369 1370 case SIGHUP: 1371 Done (EXEC_EXIT_HUP, 0); 1372 /*NOTREACHED*/ 1373 1374 case SIGQUIT: 1375 case SIGINT: 1376 Done (EXEC_EXIT_INTR, 0); 1377 /*NOTREACHED*/ 1378 1379 case SIGPIPE: 1380 Done (EXEC_EXIT_PIPE, 0); 1381 /*NOTREACHED*/ 1382 1383 case SIGTERM: 1384 /* 1385 * If we were killed with SIGTERM, it should have been 1386 * via the Spooler who should have killed the entire 1387 * process group. We have to wait for the children, 1388 * since we're their parent, but WE MAY HAVE WAITED 1389 * FOR THEM ALREADY (in cool_heels()). 1390 */ 1391 if (ChildPid != WaitedChildPid) { 1392 register int cpid; 1393 1394 while ( 1395 (cpid = wait((int *)0)) != ChildPid 1396 && (cpid != -1 || errno != ECHILD) 1397 ) 1398 ; 1399 } 1400 1401 /* 1402 * We can't rely on getting SIGTERM back in the wait() 1403 * above, because, for instance, some shells trap SIGTERM 1404 * and exit instead. Thus we force it. 1405 */ 1406 done (SIGTERM, 0); /* Don't use Done() */ 1407 /*NOTREACHED*/ 1408 } 1409 } 1410 1411 /** 1412 ** done() - TELL SPOOLER THIS CHILD IS DONE 1413 **/ 1414 1415 static void 1416 done(int status, int err) 1417 { 1418 if (do_undial) 1419 undial (1); 1420 1421 mputm (ChildMd, S_CHILD_DONE, key, status, err); 1422 mdisconnect (ChildMd); 1423 1424 exit (0); 1425 /*NOTREACHED*/ 1426 } 1427 1428 /** 1429 ** child_mallocfail() 1430 **/ 1431 1432 static void 1433 child_mallocfail(void) 1434 { 1435 Done (EXEC_EXIT_NOMEM, ENOMEM); 1436 } 1437