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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <dial.h> 34 35 #include <stdlib.h> 36 #include "limits.h" 37 #include "stdarg.h" 38 #include "wait.h" 39 #include "dial.h" 40 #include "lpsched.h" 41 #include <syslog.h> 42 #include <pwd.h> 43 44 #define Done(EC,ERRNO) done(((EC) << 8),ERRNO) 45 46 #define STRLCAT(dst, src, size) \ 47 if (strlcat((dst), (src), (size)) >= (size)) { \ 48 errno = EINVAL; \ 49 return (-1); \ 50 } 51 52 static MESG * ChildMd; 53 54 static int ChildPid; 55 static int WaitedChildPid; 56 static int slot; 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 static char * 135 arg_string(enum trust type, char *fmt, ...) 136 { 137 char buf[BUFSIZ]; 138 va_list args; 139 140 va_start(args, fmt); 141 (void) vsnprintf(buf, sizeof(buf), fmt, args); 142 va_end(args); 143 144 /* 145 * If the string contains data from an untrusted origin (user supplied), 146 * clean it up in case one of our progeny is a shell script and isn't 147 * careful about checking its input. 148 */ 149 if (type == UNTRUSTED) 150 clean_string(buf); 151 152 return (strdup(buf)); 153 } 154 155 /* stolen from libc/gen/port/gen/execvp.c */ 156 static const char * 157 execat(const char *s1, const char *s2, char *si) 158 { 159 char *s; 160 int cnt = PATH_MAX + 1; /* number of characters in s2 */ 161 162 s = si; 163 while (*s1 && *s1 != ':') { 164 if (cnt > 0) { 165 *s++ = *s1++; 166 cnt--; 167 } else 168 s1++; 169 } 170 if (si != s && cnt > 0) { 171 *s++ = '/'; 172 cnt--; 173 } 174 while (*s2 && cnt > 0) { 175 *s++ = *s2++; 176 cnt--; 177 } 178 *s = '\0'; 179 return (*s1 ? ++s1: 0); 180 } 181 182 /* 183 * Similiar to execvp(), execpt you can supply an environment and we always 184 * use /bin/sh for shell scripts. The PATH searched is the PATH in the 185 * current environment, not the environment in the argument list. 186 * This was pretty much stolen from libc/gen/port/execvp.c 187 */ 188 static int 189 execvpe(char *name, char *const argv[], char *const envp[]) 190 { 191 char *path; 192 char fname[PATH_MAX+2]; 193 char *newargs[256]; 194 int i; 195 const char *cp; 196 unsigned etxtbsy = 1; 197 int eacces = 0; 198 199 if (*name == '\0') { 200 errno = ENOENT; 201 return (-1); 202 } 203 204 if ((path = getenv("PATH")) == NULL) 205 path = "/usr/bin:/bin"; 206 207 cp = strchr(name, '/')? (const char *)"": path; 208 209 do { 210 cp = execat(cp, name, fname); 211 retry: 212 /* 213 * 4025035 and 4038378 214 * if a filename begins with a "-" prepend "./" so that 215 * the shell can't interpret it as an option 216 */ 217 if (*fname == '-') { 218 size_t size = strlen(fname) + 1; 219 if ((size + 2) > sizeof (fname)) { 220 errno = E2BIG; 221 return (-1); 222 } 223 (void) memmove(fname + 2, fname, size); 224 fname[0] = '.'; 225 fname[1] = '/'; 226 } 227 (void) execve(fname, argv, envp); 228 switch (errno) { 229 case ENOEXEC: 230 newargs[0] = "sh"; 231 newargs[1] = fname; 232 for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) { 233 if (i >= 254) { 234 errno = E2BIG; 235 return (-1); 236 } 237 } 238 (void) execve("/bin/sh", newargs, envp); 239 return (-1); 240 case ETXTBSY: 241 if (++etxtbsy > 5) 242 return (-1); 243 (void) sleep(etxtbsy); 244 goto retry; 245 case EACCES: 246 ++eacces; 247 break; 248 case ENOMEM: 249 case E2BIG: 250 case EFAULT: 251 return (-1); 252 } 253 } while (cp); 254 if (eacces) 255 errno = EACCES; 256 return (-1); 257 } 258 259 static char time_buf[50]; 260 /** 261 ** exec() - FORK AND EXEC CHILD PROCESS 262 **/ 263 264 /*VARARGS1*/ 265 int 266 exec(int type, ...) 267 { 268 va_list args; 269 270 int i; 271 int procuid; 272 int procgid; 273 int ret; 274 int fr_flg; 275 276 char *cp; 277 char *infile; 278 char *outfile; 279 char *errfile; 280 char *sep; 281 282 char **listp; 283 char **file_list; 284 char *printerName; 285 char *printerNameToShow; 286 static char nameBuf[100]; 287 char *clean_title; 288 289 PSTATUS *printer; 290 291 RSTATUS *request; 292 293 FSTATUS *form; 294 295 EXEC *ep; 296 297 PWSTATUS *pwheel; 298 time_t now; 299 struct passwd *pwp; 300 #ifdef LP_USE_PAPI_ATTR 301 struct stat tmpBuf; 302 char tmpName[BUFSIZ]; 303 char *path = NULL; 304 #endif 305 char *av[ARG_MAX]; 306 char **envp = NULL; 307 int ac = 0; 308 309 syslog(LOG_DEBUG, "exec(%s)", _exec_name(type)); 310 311 memset(av, 0, sizeof (*av)); 312 313 va_start (args, type); 314 315 switch (type) { 316 317 case EX_INTERF: 318 printer = va_arg(args, PSTATUS *); 319 if (printer->status & PS_REMOTE) { 320 errno = EINVAL; 321 return (-1); 322 } 323 request = printer->request; 324 ep = printer->exec; 325 break; 326 327 case EX_FAULT_MESSAGE: 328 printer = va_arg(args, PSTATUS *); 329 request = va_arg(args, RSTATUS *); 330 if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) { 331 return(0); 332 } 333 ep = printer->fault_exec; 334 printerName = (printer->printer && printer->printer->name 335 ? printer->printer->name : "??"); 336 snprintf(nameBuf, sizeof (nameBuf), 337 "%s (on %s)\n", printerName, Local_System); 338 339 printerNameToShow = nameBuf; 340 341 (void) time(&now); 342 (void) strftime(time_buf, sizeof (time_buf), 343 NULL, localtime(&now)); 344 break; 345 346 case EX_SLOWF: 347 request = va_arg(args, RSTATUS *); 348 ep = request->exec; 349 break; 350 351 case EX_NOTIFY: 352 request = va_arg(args, RSTATUS *); 353 if (request->request->actions & ACT_NOTIFY) { 354 errno = EINVAL; 355 return (-1); 356 } 357 ep = request->exec; 358 break; 359 360 case EX_ALERT: 361 printer = va_arg(args, PSTATUS *); 362 if (!(printer->printer->fault_alert.shcmd)) { 363 errno = EINVAL; 364 return(-1); 365 } 366 ep = printer->alert->exec; 367 break; 368 369 case EX_PALERT: 370 pwheel = va_arg(args, PWSTATUS *); 371 ep = pwheel->alert->exec; 372 break; 373 374 case EX_FORM_MESSAGE: 375 (void) time(&now); 376 (void) strftime(time_buf, sizeof (time_buf), 377 NULL, localtime(&now)); 378 379 /*FALLTHRU*/ 380 case EX_FALERT: 381 form = va_arg(args, FSTATUS *); 382 ep = form->alert->exec; 383 break; 384 385 default: 386 errno = EINVAL; 387 return(-1); 388 389 } 390 va_end (args); 391 392 if (!ep || (ep->pid > 0)) { 393 errno = EBUSY; 394 return(-1); 395 } 396 397 ep->flags = 0; 398 399 key = ep->key = getkey(); 400 slot = ep - Exec_Table; 401 402 switch ((ep->pid = Fork1(ep))) { 403 404 case -1: 405 relock (); 406 return(-1); 407 408 case 0: 409 /* 410 * We want to be able to tell our parent how we died. 411 */ 412 lp_alloc_fail_handler = child_mallocfail; 413 break; 414 415 default: 416 switch(type) { 417 418 case EX_INTERF: 419 request->request->outcome |= RS_PRINTING; 420 break; 421 422 case EX_NOTIFY: 423 request->request->outcome |= RS_NOTIFYING; 424 break; 425 426 case EX_SLOWF: 427 request->request->outcome |= RS_FILTERING; 428 request->request->outcome &= ~RS_REFILTER; 429 break; 430 431 } 432 return(0); 433 434 } 435 436 for (i = 0; i < NSIG; i++) 437 (void)signal (i, SIG_DFL); 438 (void)signal (SIGALRM, SIG_IGN); 439 (void)signal (SIGTERM, sigtrap); 440 441 for (i = 0; i < OpenMax; i++) 442 if (i != ChildMd->writefd) 443 Close (i); 444 445 setpgrp(); 446 447 /* Set a default path */ 448 addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin"); 449 /* copy locale related variables */ 450 addenv (&envp, "TZ", getenv("TZ")); 451 addenv (&envp, "LANG", getenv("LANG")); 452 addenv (&envp, "LC_ALL", getenv("LC_ALL")); 453 addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE")); 454 addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE")); 455 addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES")); 456 addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY")); 457 addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC")); 458 addenv (&envp, "LC_TIME", getenv("LC_TIME")); 459 460 sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key); 461 addenv (&envp, "SPOOLER_KEY", cp); 462 463 #if defined(DEBUG) 464 addenv (&envp, "LPDEBUG", (debug? "1" : "0")); 465 #endif 466 467 /* 468 * Open the standard input, standard output, and standard error. 469 */ 470 switch (type) { 471 472 case EX_SLOWF: 473 case EX_INTERF: 474 /* 475 * stdin: /dev/null 476 * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF) 477 * stderr: req# 478 */ 479 infile = 0; 480 outfile = 0; 481 errfile = makereqerr(request); 482 break; 483 484 case EX_NOTIFY: 485 /* 486 * stdin: req# 487 * stdout: /dev/null 488 * stderr: /dev/null 489 */ 490 infile = makereqerr(request); 491 outfile = 0; 492 errfile = 0; 493 494 break; 495 496 case EX_ALERT: 497 case EX_FALERT: 498 case EX_PALERT: 499 case EX_FAULT_MESSAGE: 500 case EX_FORM_MESSAGE: 501 /* 502 * stdin: /dev/null 503 * stdout: /dev/null 504 * stderr: /dev/null 505 */ 506 infile = 0; 507 outfile = 0; 508 errfile = 0; 509 break; 510 511 } 512 513 if (infile) { 514 if (Open(infile, O_RDONLY) == -1) 515 Done (EXEC_EXIT_NOPEN, errno); 516 } else { 517 if (Open("/dev/null", O_RDONLY) == -1) 518 Done (EXEC_EXIT_NOPEN, errno); 519 } 520 521 if (outfile) { 522 if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) 523 Done (EXEC_EXIT_NOPEN, errno); 524 } else { 525 /* 526 * If EX_INTERF, this is still needed to cause the 527 * standard error channel to be #2. 528 */ 529 if (Open("/dev/null", O_WRONLY) == -1) 530 Done (EXEC_EXIT_NOPEN, errno); 531 } 532 533 if (errfile) { 534 if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) 535 Done (EXEC_EXIT_NOPEN, errno); 536 } else { 537 if (Open("/dev/null", O_WRONLY) == -1) 538 Done (EXEC_EXIT_NOPEN, errno); 539 } 540 541 switch (type) { 542 543 case EX_INTERF: 544 /* 545 * Opening a ``port'' can be dangerous to our health: 546 * 547 * - Hangups can occur if the line is dropped. 548 * - The printer may send an interrupt. 549 * - A FIFO may be closed, generating SIGPIPE. 550 * 551 * We catch these so we can complain nicely. 552 */ 553 trap_fault_signals (); 554 555 (void)Close (1); 556 557 if (strchr (request->secure->user, '!')) 558 { 559 procuid = Lp_Uid; 560 procgid = Lp_Gid; 561 } 562 else 563 { 564 procuid = request->secure->uid; 565 procgid = request->secure->gid; 566 } 567 if (printer->printer->dial_info) 568 { 569 ret = open_dialup(request->printer_type, 570 printer->printer); 571 if (ret == 0) 572 do_undial = 1; 573 } 574 else 575 { 576 ret = open_direct(request->printer_type, 577 printer->printer); 578 do_undial = 0; 579 /* this is a URI */ 580 if (is_printer_uri(printer->printer->device) == 0) 581 addenv(&envp, "DEVICE_URI", 582 printer->printer->device); 583 } 584 addenv(&envp, "DEVICE_URI", 585 printer->printer->device); 586 if (ret != 0) 587 Done (ret, errno); 588 589 if (!(request->request->outcome & RS_FILTERED)) 590 file_list = request->request->file_list; 591 592 else { 593 register int count = 0; 594 register char * num = BIGGEST_REQID_S; 595 register char * prefix; 596 597 prefix = makestr( 598 Lp_Tmp, 599 "/", 600 (request->secure && request->secure->system ? 601 request->secure->system : Local_System), 602 "/F", 603 getreqno(request->secure->req_id), 604 "-", 605 (char *)0 606 ); 607 608 file_list = (char **)Malloc( 609 (lenlist(request->request->file_list) + 1) 610 * sizeof(char *) 611 ); 612 613 for ( 614 listp = request->request->file_list; 615 *listp; 616 listp++ 617 ) { 618 sprintf (num, "%d", count + 1); 619 file_list[count] = makestr( 620 prefix, 621 num, 622 (char *)0 623 ); 624 count++; 625 } 626 file_list[count] = 0; 627 } 628 629 #ifdef LP_USE_PAPI_ATTR 630 /* 631 * Check if the PAPI job attribute file exists, if it does 632 * pass the file's pathname to the printer interface script 633 * in an environment variable. This file is created when 634 * print jobs are submitted via the PAPI interface. 635 */ 636 snprintf(tmpName, sizeof (tmpName), "%s-%s", 637 getreqno(request->secure->req_id), LP_PAPIATTRNAME); 638 path = makepath(SPOOLDIR, "temp", tmpName, (char *)0); 639 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 640 { 641 /* 642 * IPP job attribute file exists for this job so 643 * set the environment variable 644 */ 645 syslog(LOG_DEBUG, "exec(): ATTRPATH='%s'", path); 646 addenv(&envp, "ATTRPATH", path); 647 } 648 Free(path); 649 650 /* 651 * now set environment variable for the printer's PostScript 652 * Printer Description (PPD) file, this is used by the filter 653 * when forming the print data for this printer. 654 */ 655 if ((request->printer != NULL) && 656 (request->printer->printer != NULL) && 657 (request->printer->printer->name != NULL)) 658 { 659 snprintf(tmpName, sizeof (tmpName), "%s.ppd", 660 request->printer->printer->name); 661 path = makepath(ETCDIR, "ppd", tmpName, (char *)0); 662 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 663 { 664 syslog(LOG_DEBUG, 665 "exec(): Printer PPD='%s'", path); 666 addenv(&envp, "PPD", path); 667 } 668 Free(path); 669 } 670 #endif 671 672 if (request->printer_type) 673 addenv(&envp, "TERM", request->printer_type); 674 675 if (!(printer->printer->daisy)) { 676 register char * chset = 0; 677 register char * csp; 678 679 if ( 680 request->form 681 && request->form->form->chset 682 && request->form->form->mandatory 683 && !STREQU(NAME_ANY, request->form->form->chset) 684 ) 685 chset = request->form->form->chset; 686 687 else if ( 688 request->request->charset 689 && !STREQU(NAME_ANY, request->request->charset) 690 ) 691 chset = request->request->charset; 692 693 if (chset) { 694 csp = search_cslist( 695 chset, 696 printer->printer->char_sets 697 ); 698 699 /* 700 * The "strtok()" below wrecks the string 701 * for future use, but this is a child 702 * process where it won't be needed again. 703 */ 704 addenv (&envp, "CHARSET", 705 (csp? strtok(csp, "=") : chset) 706 ); 707 } 708 } 709 710 if (request->fast) 711 addenv(&envp, "FILTER", request->fast); 712 713 /* 714 */ 715 if (strcmp (request->secure->user, request->request->user)) 716 { 717 addenv (&envp, "ALIAS_USERNAME", 718 request->request->user); 719 } 720 /* 721 * Add the system name to the user name (ala system!user) 722 * unless it is already there. RFS users may have trouble 723 * here, sorry! 724 */ 725 cp = strchr(request->secure->user, '@'); 726 727 allTraysWithForm(printer, request->form); 728 729 /* 730 * Fix for 4137389 731 * Remove double quotes from title string. 732 */ 733 fr_flg = 1; 734 clean_title = strdup(NB(request->request->title)); 735 if (clean_title == NULL) { 736 /* 737 * strdup failed. We're probably hosed 738 * but try setting clean_title 739 * to original title and continuing. 740 */ 741 clean_title = NB(request->request->title); 742 fr_flg = 0; 743 } else if (strcmp(clean_title, "") != 0) { 744 char *ct_p; 745 746 for (ct_p = clean_title; *ct_p != NULL; ct_p++) { 747 if (*ct_p == '"') 748 *ct_p = ' '; 749 } 750 } 751 752 av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces, 753 printer->printer->name); 754 av[ac++] = arg_string(TRUSTED, "%s", request->secure->req_id); 755 av[ac++] = arg_string(UNTRUSTED, "%s%s%s", 756 request->secure->user, 757 (cp? "" : "@"), 758 (cp? "" : request->secure->system)); 759 av[ac++] = arg_string(TRUSTED, "%s", clean_title); 760 av[ac++] = arg_string(TRUSTED, "%d", request->copies); 761 762 if (fr_flg) 763 free (clean_title); 764 765 sep = ""; 766 767 /* 768 * Do the administrator defined key=value pair options 769 */ 770 771 argbuf[0] = '\0'; 772 773 if (printer->printer->options) { 774 char **tmp = printer->printer->options; 775 while(*tmp != NULL) { 776 STRLCAT(argbuf, sep, sizeof (argbuf)); 777 sep = " "; 778 STRLCAT(argbuf, *tmp++, sizeof (argbuf)); 779 } 780 } 781 782 /* 783 * Do the administrator defined ``stty'' stuff before 784 * the user's -o options, to allow the user to override. 785 */ 786 if (printer->printer->stty) { 787 STRLCAT (argbuf, sep, sizeof (argbuf)); 788 sep = " "; 789 STRLCAT (argbuf, "stty='", sizeof (argbuf)); 790 STRLCAT (argbuf, printer->printer->stty, 791 sizeof (argbuf)); 792 STRLCAT (argbuf, "'", sizeof (argbuf)); 793 } 794 795 /* 796 * Do all of the user's options except the cpi/lpi/etc. 797 * stuff, which is done separately. 798 */ 799 if (request->request->options) { 800 listp = dashos(request->request->options); 801 while (*listp) { 802 if ( 803 !STRNEQU(*listp, "cpi=", 4) 804 && !STRNEQU(*listp, "lpi=", 4) 805 && !STRNEQU(*listp, "width=", 6) 806 && !STRNEQU(*listp, "length=", 7) 807 ) { 808 STRLCAT (argbuf, sep, sizeof (argbuf)); 809 sep = " "; 810 STRLCAT (argbuf, *listp, 811 sizeof (argbuf)); 812 } 813 listp++; 814 } 815 } 816 817 /* 818 * The "pickfilter()" routine (from "validate()") 819 * stored the cpi/lpi/etc. stuff that should be 820 * used for this request. It chose form over user, 821 * and user over printer. 822 */ 823 if (request->cpi) { 824 STRLCAT (argbuf, sep, sizeof (argbuf)); 825 sep = " "; 826 STRLCAT (argbuf, "cpi=", sizeof (argbuf)); 827 STRLCAT (argbuf, request->cpi, sizeof (argbuf)); 828 } 829 if (request->lpi) { 830 STRLCAT (argbuf, sep, sizeof (argbuf)); 831 sep = " "; 832 STRLCAT (argbuf, "lpi=", sizeof (argbuf)); 833 STRLCAT (argbuf, request->lpi, sizeof (argbuf)); 834 } 835 if (request->pwid) { 836 STRLCAT (argbuf, sep, sizeof (argbuf)); 837 sep = " "; 838 STRLCAT (argbuf, "width=", sizeof (argbuf)); 839 STRLCAT (argbuf, request->pwid, sizeof (argbuf)); 840 } 841 if (request->plen) { 842 STRLCAT (argbuf, sep, sizeof (argbuf)); 843 sep = " "; 844 STRLCAT (argbuf, "length=", sizeof (argbuf)); 845 STRLCAT (argbuf, request->plen, sizeof (argbuf)); 846 } 847 848 /* 849 * Do the ``raw'' bit last, to ensure it gets 850 * done. If the user doesn't want this, then he or 851 * she can do the correct thing using -o stty= 852 * and leaving out the -r option. 853 */ 854 if (request->request->actions & ACT_RAW) { 855 STRLCAT (argbuf, sep, sizeof (argbuf)); 856 sep = " "; 857 STRLCAT (argbuf, "stty=-opost", sizeof (argbuf)); 858 } 859 860 861 /* the "options" */ 862 av[ac++] = arg_string(UNTRUSTED, "%s", argbuf); 863 864 for (listp = file_list; *listp; listp++) 865 av[ac++] = arg_string(TRUSTED, "%s", *listp); 866 867 (void)chfiles (file_list, procuid, procgid); 868 869 break; 870 871 872 case EX_SLOWF: 873 if (request->slow) 874 addenv(&envp, "FILTER", request->slow); 875 876 if (strchr (request->secure->user, '!')) 877 { 878 procuid = Lp_Uid; 879 procgid = Lp_Gid; 880 } 881 else 882 { 883 procuid = request->secure->uid; 884 procgid = request->secure->gid; 885 } 886 cp = _alloc_files( 887 lenlist(request->request->file_list), 888 getreqno(request->secure->req_id), 889 procuid, 890 procgid, 891 (request->secure && request->secure->system ? 892 request->secure->system : NULL ) 893 ); 894 895 av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter); 896 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_Tmp, 897 (request->secure && request->secure->system ? 898 request->secure->system : Local_System), 899 cp); 900 for (listp = request->request->file_list; *listp; listp++) 901 av[ac++] = arg_string(TRUSTED, "%s", *listp); 902 903 (void)chfiles (request->request->file_list, procuid, procgid); 904 905 #ifdef LP_USE_PAPI_ATTR 906 /* 907 * Check if the PAPI job attribute file exists, if it does 908 * pass the file's pathname to the slow-filters in an 909 * environment variable. Note: this file is created when 910 * print jobs are submitted via the PAPI interface. 911 */ 912 snprintf(tmpName, sizeof (tmpName), "%s-%s", 913 getreqno(request->secure->req_id), LP_PAPIATTRNAME); 914 path = makepath(SPOOLDIR, "temp", tmpName, (char *)0); 915 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 916 { 917 /* 918 * IPP job attribute file exists for this job so 919 * set the environment variable 920 */ 921 syslog(LOG_DEBUG, "exec(): ATTRPATH='%s'", path); 922 addenv(&envp, "ATTRPATH", path); 923 } 924 Free(path); 925 926 927 /* 928 * now set environment variable for the printer's PostScript 929 * Printer Description (PPD) file, this is used by the filter 930 * when forming the print data for this printer. 931 */ 932 if ((request->printer != NULL) && 933 (request->printer->printer != NULL) && 934 (request->printer->printer->name != NULL)) 935 { 936 snprintf(tmpName, sizeof (tmpName), "%s.ppd", 937 request->printer->printer->name); 938 path = makepath(ETCDIR, "ppd", tmpName, (char *)0); 939 if ((path != NULL) && (stat(path, &tmpBuf) == 0)) 940 { 941 syslog(LOG_DEBUG, 942 "exec(): Printer PPD='%s'", path); 943 addenv(&envp, "PPD", path); 944 } 945 Free(path); 946 } 947 #endif 948 break; 949 950 case EX_ALERT: 951 procuid = Lp_Uid; 952 procgid = Lp_Gid; 953 (void)Chown (printer->alert->msgfile, procuid, procgid); 954 955 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, 956 printer->printer->name, ALERTSHFILE); 957 av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); 958 959 break; 960 961 case EX_PALERT: 962 procuid = Lp_Uid; 963 procgid = Lp_Gid; 964 (void)Chown (pwheel->alert->msgfile, procuid, procgid); 965 966 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels, 967 pwheel->pwheel->name, ALERTSHFILE); 968 av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); 969 970 break; 971 972 case EX_FALERT: 973 procuid = Lp_Uid; 974 procgid = Lp_Gid; 975 (void)Chown (form->alert->msgfile, procuid, procgid); 976 977 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, 978 form->form->name, ALERTSHFILE); 979 av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); 980 981 break; 982 983 case EX_FORM_MESSAGE: 984 procuid = Lp_Uid; 985 procgid = Lp_Gid; 986 987 av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults); 988 av[ac++] = arg_string(TRUSTED, "%s", form->form->name); 989 av[ac++] = arg_string(TRUSTED, "%s", time_buf); 990 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, 991 form->form->name, FORMMESSAGEFILE); 992 993 break; 994 995 case EX_FAULT_MESSAGE: 996 procuid = Lp_Uid; 997 procgid = Lp_Gid; 998 999 av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults); 1000 av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow); 1001 av[ac++] = arg_string(TRUSTED, "%s", time_buf); 1002 av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, 1003 printerName, FAULTMESSAGEFILE); 1004 1005 break; 1006 1007 case EX_NOTIFY: 1008 if (request->request->alert) { 1009 if (strchr(request->secure->user, '!')) { 1010 procuid = Lp_Uid; 1011 procgid = Lp_Gid; 1012 } else { 1013 procuid = request->secure->uid; 1014 procgid = request->secure->gid; 1015 } 1016 av[ac++] = arg_string(TRUSTED, "%s", 1017 request->request->alert); 1018 } else { 1019 char *user = strdup(request->secure->user); 1020 procuid = Lp_Uid; 1021 procgid = Lp_Gid; 1022 clean_string(user); 1023 1024 if ((request->request->actions & ACT_WRITE) && 1025 (!request->secure->system || 1026 STREQU(request->secure->system, Local_System))) { 1027 av[ac++] = arg_string(TRUSTED, "%s", BINWRITE); 1028 snprintf(argbuf, sizeof (argbuf), 1029 "%s %s || %s %s", 1030 BINWRITE, user, 1031 BINMAIL, user 1032 ); 1033 av[ac++] = arg_string(TRUSTED, "/bin/sh"); 1034 av[ac++] = arg_string(TRUSTED, "-c"); 1035 av[ac++] = arg_string(TRUSTED, "%s", argbuf); 1036 } else { 1037 av[ac++] = arg_string(TRUSTED, "%s", BINMAIL); 1038 av[ac++] = arg_string(UNTRUSTED, "%s", user); 1039 } 1040 1041 free(user); 1042 } 1043 break; 1044 } 1045 1046 av[ac++] = NULL; 1047 1048 Fork2 (); 1049 /* only the child returns */ 1050 1051 /* 1052 * Correctly set up the supplemental group list 1053 * for proper file access (before execl the interface program) 1054 */ 1055 1056 pwp = getpwuid(procuid); 1057 if (pwp == NULL) { 1058 note("getpwuid(%d) call failed\n", procuid); 1059 } else if (initgroups(pwp->pw_name, procgid) < 0) { 1060 note("initgroups() call failed %d\n", errno); 1061 } 1062 1063 setgid (procgid); 1064 setuid (procuid); 1065 1066 /* 1067 * The shell doesn't allow the "trap" builtin to set a trap 1068 * for a signal ignored when the shell is started. Thus, don't 1069 * turn off signals in the last child! 1070 */ 1071 1072 for (i = 0; av[i] != NULL; i++) 1073 syslog(LOG_DEBUG, "exec: av[%d] = %s", i, av[i]); 1074 for (i = 0; av[i] != NULL; i++) 1075 syslog(LOG_DEBUG, "exec: envp[%d] = %s", i, envp[i]); 1076 1077 execvpe(av[0], av, envp); 1078 Done (EXEC_EXIT_NEXEC, errno); 1079 /*NOTREACHED*/ 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