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