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