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