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