xref: /onnv-gate/usr/src/cmd/lp/cmd/lpsched/exec.c (revision 12724:f08debe63952)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213125Sjacobs 
220Sstevel@tonic-gate /*
23*12248SSonam.Gupta@Sun.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
26320Sceastha /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27320Sceastha /*	  All Rights Reserved  	*/
28320Sceastha 
291676Sjpk #include <pwd.h>
301676Sjpk #include <zone.h>
311676Sjpk #if defined PS_FAULTED
321676Sjpk #undef  PS_FAULTED
331676Sjpk #endif /* PS_FAULTED */
340Sstevel@tonic-gate #include <dial.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <stdlib.h>
370Sstevel@tonic-gate #include "limits.h"
380Sstevel@tonic-gate #include "stdarg.h"
390Sstevel@tonic-gate #include "wait.h"
400Sstevel@tonic-gate #include "dial.h"
410Sstevel@tonic-gate #include "lpsched.h"
420Sstevel@tonic-gate #include <syslog.h>
431676Sjpk #include "tsol/label.h"
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #define Done(EC,ERRNO)	done(((EC) << 8),ERRNO)
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #define	STRLCAT(dst, src, size) \
480Sstevel@tonic-gate 	if (strlcat((dst), (src), (size)) >= (size)) { \
490Sstevel@tonic-gate 		errno = EINVAL; \
500Sstevel@tonic-gate 		return (-1); \
510Sstevel@tonic-gate 	}
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static MESG *		ChildMd;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate static int		ChildPid;
560Sstevel@tonic-gate static int		WaitedChildPid;
570Sstevel@tonic-gate static int		do_undial;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static char		argbuf[ARG_MAX];
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static long		key;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static void		sigtrap ( int );
640Sstevel@tonic-gate static void		done ( int , int );
650Sstevel@tonic-gate static void		cool_heels ( void );
660Sstevel@tonic-gate static void		addenv (char ***envp, char * , char * );
670Sstevel@tonic-gate static void		trap_fault_signals ( void );
680Sstevel@tonic-gate static void		ignore_fault_signals ( void );
690Sstevel@tonic-gate static void		child_mallocfail ( void );
700Sstevel@tonic-gate static void		Fork2 ( void );
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static int		Fork1 ( EXEC * );
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static void
relock(void)750Sstevel@tonic-gate relock(void)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	struct flock		l;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	l.l_type = F_WRLCK;
800Sstevel@tonic-gate 	l.l_whence = 1;
810Sstevel@tonic-gate 	l.l_start = 0;
820Sstevel@tonic-gate 	l.l_len = 0;
830Sstevel@tonic-gate 	(void)Fcntl (lock_fd, F_SETLK, &l);
840Sstevel@tonic-gate 	return;
850Sstevel@tonic-gate }
860Sstevel@tonic-gate 
_exec_name(int type)870Sstevel@tonic-gate static char *_exec_name(int type)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	static char *_names[] = {
900Sstevel@tonic-gate 	"", "EX_INTERF", "EX_SLOWF", "EX_ALERT", "EX_FALERT", "EX_PALERT",
910Sstevel@tonic-gate 	"EX_NOTIFY", "EX_FAULT_MESSAGE", "EX_FORM_MESSAGE", NULL };
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	if ((type < 0) || (type > EX_FORM_MESSAGE))
940Sstevel@tonic-gate 		return ("BAD_EXEC_TYPE");
950Sstevel@tonic-gate 	else
960Sstevel@tonic-gate 		return (_names[type]);
970Sstevel@tonic-gate }
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * This function replaces characters in a string that might be used
1010Sstevel@tonic-gate  * to exploit a security hole.  Replace command seperators (`, &, ;, |, ^),
1020Sstevel@tonic-gate  * output redirection (>, |), variable expansion ($), and character
1030Sstevel@tonic-gate  * escape (\).
1040Sstevel@tonic-gate  *
1050Sstevel@tonic-gate  * Bugid 4141687
1060Sstevel@tonic-gate  * Add ( ) < * ? [
1070Sstevel@tonic-gate  * Bugid 4139071
1080Sstevel@tonic-gate  * Remove \
1090Sstevel@tonic-gate  */
clean_string(char * ptr)1100Sstevel@tonic-gate void clean_string(char *ptr)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	char *cp;
1130Sstevel@tonic-gate 	wchar_t wc;
1140Sstevel@tonic-gate 	size_t len;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	for (cp = ptr; *cp != NULL; ) {
1170Sstevel@tonic-gate 		if ((len = mbtowc(&wc, cp, MB_CUR_MAX)) == -1) {
1180Sstevel@tonic-gate 			cp++;
1190Sstevel@tonic-gate 			continue;
1200Sstevel@tonic-gate 		}
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 		if (len == 1 &&
1230Sstevel@tonic-gate 		    ((wc == L'`') || (wc == L'&') || (wc == L';') ||
1240Sstevel@tonic-gate 		    (wc == L'|') || (wc == L'>') || (wc == L'^') ||
1250Sstevel@tonic-gate 		    (wc == L'$') || (wc == L'(') || (wc == L')') ||
1260Sstevel@tonic-gate 		    (wc == L'<') || (wc == L'*') || (wc == L'?') ||
1270Sstevel@tonic-gate 		    (wc == L'[')))
1280Sstevel@tonic-gate 			*cp = '_';
1290Sstevel@tonic-gate 		cp += len;
1300Sstevel@tonic-gate 	}
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate enum trust {TRUSTED, UNTRUSTED};
1343204Sjacobs 
1353204Sjacobs static char *arg_string(enum trust type, char *fmt, ...) __PRINTFLIKE(2);
1363204Sjacobs 
1373204Sjacobs /* PRINTFLIKE2 */
1380Sstevel@tonic-gate static char *
arg_string(enum trust type,char * fmt,...)1390Sstevel@tonic-gate arg_string(enum trust type, char *fmt, ...)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	char buf[BUFSIZ];
1420Sstevel@tonic-gate 	va_list	args;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	va_start(args, fmt);
1450Sstevel@tonic-gate 	(void) vsnprintf(buf, sizeof(buf), fmt, args);
1460Sstevel@tonic-gate 	va_end(args);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	/*
1490Sstevel@tonic-gate 	 * If the string contains data from an untrusted origin (user supplied),
1500Sstevel@tonic-gate 	 * clean it up in case one of our progeny is a shell script and isn't
1510Sstevel@tonic-gate 	 * careful about checking its input.
1520Sstevel@tonic-gate 	 */
1530Sstevel@tonic-gate 	if (type == UNTRUSTED)
1540Sstevel@tonic-gate 		clean_string(buf);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	return (strdup(buf));
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /* stolen from libc/gen/port/gen/execvp.c */
1600Sstevel@tonic-gate static const char *
execat(const char * s1,const char * s2,char * si)1610Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate         char    *s;
1640Sstevel@tonic-gate         int cnt = PATH_MAX + 1; /* number of characters in s2 */
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate         s = si;
1670Sstevel@tonic-gate         while (*s1 && *s1 != ':') {
1680Sstevel@tonic-gate                 if (cnt > 0) {
1690Sstevel@tonic-gate                         *s++ = *s1++;
1700Sstevel@tonic-gate                         cnt--;
1710Sstevel@tonic-gate                 } else
1720Sstevel@tonic-gate                         s1++;
1730Sstevel@tonic-gate         }
1740Sstevel@tonic-gate         if (si != s && cnt > 0) {
1750Sstevel@tonic-gate                 *s++ = '/';
1760Sstevel@tonic-gate                 cnt--;
1770Sstevel@tonic-gate         }
1780Sstevel@tonic-gate         while (*s2 && cnt > 0) {
1790Sstevel@tonic-gate                 *s++ = *s2++;
1800Sstevel@tonic-gate                 cnt--;
1810Sstevel@tonic-gate         }
1820Sstevel@tonic-gate         *s = '\0';
1830Sstevel@tonic-gate         return (*s1 ? ++s1: 0);
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate  * Similiar to execvp(), execpt you can supply an environment and we always
1880Sstevel@tonic-gate  * use /bin/sh for shell scripts.  The PATH searched is the PATH in the
1890Sstevel@tonic-gate  * current environment, not the environment in the argument list.
1900Sstevel@tonic-gate  * This was pretty much stolen from libc/gen/port/execvp.c
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate static int
execvpe(char * name,char * const argv[],char * const envp[])1930Sstevel@tonic-gate execvpe(char *name, char *const argv[], char *const envp[])
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	char *path;
1960Sstevel@tonic-gate 	char fname[PATH_MAX+2];
1970Sstevel@tonic-gate 	char *newargs[256];
1980Sstevel@tonic-gate 	int i;
1990Sstevel@tonic-gate 	const char *cp;
2000Sstevel@tonic-gate 	unsigned etxtbsy = 1;
2010Sstevel@tonic-gate         int eacces = 0;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if (*name == '\0') {
2040Sstevel@tonic-gate 		errno = ENOENT;
2050Sstevel@tonic-gate 		return (-1);
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if ((path = getenv("PATH")) == NULL)
2090Sstevel@tonic-gate 		path = "/usr/bin:/bin";
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate         cp = strchr(name, '/')? (const char *)"": path;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate         do {
2140Sstevel@tonic-gate                 cp = execat(cp, name, fname);
2150Sstevel@tonic-gate         retry:
2160Sstevel@tonic-gate                 /*
2170Sstevel@tonic-gate                  * 4025035 and 4038378
2180Sstevel@tonic-gate                  * if a filename begins with a "-" prepend "./" so that
2190Sstevel@tonic-gate                  * the shell can't interpret it as an option
2200Sstevel@tonic-gate                  */
2210Sstevel@tonic-gate                 if (*fname == '-') {
2220Sstevel@tonic-gate                         size_t size = strlen(fname) + 1;
2230Sstevel@tonic-gate                         if ((size + 2) > sizeof (fname)) {
2240Sstevel@tonic-gate                                 errno = E2BIG;
2250Sstevel@tonic-gate                                 return (-1);
2260Sstevel@tonic-gate                         }
2270Sstevel@tonic-gate                         (void) memmove(fname + 2, fname, size);
2280Sstevel@tonic-gate                         fname[0] = '.';
2290Sstevel@tonic-gate                         fname[1] = '/';
2300Sstevel@tonic-gate                 }
2310Sstevel@tonic-gate                 (void) execve(fname, argv, envp);
2320Sstevel@tonic-gate                 switch (errno) {
2330Sstevel@tonic-gate                 case ENOEXEC:
2340Sstevel@tonic-gate                         newargs[0] = "sh";
2350Sstevel@tonic-gate                         newargs[1] = fname;
2360Sstevel@tonic-gate                         for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) {
2370Sstevel@tonic-gate                                 if (i >= 254) {
2380Sstevel@tonic-gate                                         errno = E2BIG;
2390Sstevel@tonic-gate                                         return (-1);
2400Sstevel@tonic-gate                                 }
2410Sstevel@tonic-gate                         }
2420Sstevel@tonic-gate                         (void) execve("/bin/sh", newargs, envp);
2430Sstevel@tonic-gate                         return (-1);
2440Sstevel@tonic-gate                 case ETXTBSY:
2450Sstevel@tonic-gate                         if (++etxtbsy > 5)
2460Sstevel@tonic-gate                                 return (-1);
2470Sstevel@tonic-gate                         (void) sleep(etxtbsy);
2480Sstevel@tonic-gate                         goto retry;
2490Sstevel@tonic-gate                 case EACCES:
2500Sstevel@tonic-gate                         ++eacces;
2510Sstevel@tonic-gate                         break;
2520Sstevel@tonic-gate                 case ENOMEM:
2530Sstevel@tonic-gate                 case E2BIG:
2540Sstevel@tonic-gate                 case EFAULT:
2550Sstevel@tonic-gate                         return (-1);
2560Sstevel@tonic-gate                 }
2570Sstevel@tonic-gate         } while (cp);
2580Sstevel@tonic-gate         if (eacces)
2590Sstevel@tonic-gate                 errno = EACCES;
2600Sstevel@tonic-gate         return (-1);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate static char time_buf[50];
2641676Sjpk 
2650Sstevel@tonic-gate /**
2660Sstevel@tonic-gate  ** exec() - FORK AND EXEC CHILD PROCESS
2670Sstevel@tonic-gate  **/
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate /*VARARGS1*/
2700Sstevel@tonic-gate int
exec(int type,...)2710Sstevel@tonic-gate exec(int type, ...)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	va_list			args;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	int			i;
2760Sstevel@tonic-gate 	int			procuid;
2770Sstevel@tonic-gate 	int			procgid;
2780Sstevel@tonic-gate 	int			ret;
2790Sstevel@tonic-gate 	int			fr_flg;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	char			*cp;
2820Sstevel@tonic-gate 	char			*infile;
2830Sstevel@tonic-gate 	char			*outfile;
2840Sstevel@tonic-gate 	char			*errfile;
2850Sstevel@tonic-gate 	char			*sep;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	char			**listp;
2880Sstevel@tonic-gate 	char			**file_list;
2890Sstevel@tonic-gate 	char			*printerName;
2900Sstevel@tonic-gate 	char			*printerNameToShow;
2910Sstevel@tonic-gate 	static char		nameBuf[100];
2920Sstevel@tonic-gate 	char			*clean_title;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	PSTATUS			*printer;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	RSTATUS			*request;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	FSTATUS			*form;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	EXEC			*ep;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	PWSTATUS		*pwheel;
3030Sstevel@tonic-gate 	time_t			now;
3040Sstevel@tonic-gate 	struct passwd		*pwp;
3050Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
3060Sstevel@tonic-gate 	struct stat		tmpBuf;
3070Sstevel@tonic-gate 	char 			tmpName[BUFSIZ];
3080Sstevel@tonic-gate 	char			*path = NULL;
3090Sstevel@tonic-gate #endif
3100Sstevel@tonic-gate 	char *av[ARG_MAX];
3110Sstevel@tonic-gate 	char **envp = NULL;
3120Sstevel@tonic-gate 	int ac = 0;
3131676Sjpk 	char	*mail_zonename = NULL;
3141676Sjpk 	char	*slabel = NULL;
31510460SSonam.Gupta@Sun.COM 	int	setid = 1;
316*12248SSonam.Gupta@Sun.COM 	char	*ridno = NULL, *tmprid = NULL;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	syslog(LOG_DEBUG, "exec(%s)", _exec_name(type));
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	memset(av, 0, sizeof (*av));
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	va_start (args, type);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	switch (type) {
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	case EX_INTERF:
3270Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3280Sstevel@tonic-gate 		request = printer->request;
3290Sstevel@tonic-gate 		ep = printer->exec;
3300Sstevel@tonic-gate 		break;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
3330Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3340Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3350Sstevel@tonic-gate 		if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) {
3360Sstevel@tonic-gate 			return(0);
3370Sstevel@tonic-gate 		}
3380Sstevel@tonic-gate 		ep = printer->fault_exec;
3390Sstevel@tonic-gate 		printerName = (printer->printer && printer->printer->name
3400Sstevel@tonic-gate 				  ? printer->printer->name : "??");
3410Sstevel@tonic-gate 			snprintf(nameBuf, sizeof (nameBuf),
3420Sstevel@tonic-gate 				"%s (on %s)\n", printerName, Local_System);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 		printerNameToShow = nameBuf;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 		(void) time(&now);
3470Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
3480Sstevel@tonic-gate 			NULL, localtime(&now));
3490Sstevel@tonic-gate 		break;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	case EX_SLOWF:
3520Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3530Sstevel@tonic-gate 		ep = request->exec;
3540Sstevel@tonic-gate 		break;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	case EX_NOTIFY:
3570Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3580Sstevel@tonic-gate 		if (request->request->actions & ACT_NOTIFY) {
3590Sstevel@tonic-gate 			errno = EINVAL;
3600Sstevel@tonic-gate 			return (-1);
3610Sstevel@tonic-gate 		}
3620Sstevel@tonic-gate 		ep = request->exec;
3630Sstevel@tonic-gate 		break;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	case EX_ALERT:
3660Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3670Sstevel@tonic-gate 		if (!(printer->printer->fault_alert.shcmd)) {
3680Sstevel@tonic-gate 			errno = EINVAL;
3690Sstevel@tonic-gate 			return(-1);
3700Sstevel@tonic-gate 		}
3710Sstevel@tonic-gate 		ep = printer->alert->exec;
3720Sstevel@tonic-gate 		break;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	case EX_PALERT:
3750Sstevel@tonic-gate 		pwheel = va_arg(args, PWSTATUS *);
3760Sstevel@tonic-gate 		ep = pwheel->alert->exec;
3770Sstevel@tonic-gate 		break;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
3800Sstevel@tonic-gate 		(void) time(&now);
3810Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
3820Sstevel@tonic-gate 			NULL, localtime(&now));
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 		/*FALLTHRU*/
3850Sstevel@tonic-gate 	case EX_FALERT:
3860Sstevel@tonic-gate 		form = va_arg(args, FSTATUS *);
3870Sstevel@tonic-gate 		ep = form->alert->exec;
3880Sstevel@tonic-gate 		break;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	default:
3910Sstevel@tonic-gate 		errno = EINVAL;
3920Sstevel@tonic-gate 		return(-1);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 	va_end (args);
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if (!ep || (ep->pid > 0)) {
3980Sstevel@tonic-gate 		errno = EBUSY;
3990Sstevel@tonic-gate 		return(-1);
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	ep->flags = 0;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	key = ep->key = getkey();
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	switch ((ep->pid = Fork1(ep))) {
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	case -1:
4090Sstevel@tonic-gate 		relock ();
4100Sstevel@tonic-gate 		return(-1);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	case 0:
4130Sstevel@tonic-gate 		/*
4140Sstevel@tonic-gate 		 * We want to be able to tell our parent how we died.
4150Sstevel@tonic-gate 		 */
4160Sstevel@tonic-gate 		lp_alloc_fail_handler = child_mallocfail;
4170Sstevel@tonic-gate 		break;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	default:
4200Sstevel@tonic-gate 		switch(type) {
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		case EX_INTERF:
4230Sstevel@tonic-gate 			request->request->outcome |= RS_PRINTING;
4240Sstevel@tonic-gate 			break;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		case EX_NOTIFY:
4270Sstevel@tonic-gate 			request->request->outcome |= RS_NOTIFYING;
4280Sstevel@tonic-gate 			break;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		case EX_SLOWF:
4310Sstevel@tonic-gate 			request->request->outcome |= RS_FILTERING;
4320Sstevel@tonic-gate 			request->request->outcome &= ~RS_REFILTER;
4330Sstevel@tonic-gate 			break;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		}
4360Sstevel@tonic-gate 		return(0);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	for (i = 0; i < NSIG; i++)
4410Sstevel@tonic-gate 		(void)signal (i, SIG_DFL);
4420Sstevel@tonic-gate 	(void)signal (SIGALRM, SIG_IGN);
4430Sstevel@tonic-gate 	(void)signal (SIGTERM, sigtrap);
4443125Sjacobs 
4453125Sjacobs 	closelog();
4460Sstevel@tonic-gate 	for (i = 0; i < OpenMax; i++)
4470Sstevel@tonic-gate 		if (i != ChildMd->writefd)
4480Sstevel@tonic-gate 			Close (i);
4493125Sjacobs 	openlog("lpsched", LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR);
4503125Sjacobs 
4510Sstevel@tonic-gate 	setpgrp();
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	/* Set a default path */
4540Sstevel@tonic-gate 	addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin");
4550Sstevel@tonic-gate 	/* copy locale related variables */
4560Sstevel@tonic-gate 	addenv (&envp, "TZ", getenv("TZ"));
4570Sstevel@tonic-gate 	addenv (&envp, "LANG", getenv("LANG"));
4580Sstevel@tonic-gate 	addenv (&envp, "LC_ALL", getenv("LC_ALL"));
4590Sstevel@tonic-gate 	addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE"));
4600Sstevel@tonic-gate 	addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE"));
4610Sstevel@tonic-gate 	addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES"));
4620Sstevel@tonic-gate 	addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY"));
4630Sstevel@tonic-gate 	addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC"));
4640Sstevel@tonic-gate 	addenv (&envp, "LC_TIME", getenv("LC_TIME"));
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key);
4670Sstevel@tonic-gate 	addenv (&envp, "SPOOLER_KEY", cp);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate #if	defined(DEBUG)
4700Sstevel@tonic-gate 	addenv (&envp, "LPDEBUG", (debug? "1" : "0"));
4710Sstevel@tonic-gate #endif
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	/*
4740Sstevel@tonic-gate 	 * Open the standard input, standard output, and standard error.
4750Sstevel@tonic-gate 	 */
4760Sstevel@tonic-gate 	switch (type) {
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	case EX_SLOWF:
4790Sstevel@tonic-gate 	case EX_INTERF:
4800Sstevel@tonic-gate 		/*
4810Sstevel@tonic-gate 		 * stdin:  /dev/null
4820Sstevel@tonic-gate 		 * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF)
4830Sstevel@tonic-gate 		 * stderr: req#
4840Sstevel@tonic-gate 		 */
4850Sstevel@tonic-gate 		infile = 0;
4860Sstevel@tonic-gate 		outfile = 0;
4870Sstevel@tonic-gate 		errfile = makereqerr(request);
4880Sstevel@tonic-gate 		break;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	case EX_NOTIFY:
4910Sstevel@tonic-gate 		/*
4920Sstevel@tonic-gate 		 * stdin:  req#
4930Sstevel@tonic-gate 		 * stdout: /dev/null
4940Sstevel@tonic-gate 		 * stderr: /dev/null
4950Sstevel@tonic-gate 		 */
4960Sstevel@tonic-gate 		infile = makereqerr(request);
4970Sstevel@tonic-gate 		outfile = 0;
4980Sstevel@tonic-gate 		errfile = 0;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 		break;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	case EX_ALERT:
5030Sstevel@tonic-gate 	case EX_FALERT:
5040Sstevel@tonic-gate 	case EX_PALERT:
5050Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
5060Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
5070Sstevel@tonic-gate 		/*
5080Sstevel@tonic-gate 		 * stdin:  /dev/null
5090Sstevel@tonic-gate 		 * stdout: /dev/null
5100Sstevel@tonic-gate 		 * stderr: /dev/null
5110Sstevel@tonic-gate 		 */
5120Sstevel@tonic-gate 		infile = 0;
5130Sstevel@tonic-gate 		outfile = 0;
5140Sstevel@tonic-gate 		errfile = 0;
5150Sstevel@tonic-gate 		break;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	if (infile) {
5200Sstevel@tonic-gate 		if (Open(infile, O_RDONLY) == -1)
5210Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5220Sstevel@tonic-gate 	} else {
5230Sstevel@tonic-gate 		if (Open("/dev/null", O_RDONLY) == -1)
5240Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	if (outfile) {
5280Sstevel@tonic-gate 		if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
5290Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5300Sstevel@tonic-gate 	} else {
5310Sstevel@tonic-gate 		/*
5320Sstevel@tonic-gate 		 * If EX_INTERF, this is still needed to cause the
5330Sstevel@tonic-gate 		 * standard error channel to be #2.
5340Sstevel@tonic-gate 		 */
5350Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
5360Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (errfile) {
5400Sstevel@tonic-gate 		if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
5410Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5420Sstevel@tonic-gate 	} else {
5430Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
5440Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	switch (type) {
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	case EX_INTERF:
5500Sstevel@tonic-gate 		/*
5510Sstevel@tonic-gate 		 * Opening a ``port'' can be dangerous to our health:
5520Sstevel@tonic-gate 		 *
5530Sstevel@tonic-gate 		 *	- Hangups can occur if the line is dropped.
5540Sstevel@tonic-gate 		 *	- The printer may send an interrupt.
5550Sstevel@tonic-gate 		 *	- A FIFO may be closed, generating SIGPIPE.
5560Sstevel@tonic-gate 		 *
5570Sstevel@tonic-gate 		 * We catch these so we can complain nicely.
5580Sstevel@tonic-gate 		 */
5590Sstevel@tonic-gate 		trap_fault_signals ();
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 		(void)Close (1);
5620Sstevel@tonic-gate 
56311378SSonam.Gupta@Sun.COM 		procuid = request->secure->uid;
56411378SSonam.Gupta@Sun.COM 		procgid = request->secure->gid;
56511378SSonam.Gupta@Sun.COM 
5660Sstevel@tonic-gate 		if (printer->printer->dial_info)
5670Sstevel@tonic-gate 		{
5680Sstevel@tonic-gate 			ret = open_dialup(request->printer_type,
5690Sstevel@tonic-gate 				printer->printer);
5700Sstevel@tonic-gate 			if (ret == 0)
5710Sstevel@tonic-gate 				do_undial = 1;
5720Sstevel@tonic-gate 		}
5730Sstevel@tonic-gate 		else
5740Sstevel@tonic-gate 		{
5750Sstevel@tonic-gate 			ret = open_direct(request->printer_type,
5760Sstevel@tonic-gate 				printer->printer);
5770Sstevel@tonic-gate 			do_undial = 0;
5780Sstevel@tonic-gate 			/* this is a URI */
5790Sstevel@tonic-gate 			if (is_printer_uri(printer->printer->device) == 0)
5800Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
5810Sstevel@tonic-gate 					 printer->printer->device);
5820Sstevel@tonic-gate 		}
5830Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
5840Sstevel@tonic-gate 					 printer->printer->device);
5850Sstevel@tonic-gate 		if (ret != 0)
5860Sstevel@tonic-gate 			Done (ret, errno);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		if (!(request->request->outcome & RS_FILTERED))
5890Sstevel@tonic-gate 			file_list = request->request->file_list;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 		else {
5920Sstevel@tonic-gate 			register int		count	= 0;
5930Sstevel@tonic-gate 			register char *		num	= BIGGEST_REQID_S;
5940Sstevel@tonic-gate 			register char *		prefix;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 			prefix = makestr(
5973125Sjacobs 				Lp_Temp,
5980Sstevel@tonic-gate 				"/F",
5990Sstevel@tonic-gate 				getreqno(request->secure->req_id),
6000Sstevel@tonic-gate 				"-",
6010Sstevel@tonic-gate 				(char *)0
6020Sstevel@tonic-gate 			);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 			file_list = (char **)Malloc(
6050Sstevel@tonic-gate 				(lenlist(request->request->file_list) + 1)
6060Sstevel@tonic-gate 			      * sizeof(char *)
6070Sstevel@tonic-gate 			);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 			for (
6100Sstevel@tonic-gate 				listp = request->request->file_list;
6110Sstevel@tonic-gate 				*listp;
6120Sstevel@tonic-gate 				listp++
6130Sstevel@tonic-gate 			) {
6140Sstevel@tonic-gate 				sprintf (num, "%d", count + 1);
6150Sstevel@tonic-gate 				file_list[count] = makestr(
6160Sstevel@tonic-gate 					prefix,
6170Sstevel@tonic-gate 					num,
6180Sstevel@tonic-gate 					(char *)0
6190Sstevel@tonic-gate 				);
6200Sstevel@tonic-gate 				count++;
6210Sstevel@tonic-gate 			}
6220Sstevel@tonic-gate 			file_list[count] = 0;
6230Sstevel@tonic-gate 		}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
6260Sstevel@tonic-gate 		/*
6270Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
6280Sstevel@tonic-gate 		 * pass the file's pathname to the printer interface script
6290Sstevel@tonic-gate 		 * in an environment variable. This file is created when
6300Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
6310Sstevel@tonic-gate 		 */
6320Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
6330Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
6343125Sjacobs 		path = makepath(Lp_Temp, tmpName, (char *)0);
6350Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
6360Sstevel@tonic-gate 		{
6370Sstevel@tonic-gate 			/*
6380Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
6390Sstevel@tonic-gate 			 * set the environment variable
6400Sstevel@tonic-gate 			 */
6410Sstevel@tonic-gate 			addenv(&envp, "ATTRPATH", path);
6420Sstevel@tonic-gate 		}
6430Sstevel@tonic-gate 		Free(path);
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		/*
6460Sstevel@tonic-gate 		 * now set environment variable for the printer's PostScript
6470Sstevel@tonic-gate 		 * Printer Description (PPD) file, this is used by the filter
6480Sstevel@tonic-gate 		 * when forming the print data for this printer.
6490Sstevel@tonic-gate 		 */
6500Sstevel@tonic-gate 		if ((request->printer != NULL) &&
6510Sstevel@tonic-gate 		    (request->printer->printer != NULL) &&
6520Sstevel@tonic-gate 		    (request->printer->printer->name != NULL))
6530Sstevel@tonic-gate 		{
6540Sstevel@tonic-gate 			snprintf(tmpName, sizeof (tmpName), "%s.ppd",
6550Sstevel@tonic-gate 				request->printer->printer->name);
6560Sstevel@tonic-gate 			path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
6570Sstevel@tonic-gate 			if ((path != NULL) && (stat(path, &tmpBuf) == 0))
6580Sstevel@tonic-gate 			{
6590Sstevel@tonic-gate 				addenv(&envp, "PPD", path);
6600Sstevel@tonic-gate 			}
6610Sstevel@tonic-gate 			Free(path);
6620Sstevel@tonic-gate 		}
6630Sstevel@tonic-gate #endif
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 		if (request->printer_type)
6660Sstevel@tonic-gate 			addenv(&envp, "TERM", request->printer_type);
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 		if (!(printer->printer->daisy)) {
6690Sstevel@tonic-gate 			register char *	chset = 0;
6700Sstevel@tonic-gate 			register char *	csp;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 			if (
6730Sstevel@tonic-gate 				request->form
6740Sstevel@tonic-gate 			     && request->form->form->chset
6750Sstevel@tonic-gate 			     && request->form->form->mandatory
6760Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->form->form->chset)
6770Sstevel@tonic-gate 			)
6780Sstevel@tonic-gate 				chset = request->form->form->chset;
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 			else if (
6810Sstevel@tonic-gate 				request->request->charset
6820Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->request->charset)
6830Sstevel@tonic-gate 			)
6840Sstevel@tonic-gate 				chset = request->request->charset;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 			if (chset) {
6870Sstevel@tonic-gate 				csp = search_cslist(
6880Sstevel@tonic-gate 					chset,
6890Sstevel@tonic-gate 					printer->printer->char_sets
6900Sstevel@tonic-gate 				);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 				/*
6930Sstevel@tonic-gate 				 * The "strtok()" below wrecks the string
6940Sstevel@tonic-gate 				 * for future use, but this is a child
6950Sstevel@tonic-gate 				 * process where it won't be needed again.
6960Sstevel@tonic-gate 				 */
6970Sstevel@tonic-gate 				addenv (&envp, "CHARSET",
6980Sstevel@tonic-gate 					(csp? strtok(csp, "=") : chset)
6990Sstevel@tonic-gate 				);
7000Sstevel@tonic-gate 			}
7010Sstevel@tonic-gate 		}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		if (request->fast)
7040Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->fast);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		/*
7071676Sjpk 		 * Add the sensitivity label to the environment for
7081676Sjpk 		 * banner page and header/footer processing
7091676Sjpk 		 */
7101676Sjpk 
7111676Sjpk 		if (is_system_labeled() && request->secure->slabel != NULL)
7121676Sjpk 			addenv(&envp, "SLABEL", request->secure->slabel);
7131676Sjpk 
7141676Sjpk 		/*
7150Sstevel@tonic-gate 		 * Add the system name to the user name (ala system!user)
7160Sstevel@tonic-gate 		 * unless it is already there. RFS users may have trouble
7170Sstevel@tonic-gate 		 * here, sorry!
7180Sstevel@tonic-gate 		 */
7190Sstevel@tonic-gate 		cp = strchr(request->secure->user, '@');
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 		allTraysWithForm(printer, request->form);
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 		/*
7240Sstevel@tonic-gate 		 * Fix for 4137389
7250Sstevel@tonic-gate 		 * Remove double quotes from title string.
7260Sstevel@tonic-gate 		 */
7270Sstevel@tonic-gate 		fr_flg = 1;
7280Sstevel@tonic-gate 		clean_title = strdup(NB(request->request->title));
7290Sstevel@tonic-gate 		if (clean_title == NULL) {
7300Sstevel@tonic-gate 			/*
7310Sstevel@tonic-gate 			 * strdup failed. We're probably hosed
7320Sstevel@tonic-gate 			 * but try setting clean_title
7330Sstevel@tonic-gate 			 * to original title and continuing.
7340Sstevel@tonic-gate 			 */
7350Sstevel@tonic-gate 			clean_title = NB(request->request->title);
7360Sstevel@tonic-gate 			fr_flg = 0;
7370Sstevel@tonic-gate 		} else if (strcmp(clean_title, "") != 0) {
7380Sstevel@tonic-gate 			char *ct_p;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 			for (ct_p = clean_title; *ct_p != NULL; ct_p++) {
7410Sstevel@tonic-gate 				if (*ct_p == '"')
7420Sstevel@tonic-gate 					*ct_p = ' ';
7430Sstevel@tonic-gate 			}
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces,
7470Sstevel@tonic-gate 					printer->printer->name);
74810460SSonam.Gupta@Sun.COM 		/*
74910460SSonam.Gupta@Sun.COM 		 * Read the options field of the request
75010460SSonam.Gupta@Sun.COM 		 * In case of remote lpd request
75110460SSonam.Gupta@Sun.COM 		 * the options field will have
75210460SSonam.Gupta@Sun.COM 		 * job-id-requested. This is the
75310460SSonam.Gupta@Sun.COM 		 * id sent by the client
75410460SSonam.Gupta@Sun.COM 		 */
75510460SSonam.Gupta@Sun.COM 		if (request->request->options != NULL) {
75610460SSonam.Gupta@Sun.COM 			char *options = NULL, *temp = NULL;
75710460SSonam.Gupta@Sun.COM 			options = temp = strdup(request->request->options);
75810460SSonam.Gupta@Sun.COM 
75910460SSonam.Gupta@Sun.COM 			/*
76010460SSonam.Gupta@Sun.COM 			 * Search for job-id-requested in
76110460SSonam.Gupta@Sun.COM 			 * options string
76210460SSonam.Gupta@Sun.COM 			 */
76310460SSonam.Gupta@Sun.COM 			options = strstr(options, "job-id-requested");
76410460SSonam.Gupta@Sun.COM 			if (options != NULL) {
76510460SSonam.Gupta@Sun.COM 				/*
76610460SSonam.Gupta@Sun.COM 				 * Extract the ridno from the string
76710460SSonam.Gupta@Sun.COM 				 * job-id-requested=xxx
76810460SSonam.Gupta@Sun.COM 				 * In this case ridno = xxx
76910460SSonam.Gupta@Sun.COM 				 */
77010460SSonam.Gupta@Sun.COM 				if (STRNEQU(options, "job-id-requested=", 17)) {
77110460SSonam.Gupta@Sun.COM 					ridno = strdup(options + 17);
772*12248SSonam.Gupta@Sun.COM 					tmprid = strstr(ridno, " ");
773*12248SSonam.Gupta@Sun.COM 					if (ridno != NULL) {
77410460SSonam.Gupta@Sun.COM 						/*
77510460SSonam.Gupta@Sun.COM 						 * Read job-id-requested
77610460SSonam.Gupta@Sun.COM 						 * successfully
77710460SSonam.Gupta@Sun.COM 						 */
778*12248SSonam.Gupta@Sun.COM 						tmprid = strstr(ridno, " ");
779*12248SSonam.Gupta@Sun.COM 						if (tmprid != NULL)
780*12248SSonam.Gupta@Sun.COM 							*tmprid = '\0';
781*12248SSonam.Gupta@Sun.COM 
78210460SSonam.Gupta@Sun.COM 						setid = 0;
783*12248SSonam.Gupta@Sun.COM 					} else
78410460SSonam.Gupta@Sun.COM 						/*
78510460SSonam.Gupta@Sun.COM 						 * could not read
78610460SSonam.Gupta@Sun.COM 						 * ridno from the string
78710460SSonam.Gupta@Sun.COM 						 * job-id-requested=xxx
78810460SSonam.Gupta@Sun.COM 						 */
78910460SSonam.Gupta@Sun.COM 						setid = 1;
79010460SSonam.Gupta@Sun.COM 				} else
79110460SSonam.Gupta@Sun.COM 					/*
79210460SSonam.Gupta@Sun.COM 					 * could not read
79310460SSonam.Gupta@Sun.COM 					 * ridno from the string
79410460SSonam.Gupta@Sun.COM 					 * job-id-requested=xxx
79510460SSonam.Gupta@Sun.COM 					 */
79610460SSonam.Gupta@Sun.COM 					setid = 1;
79710460SSonam.Gupta@Sun.COM 			} else
79810460SSonam.Gupta@Sun.COM 				/*
79910460SSonam.Gupta@Sun.COM 				 * No job-id-requested in
80010460SSonam.Gupta@Sun.COM 				 * request options
80110460SSonam.Gupta@Sun.COM 				 */
80210460SSonam.Gupta@Sun.COM 				setid = 1;
80310460SSonam.Gupta@Sun.COM 
80410460SSonam.Gupta@Sun.COM 			if (temp != NULL)
80510460SSonam.Gupta@Sun.COM 				free(temp);
80610460SSonam.Gupta@Sun.COM 
80710460SSonam.Gupta@Sun.COM 		} else
80810460SSonam.Gupta@Sun.COM 			/*
80910460SSonam.Gupta@Sun.COM 			 * options field in request structure
81010460SSonam.Gupta@Sun.COM 			 * not set
81110460SSonam.Gupta@Sun.COM 			 */
81210460SSonam.Gupta@Sun.COM 			setid = 1;
81310460SSonam.Gupta@Sun.COM 
81410460SSonam.Gupta@Sun.COM 
81510460SSonam.Gupta@Sun.COM 		/*
81610460SSonam.Gupta@Sun.COM 		 * setid = 1 means the job-id-requested attribute
81710460SSonam.Gupta@Sun.COM 		 * is not set so read the request->secure->req_id
81810460SSonam.Gupta@Sun.COM 		 */
81910460SSonam.Gupta@Sun.COM 		if (setid)
82010460SSonam.Gupta@Sun.COM 			av[ac++] = arg_string(TRUSTED, "%s",
82110460SSonam.Gupta@Sun.COM 			    request->secure->req_id);
82210460SSonam.Gupta@Sun.COM 		else {
82310460SSonam.Gupta@Sun.COM 			/*
82410460SSonam.Gupta@Sun.COM 			 * From request->secure->req_id extract the
82510460SSonam.Gupta@Sun.COM 			 * printer-name.
82610460SSonam.Gupta@Sun.COM 			 * request->secure->req_id = <printer-name>-<req_id>
82710460SSonam.Gupta@Sun.COM 			 * The final req-id will be
82810460SSonam.Gupta@Sun.COM 			 * <printer-name>-<ridno>
82910460SSonam.Gupta@Sun.COM 			 */
83010460SSonam.Gupta@Sun.COM 			char *r1 = NULL, *r2 = NULL, *tmp = NULL;
83110460SSonam.Gupta@Sun.COM 			r1 = r2 = tmp = strdup(request->secure->req_id);
83210460SSonam.Gupta@Sun.COM 			r2 = strrchr(r1, '-');
83310460SSonam.Gupta@Sun.COM 			if (r2 != NULL) {
83410460SSonam.Gupta@Sun.COM 				char *r3 = NULL;
83510460SSonam.Gupta@Sun.COM 				int lr1 = strlen(r1);
83610460SSonam.Gupta@Sun.COM 				int lr2 = strlen(r2);
83710460SSonam.Gupta@Sun.COM 				r1[lr1 - lr2 + 1] = '\0';
83810460SSonam.Gupta@Sun.COM 
83910460SSonam.Gupta@Sun.COM 				/*
84010460SSonam.Gupta@Sun.COM 				 * Now r1 = <printer-name>-
84110460SSonam.Gupta@Sun.COM 				 */
84210460SSonam.Gupta@Sun.COM 				lr1 = strlen(r1);
84310460SSonam.Gupta@Sun.COM 				lr2 = strlen(ridno);
84410460SSonam.Gupta@Sun.COM 
84510460SSonam.Gupta@Sun.COM 				r3 = (char *)malloc(lr1+lr2+1);
84610460SSonam.Gupta@Sun.COM 				if (r3 != NULL) {
84710460SSonam.Gupta@Sun.COM 					strcpy(r3, r1);
84810460SSonam.Gupta@Sun.COM 					strcat(r3, ridno);
84910460SSonam.Gupta@Sun.COM 					/*
85010460SSonam.Gupta@Sun.COM 					 * Here r3 = <printer-name>-<ridno>
85110460SSonam.Gupta@Sun.COM 					 */
85210460SSonam.Gupta@Sun.COM 					av[ac++] = arg_string(TRUSTED,
85310460SSonam.Gupta@Sun.COM 					    "%s", r3);
85410460SSonam.Gupta@Sun.COM 					free(r3);
85510460SSonam.Gupta@Sun.COM 				} else
85610460SSonam.Gupta@Sun.COM 					av[ac++] = arg_string(TRUSTED, "%s",
85710460SSonam.Gupta@Sun.COM 					    request->secure->req_id);
85810460SSonam.Gupta@Sun.COM 
85910460SSonam.Gupta@Sun.COM 			} else
86010460SSonam.Gupta@Sun.COM 				av[ac++] = arg_string(TRUSTED, "%s",
86110460SSonam.Gupta@Sun.COM 				    request->secure->req_id);
86210460SSonam.Gupta@Sun.COM 
86310460SSonam.Gupta@Sun.COM 			if (tmp != NULL)
86410460SSonam.Gupta@Sun.COM 				free(tmp);
86510460SSonam.Gupta@Sun.COM 
86610460SSonam.Gupta@Sun.COM 			if (ridno != NULL)
86710460SSonam.Gupta@Sun.COM 				free(ridno);
86810460SSonam.Gupta@Sun.COM 		}
86910460SSonam.Gupta@Sun.COM 
8703125Sjacobs 		av[ac++] = arg_string(UNTRUSTED, "%s", request->request->user);
8710Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", clean_title);
8720Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%d", request->copies);
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		if (fr_flg)
8750Sstevel@tonic-gate 			free (clean_title);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 		sep = "";
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 		/*
8800Sstevel@tonic-gate 		 * Do the administrator defined key=value pair options
8810Sstevel@tonic-gate 		 */
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 		argbuf[0] = '\0';
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 		if (printer->printer->options) {
8860Sstevel@tonic-gate 			char **tmp = printer->printer->options;
8870Sstevel@tonic-gate 			while(*tmp != NULL) {
8880Sstevel@tonic-gate 				STRLCAT(argbuf, sep, sizeof (argbuf));
8890Sstevel@tonic-gate 				sep = " ";
8900Sstevel@tonic-gate 				STRLCAT(argbuf, *tmp++, sizeof (argbuf));
8910Sstevel@tonic-gate 			}
8920Sstevel@tonic-gate 		}
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		/*
8950Sstevel@tonic-gate 		 * Do the administrator defined ``stty'' stuff before
8960Sstevel@tonic-gate 		 * the user's -o options, to allow the user to override.
8970Sstevel@tonic-gate 		 */
8980Sstevel@tonic-gate 		if (printer->printer->stty) {
8990Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
9000Sstevel@tonic-gate 			sep = " ";
9010Sstevel@tonic-gate 			STRLCAT (argbuf, "stty='", sizeof (argbuf));
9020Sstevel@tonic-gate 			STRLCAT (argbuf, printer->printer->stty,
9030Sstevel@tonic-gate 			    sizeof (argbuf));
9040Sstevel@tonic-gate 			STRLCAT (argbuf, "'", sizeof (argbuf));
9050Sstevel@tonic-gate 		}
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 		/*
9080Sstevel@tonic-gate 		 * Do all of the user's options except the cpi/lpi/etc.
9090Sstevel@tonic-gate 		 * stuff, which is done separately.
9100Sstevel@tonic-gate 		 */
9110Sstevel@tonic-gate 		if (request->request->options) {
9120Sstevel@tonic-gate 			listp = dashos(request->request->options);
9130Sstevel@tonic-gate 			while (*listp) {
9140Sstevel@tonic-gate 				if (
9150Sstevel@tonic-gate 					!STRNEQU(*listp, "cpi=", 4)
9160Sstevel@tonic-gate 				     && !STRNEQU(*listp, "lpi=", 4)
9170Sstevel@tonic-gate 				     && !STRNEQU(*listp, "width=", 6)
9180Sstevel@tonic-gate 				     && !STRNEQU(*listp, "length=", 7)
9190Sstevel@tonic-gate 				) {
9200Sstevel@tonic-gate 					STRLCAT (argbuf, sep, sizeof (argbuf));
9210Sstevel@tonic-gate 					sep = " ";
9220Sstevel@tonic-gate 					STRLCAT (argbuf, *listp,
9230Sstevel@tonic-gate 					    sizeof (argbuf));
9240Sstevel@tonic-gate 				}
9250Sstevel@tonic-gate 				listp++;
9260Sstevel@tonic-gate 			}
9270Sstevel@tonic-gate 		}
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 		/*
9300Sstevel@tonic-gate 		 * The "pickfilter()" routine (from "validate()")
9310Sstevel@tonic-gate 		 * stored the cpi/lpi/etc. stuff that should be
9320Sstevel@tonic-gate 		 * used for this request. It chose form over user,
9330Sstevel@tonic-gate 		 * and user over printer.
9340Sstevel@tonic-gate 		 */
9350Sstevel@tonic-gate 		if (request->cpi) {
9360Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
9370Sstevel@tonic-gate 			sep = " ";
9380Sstevel@tonic-gate 			STRLCAT (argbuf, "cpi=", sizeof (argbuf));
9390Sstevel@tonic-gate 			STRLCAT (argbuf, request->cpi, sizeof (argbuf));
9400Sstevel@tonic-gate 		}
9410Sstevel@tonic-gate 		if (request->lpi) {
9420Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
9430Sstevel@tonic-gate 			sep = " ";
9440Sstevel@tonic-gate 			STRLCAT (argbuf, "lpi=", sizeof (argbuf));
9450Sstevel@tonic-gate 			STRLCAT (argbuf, request->lpi, sizeof (argbuf));
9460Sstevel@tonic-gate 		}
9470Sstevel@tonic-gate 		if (request->pwid) {
9480Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
9490Sstevel@tonic-gate 			sep = " ";
9500Sstevel@tonic-gate 			STRLCAT (argbuf, "width=", sizeof (argbuf));
9510Sstevel@tonic-gate 			STRLCAT (argbuf, request->pwid, sizeof (argbuf));
9520Sstevel@tonic-gate 		}
9530Sstevel@tonic-gate 		if (request->plen) {
9540Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
9550Sstevel@tonic-gate 			sep = " ";
9560Sstevel@tonic-gate 			STRLCAT (argbuf, "length=", sizeof (argbuf));
9570Sstevel@tonic-gate 			STRLCAT (argbuf, request->plen, sizeof (argbuf));
9580Sstevel@tonic-gate 		}
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 		/*
9610Sstevel@tonic-gate 		 * Do the ``raw'' bit last, to ensure it gets
9620Sstevel@tonic-gate 		 * done. If the user doesn't want this, then he or
9630Sstevel@tonic-gate 		 * she can do the correct thing using -o stty=
9640Sstevel@tonic-gate 		 * and leaving out the -r option.
9650Sstevel@tonic-gate 		 */
9660Sstevel@tonic-gate 		if (request->request->actions & ACT_RAW) {
9670Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
9680Sstevel@tonic-gate 			sep = " ";
9690Sstevel@tonic-gate 			STRLCAT (argbuf, "stty=-opost", sizeof (argbuf));
9700Sstevel@tonic-gate 		}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		/* the "options" */
9740Sstevel@tonic-gate 		av[ac++] = arg_string(UNTRUSTED, "%s", argbuf);
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 		for (listp = file_list; *listp; listp++)
9770Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 		(void)chfiles (file_list, procuid, procgid);
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 		break;
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	case EX_SLOWF:
9850Sstevel@tonic-gate 		if (request->slow)
9860Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->slow);
9870Sstevel@tonic-gate 
98811378SSonam.Gupta@Sun.COM 		procuid = request->secure->uid;
98911378SSonam.Gupta@Sun.COM 		procgid = request->secure->gid;
99011378SSonam.Gupta@Sun.COM 
9910Sstevel@tonic-gate 		cp = _alloc_files(
9920Sstevel@tonic-gate 			lenlist(request->request->file_list),
9930Sstevel@tonic-gate 			getreqno(request->secure->req_id),
9943125Sjacobs 			procuid, procgid);
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter);
9973204Sjacobs 		av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_Temp, cp);
9980Sstevel@tonic-gate 		for (listp = request->request->file_list; *listp; listp++)
9990Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 		(void)chfiles (request->request->file_list, procuid, procgid);
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
10040Sstevel@tonic-gate 		/*
10050Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
10060Sstevel@tonic-gate 		 * pass the file's pathname to the slow-filters in an
10070Sstevel@tonic-gate 		 * environment variable. Note: this file is created when
10080Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
10090Sstevel@tonic-gate 		 */
10100Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
10110Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
10123125Sjacobs 		path = makepath(Lp_Temp, tmpName, (char *)0);
10130Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
10140Sstevel@tonic-gate 		{
10150Sstevel@tonic-gate 			/*
10160Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
10170Sstevel@tonic-gate 			 * set the environment variable
10180Sstevel@tonic-gate 			 */
10190Sstevel@tonic-gate 			addenv(&envp, "ATTRPATH", path);
10200Sstevel@tonic-gate 		}
10210Sstevel@tonic-gate 		Free(path);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 		/*
10250Sstevel@tonic-gate 		 * now set environment variable for the printer's PostScript
10260Sstevel@tonic-gate 		 * Printer Description (PPD) file, this is used by the filter
10270Sstevel@tonic-gate 		 * when forming the print data for this printer.
10280Sstevel@tonic-gate 		 */
10290Sstevel@tonic-gate 		if ((request->printer != NULL) &&
10300Sstevel@tonic-gate 		    (request->printer->printer != NULL) &&
10310Sstevel@tonic-gate 		    (request->printer->printer->name != NULL))
10320Sstevel@tonic-gate 		{
10330Sstevel@tonic-gate 			snprintf(tmpName, sizeof (tmpName), "%s.ppd",
10340Sstevel@tonic-gate 				request->printer->printer->name);
10350Sstevel@tonic-gate 			path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
10360Sstevel@tonic-gate 			if ((path != NULL) && (stat(path, &tmpBuf) == 0))
10370Sstevel@tonic-gate 			{
10380Sstevel@tonic-gate 				addenv(&envp, "PPD", path);
10390Sstevel@tonic-gate 			}
10400Sstevel@tonic-gate 			Free(path);
10410Sstevel@tonic-gate 		}
10420Sstevel@tonic-gate #endif
10430Sstevel@tonic-gate 		break;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	case EX_ALERT:
10460Sstevel@tonic-gate 		procuid = Lp_Uid;
10470Sstevel@tonic-gate 		procgid = Lp_Gid;
10480Sstevel@tonic-gate 		(void)Chown (printer->alert->msgfile, procuid, procgid);
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
10510Sstevel@tonic-gate 				printer->printer->name, ALERTSHFILE);
10520Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 		break;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	case EX_PALERT:
10570Sstevel@tonic-gate 		procuid = Lp_Uid;
10580Sstevel@tonic-gate 		procgid = Lp_Gid;
10590Sstevel@tonic-gate 		(void)Chown (pwheel->alert->msgfile, procuid, procgid);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels,
10620Sstevel@tonic-gate 				pwheel->pwheel->name, ALERTSHFILE);
10630Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 		break;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	case EX_FALERT:
10680Sstevel@tonic-gate 		procuid = Lp_Uid;
10690Sstevel@tonic-gate 		procgid = Lp_Gid;
10700Sstevel@tonic-gate 		(void)Chown (form->alert->msgfile, procuid, procgid);
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
10730Sstevel@tonic-gate 				form->form->name, ALERTSHFILE);
10740Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 		break;
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
10790Sstevel@tonic-gate 		procuid = Lp_Uid;
10800Sstevel@tonic-gate 		procgid = Lp_Gid;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults);
10830Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", form->form->name);
10840Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
10850Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
10860Sstevel@tonic-gate 				form->form->name, FORMMESSAGEFILE);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 		break;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
10910Sstevel@tonic-gate 		procuid = Lp_Uid;
10920Sstevel@tonic-gate 		procgid = Lp_Gid;
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults);
10950Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow);
10960Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
10970Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
10980Sstevel@tonic-gate 				printerName, FAULTMESSAGEFILE);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 		break;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	case EX_NOTIFY:
11030Sstevel@tonic-gate 		if (request->request->alert) {
110411378SSonam.Gupta@Sun.COM 			procuid = request->secure->uid;
110511378SSonam.Gupta@Sun.COM 			procgid = request->secure->gid;
110611378SSonam.Gupta@Sun.COM 
11070Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s",
11080Sstevel@tonic-gate 					request->request->alert);
11090Sstevel@tonic-gate 		} else {
11103125Sjacobs 			char *user = strdup(request->request->user);
11110Sstevel@tonic-gate 			clean_string(user);
11121676Sjpk 			slabel = request->secure->slabel;
11130Sstevel@tonic-gate 
11143125Sjacobs 			if (request->request->actions & ACT_WRITE) {
11150Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINWRITE);
11160Sstevel@tonic-gate 				snprintf(argbuf, sizeof (argbuf),
11170Sstevel@tonic-gate 					"%s %s || %s %s",
11180Sstevel@tonic-gate 					BINWRITE, user,
11190Sstevel@tonic-gate 					BINMAIL, user
11200Sstevel@tonic-gate 				);
11210Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "/bin/sh");
11220Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "-c");
11230Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", argbuf);
11241676Sjpk 			} else if ((getzoneid() == GLOBAL_ZONEID) &&
11251676Sjpk 				   is_system_labeled() && (slabel != NULL)) {
11261676Sjpk 				/*
11271676Sjpk 				 * If in the global zone and the system is
11281676Sjpk 				 * labeled, mail is handled via a local
11291676Sjpk 				 * labeled zone that is the same label as
11301676Sjpk 				 * the request.
11311676Sjpk 				 */
11321676Sjpk 				if ((mail_zonename =
11331676Sjpk 				    get_labeled_zonename(slabel)) ==
11341676Sjpk 				    (char *)-1) {
11351676Sjpk 					/*
11361676Sjpk 					 * Cannot find labeled zone, just
11371676Sjpk 					 * return 0.
11381676Sjpk 					 */
11391676Sjpk 					return(0);
11401676Sjpk 				}
11411676Sjpk 			}
11421676Sjpk 			if (mail_zonename == NULL) {
11431676Sjpk 				procuid = Lp_Uid;
11441676Sjpk 				procgid = Lp_Gid;
11450Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINMAIL);
11460Sstevel@tonic-gate 				av[ac++] = arg_string(UNTRUSTED, "%s", user);
11471676Sjpk 			} else {
11481676Sjpk 				procuid = getuid();
11491676Sjpk 				procgid = getgid();
11501676Sjpk 				av[ac++] = arg_string(TRUSTED, "%s",
11511676Sjpk 				    "/usr/sbin/zlogin");
11521676Sjpk 				av[ac++] = arg_string(TRUSTED, "%s",
11531676Sjpk 				    mail_zonename);
11541676Sjpk 				av[ac++] = arg_string(TRUSTED, "%s",
11551676Sjpk 				    BINMAIL);
11561676Sjpk 				av[ac++] = arg_string(UNTRUSTED, "%s",
11571676Sjpk 				    user);
11581676Sjpk 				Free(mail_zonename);
11590Sstevel@tonic-gate 			}
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 			free(user);
11620Sstevel@tonic-gate 		}
11630Sstevel@tonic-gate 		break;
11640Sstevel@tonic-gate 	}
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	av[ac++] = NULL;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	Fork2 ();
11690Sstevel@tonic-gate 	/* only the child returns */
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	/*
11720Sstevel@tonic-gate 	 * Correctly set up the supplemental group list
11730Sstevel@tonic-gate 	 * for proper file access (before execl the interface program)
11740Sstevel@tonic-gate 	 */
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	pwp = getpwuid(procuid);
11770Sstevel@tonic-gate 	if (pwp == NULL) {
11780Sstevel@tonic-gate 		note("getpwuid(%d) call failed\n", procuid);
11790Sstevel@tonic-gate 	} else if (initgroups(pwp->pw_name, procgid) < 0) {
11800Sstevel@tonic-gate 		note("initgroups() call failed %d\n", errno);
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	setgid (procgid);
11840Sstevel@tonic-gate 	setuid (procuid);
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	/*
11870Sstevel@tonic-gate 	 * The shell doesn't allow the "trap" builtin to set a trap
11880Sstevel@tonic-gate 	 * for a signal ignored when the shell is started. Thus, don't
11890Sstevel@tonic-gate 	 * turn off signals in the last child!
11900Sstevel@tonic-gate 	 */
11910Sstevel@tonic-gate 
11923125Sjacobs #ifdef DEBUG
11930Sstevel@tonic-gate 	for (i = 0; av[i] != NULL; i++)
11943125Sjacobs 		note("exec(%s): av[%d] = %s", _exec_name(type), i, av[i]);
11951676Sjpk 	for (i = 0; envp[i] != NULL; i++)
11963125Sjacobs 		note("exec(%s): envp[%d] = %s", _exec_name(type), i, envp[i]);
11973125Sjacobs #endif
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	execvpe(av[0], av, envp);
12000Sstevel@tonic-gate 	Done (EXEC_EXIT_NEXEC, errno);
12010Sstevel@tonic-gate 	/*NOTREACHED*/
1202320Sceastha 	return (0);
12030Sstevel@tonic-gate }
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate /**
12060Sstevel@tonic-gate  ** addenv() - ADD A VARIABLE TO THE ENVIRONMENT
12070Sstevel@tonic-gate  **/
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate static void
addenv(char *** envp,char * name,char * value)12100Sstevel@tonic-gate addenv(char ***envp, char *name, char *value)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	register char *		cp;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	if ((name == NULL) || (value == NULL))
12150Sstevel@tonic-gate 		return;
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	if ((cp = makestr(name, "=", value, (char *)0)))
12180Sstevel@tonic-gate 		addlist(envp, cp);
12190Sstevel@tonic-gate 	return;
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate /**
12230Sstevel@tonic-gate  ** Fork1() - FORK FIRST CHILD, SET UP CONNECTION TO IT
12240Sstevel@tonic-gate  **/
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate static int
Fork1(EXEC * ep)12270Sstevel@tonic-gate Fork1(EXEC *ep)
12280Sstevel@tonic-gate {
12290Sstevel@tonic-gate 	int			pid;
12300Sstevel@tonic-gate 	int			fds[2];
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	if (pipe(fds) == -1) {
12330Sstevel@tonic-gate 		note("Failed to create pipe for child process (%s).\n", PERROR);
12340Sstevel@tonic-gate 		errno = EAGAIN ;
12350Sstevel@tonic-gate 		return(-1);
12360Sstevel@tonic-gate 	}
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	ep->md = mconnect((char *)0, fds[0], fds[1]);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	switch (pid = fork()) {
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	case -1:
12430Sstevel@tonic-gate 		mdisconnect(ep->md);
12440Sstevel@tonic-gate 		close(fds[0]);
12450Sstevel@tonic-gate 		close(fds[1]);
12460Sstevel@tonic-gate 		ep->md = 0;
12470Sstevel@tonic-gate 		return (-1);
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	case 0:
12500Sstevel@tonic-gate 		ChildMd = mconnect(NULL, fds[1], fds[1]);
12510Sstevel@tonic-gate 		return (0);
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	default:
12540Sstevel@tonic-gate 		mlistenadd(ep->md, POLLIN);
12550Sstevel@tonic-gate 		return (pid);
12560Sstevel@tonic-gate 	}
12570Sstevel@tonic-gate }
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate /**
12600Sstevel@tonic-gate  ** Fork2() - FORK SECOND CHILD AND WAIT FOR IT
12610Sstevel@tonic-gate  **/
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate static void
Fork2(void)12640Sstevel@tonic-gate Fork2(void)
12650Sstevel@tonic-gate {
12660Sstevel@tonic-gate 	switch ((ChildPid = fork())) {
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	case -1:
12690Sstevel@tonic-gate 		Done (EXEC_EXIT_NFORK, errno);
12700Sstevel@tonic-gate 		/*NOTREACHED*/
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	case 0:
12730Sstevel@tonic-gate 		return;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	default:
12760Sstevel@tonic-gate 		/*
12770Sstevel@tonic-gate 		 * Delay calling "ignore_fault_signals()" as long
12780Sstevel@tonic-gate 		 * as possible, to give the child a chance to exec
12790Sstevel@tonic-gate 		 * the interface program and turn on traps.
12800Sstevel@tonic-gate 		 */
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 		cool_heels ();
12830Sstevel@tonic-gate 		/*NOTREACHED*/
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate }
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate /**
12900Sstevel@tonic-gate  ** cool_heels() - WAIT FOR CHILD TO "DIE"
12910Sstevel@tonic-gate  **/
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate static void
cool_heels(void)12940Sstevel@tonic-gate cool_heels(void)
12950Sstevel@tonic-gate {
12960Sstevel@tonic-gate 	int			status;
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	/*
12990Sstevel@tonic-gate 	 * At this point our only job is to wait for the child process.
13000Sstevel@tonic-gate 	 * If we hang out for a bit longer, that's okay.
13010Sstevel@tonic-gate 	 * By delaying before turning off the fault signals,
13020Sstevel@tonic-gate 	 * we increase the chance that the child process has completed
13030Sstevel@tonic-gate 	 * its exec and has turned on the fault traps. Nonetheless,
13040Sstevel@tonic-gate 	 * we can't guarantee a zero chance of missing a fault.
13050Sstevel@tonic-gate 	 * (We don't want to keep trapping the signals because the
13060Sstevel@tonic-gate 	 * interface program is likely to have a better way to handle
13070Sstevel@tonic-gate 	 * them; this process provides only rudimentary handling.)
13080Sstevel@tonic-gate 	 *
13090Sstevel@tonic-gate 	 * Note that on a very busy system, or with a very fast interface
13100Sstevel@tonic-gate 	 * program, the tables could be turned: Our sleep below (coupled
13110Sstevel@tonic-gate 	 * with a delay in the kernel scheduling us) may cause us to
13120Sstevel@tonic-gate 	 * detect the fault instead of the interface program.
13130Sstevel@tonic-gate 	 *
13140Sstevel@tonic-gate 	 * What we need is a way to synchronize with the child process.
13150Sstevel@tonic-gate 	 */
13160Sstevel@tonic-gate 	sleep (1);
13170Sstevel@tonic-gate 	ignore_fault_signals ();
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	WaitedChildPid = 0;
13200Sstevel@tonic-gate 	while ((WaitedChildPid = wait(&status)) != ChildPid)
13210Sstevel@tonic-gate 		;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	if (
13240Sstevel@tonic-gate 		EXITED(status) > EXEC_EXIT_USER
13250Sstevel@tonic-gate 	     && EXITED(status) != EXEC_EXIT_FAULT
13260Sstevel@tonic-gate 	)
13270Sstevel@tonic-gate 		Done (EXEC_EXIT_EXIT, EXITED(status));
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	done (status, 0);	/* Don't use Done() */
13300Sstevel@tonic-gate 	/*NOTREACHED*/
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate /**
13350Sstevel@tonic-gate  ** trap_fault_signals() - TRAP SIGNALS THAT CAN OCCUR ON PRINTER FAULT
13360Sstevel@tonic-gate  ** ignore_fault_signals() - IGNORE SAME
13370Sstevel@tonic-gate  **/
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate static void
trap_fault_signals(void)13400Sstevel@tonic-gate trap_fault_signals(void)
13410Sstevel@tonic-gate {
13420Sstevel@tonic-gate 	signal (SIGHUP, sigtrap);
13430Sstevel@tonic-gate 	signal (SIGINT, sigtrap);
13440Sstevel@tonic-gate 	signal (SIGQUIT, sigtrap);
13450Sstevel@tonic-gate 	signal (SIGPIPE, sigtrap);
13460Sstevel@tonic-gate 	return;
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate static void
ignore_fault_signals(void)13500Sstevel@tonic-gate ignore_fault_signals(void)
13510Sstevel@tonic-gate {
13520Sstevel@tonic-gate 	signal (SIGHUP, SIG_IGN);
13530Sstevel@tonic-gate 	signal (SIGINT, SIG_IGN);
13540Sstevel@tonic-gate 	signal (SIGQUIT, SIG_IGN);
13550Sstevel@tonic-gate 	signal (SIGPIPE, SIG_IGN);
13560Sstevel@tonic-gate 	return;
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate /**
13600Sstevel@tonic-gate  ** sigtrap() - TRAP VARIOUS SIGNALS
13610Sstevel@tonic-gate  **/
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate static void
sigtrap(int sig)13640Sstevel@tonic-gate sigtrap(int sig)
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate 	signal (sig, SIG_IGN);
13670Sstevel@tonic-gate 	switch (sig) {
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	case SIGHUP:
13700Sstevel@tonic-gate 		Done (EXEC_EXIT_HUP, 0);
13710Sstevel@tonic-gate 		/*NOTREACHED*/
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	case SIGQUIT:
13740Sstevel@tonic-gate 	case SIGINT:
13750Sstevel@tonic-gate 		Done (EXEC_EXIT_INTR, 0);
13760Sstevel@tonic-gate 		/*NOTREACHED*/
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	case SIGPIPE:
13790Sstevel@tonic-gate 		Done (EXEC_EXIT_PIPE, 0);
13800Sstevel@tonic-gate 		/*NOTREACHED*/
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	case SIGTERM:
13830Sstevel@tonic-gate 		/*
13840Sstevel@tonic-gate 		 * If we were killed with SIGTERM, it should have been
13850Sstevel@tonic-gate 		 * via the Spooler who should have killed the entire
13860Sstevel@tonic-gate 		 * process group. We have to wait for the children,
13870Sstevel@tonic-gate 		 * since we're their parent, but WE MAY HAVE WAITED
13880Sstevel@tonic-gate 		 * FOR THEM ALREADY (in cool_heels()).
13890Sstevel@tonic-gate 		 */
13900Sstevel@tonic-gate 		if (ChildPid != WaitedChildPid) {
13910Sstevel@tonic-gate 			register int		cpid;
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 			while (
13940Sstevel@tonic-gate 				(cpid = wait((int *)0)) != ChildPid
13950Sstevel@tonic-gate 			     && (cpid != -1 || errno != ECHILD)
13960Sstevel@tonic-gate 			)
13970Sstevel@tonic-gate 				;
13980Sstevel@tonic-gate 		}
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 		/*
14010Sstevel@tonic-gate 		 * We can't rely on getting SIGTERM back in the wait()
14020Sstevel@tonic-gate 		 * above, because, for instance, some shells trap SIGTERM
14030Sstevel@tonic-gate 		 * and exit instead. Thus we force it.
14040Sstevel@tonic-gate 		 */
14050Sstevel@tonic-gate 		done (SIGTERM, 0);	/* Don't use Done() */
14060Sstevel@tonic-gate 		/*NOTREACHED*/
14070Sstevel@tonic-gate 	}
14080Sstevel@tonic-gate }
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate /**
14110Sstevel@tonic-gate  ** done() - TELL SPOOLER THIS CHILD IS DONE
14120Sstevel@tonic-gate  **/
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate static void
done(int status,int err)14150Sstevel@tonic-gate done(int status, int err)
14160Sstevel@tonic-gate {
14170Sstevel@tonic-gate 	if (do_undial)
14180Sstevel@tonic-gate 		undial (1);
14190Sstevel@tonic-gate 
14203125Sjacobs 	mputm (ChildMd, S_CHILD_DONE, key, status, err);
14210Sstevel@tonic-gate 	mdisconnect (ChildMd);
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	exit (0);
14240Sstevel@tonic-gate 	/*NOTREACHED*/
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate /**
14280Sstevel@tonic-gate  ** child_mallocfail()
14290Sstevel@tonic-gate  **/
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate static void
child_mallocfail(void)14320Sstevel@tonic-gate child_mallocfail(void)
14330Sstevel@tonic-gate {
14340Sstevel@tonic-gate 	Done (EXEC_EXIT_NOMEM, ENOMEM);
14350Sstevel@tonic-gate }
1436