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