/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <pwd.h>
#include <zone.h>
#if defined PS_FAULTED
#endif /* PS_FAULTED */
#include <dial.h>
#include <stdlib.h>
#include "limits.h"
#include "stdarg.h"
#include "wait.h"
#include "dial.h"
#include "lpsched.h"
#include <syslog.h>
return (-1); \
}
static int ChildPid;
static int WaitedChildPid;
static int do_undial;
static long key;
static void sigtrap ( int );
static void done ( int , int );
static void cool_heels ( void );
static void trap_fault_signals ( void );
static void ignore_fault_signals ( void );
static void child_mallocfail ( void );
static void Fork2 ( void );
static void
relock(void)
{
struct flock l;
l.l_whence = 1;
l.l_start = 0;
l.l_len = 0;
return;
}
{
static char *_names[] = {
"", "EX_INTERF", "EX_SLOWF", "EX_ALERT", "EX_FALERT", "EX_PALERT",
return ("BAD_EXEC_TYPE");
else
}
/*
* This function replaces characters in a string that might be used
* to exploit a security hole. Replace command seperators (`, &, ;, |, ^),
* output redirection (>, |), variable expansion ($), and character
* escape (\).
*
* Bugid 4141687
* Add ( ) < * ? [
* Bugid 4139071
* Remove \
*/
{
char *cp;
cp++;
continue;
}
if (len == 1 &&
(wc == L'[')))
*cp = '_';
}
}
/* PRINTFLIKE2 */
static char *
{
/*
* If the string contains data from an untrusted origin (user supplied),
* clean it up in case one of our progeny is a shell script and isn't
* careful about checking its input.
*/
}
static const char *
{
char *s;
s = si;
if (cnt > 0) {
*s++ = *s1++;
cnt--;
} else
s1++;
}
*s++ = '/';
cnt--;
}
*s++ = *s2++;
cnt--;
}
*s = '\0';
}
/*
* Similiar to execvp(), execpt you can supply an environment and we always
* current environment, not the environment in the argument list.
*/
static int
{
char *path;
int i;
const char *cp;
int eacces = 0;
if (*name == '\0') {
return (-1);
}
do {
/*
* 4025035 and 4038378
* if a filename begins with a "-" prepend "./" so that
* the shell can't interpret it as an option
*/
if (*fname == '-') {
return (-1);
}
fname[0] = '.';
}
switch (errno) {
case ENOEXEC:
newargs[0] = "sh";
if (i >= 254) {
return (-1);
}
}
return (-1);
case ETXTBSY:
if (++etxtbsy > 5)
return (-1);
goto retry;
case EACCES:
++eacces;
break;
case ENOMEM:
case E2BIG:
case EFAULT:
return (-1);
}
} while (cp);
if (eacces)
return (-1);
}
/**
** exec() - FORK AND EXEC CHILD PROCESS
**/
/*VARARGS1*/
int
{
int i;
int procuid;
int procgid;
int ret;
int fr_flg;
char *cp;
char *infile;
char *outfile;
char *errfile;
char *sep;
char **listp;
char **file_list;
char *printerName;
char *printerNameToShow;
char *clean_title;
#ifdef LP_USE_PAPI_ATTR
#endif
int ac = 0;
switch (type) {
case EX_INTERF:
break;
case EX_FAULT_MESSAGE:
return(0);
}
break;
case EX_SLOWF:
break;
case EX_NOTIFY:
return (-1);
}
break;
case EX_ALERT:
return(-1);
}
break;
case EX_PALERT:
break;
case EX_FORM_MESSAGE:
/*FALLTHRU*/
case EX_FALERT:
break;
default:
return(-1);
}
return(-1);
}
case -1:
relock ();
return(-1);
case 0:
/*
* We want to be able to tell our parent how we died.
*/
break;
default:
switch(type) {
case EX_INTERF:
break;
case EX_NOTIFY:
break;
case EX_SLOWF:
break;
}
return(0);
}
for (i = 0; i < NSIG; i++)
closelog();
for (i = 0; i < OpenMax; i++)
Close (i);
setpgrp();
/* Set a default path */
/* copy locale related variables */
#if defined(DEBUG)
#endif
/*
* Open the standard input, standard output, and standard error.
*/
switch (type) {
case EX_SLOWF:
case EX_INTERF:
/*
* stderr: req#
*/
infile = 0;
outfile = 0;
break;
case EX_NOTIFY:
/*
* stdin: req#
*/
outfile = 0;
errfile = 0;
break;
case EX_ALERT:
case EX_FALERT:
case EX_PALERT:
case EX_FAULT_MESSAGE:
case EX_FORM_MESSAGE:
/*
*/
infile = 0;
outfile = 0;
errfile = 0;
break;
}
if (infile) {
} else {
}
if (outfile) {
} else {
/*
* If EX_INTERF, this is still needed to cause the
* standard error channel to be #2.
*/
}
if (errfile) {
} else {
}
switch (type) {
case EX_INTERF:
/*
* Opening a ``port'' can be dangerous to our health:
*
* - Hangups can occur if the line is dropped.
* - The printer may send an interrupt.
* - A FIFO may be closed, generating SIGPIPE.
*
* We catch these so we can complain nicely.
*/
(void)Close (1);
{
if (ret == 0)
do_undial = 1;
}
else
{
do_undial = 0;
/* this is a URI */
}
if (ret != 0)
else {
register int count = 0;
register char * prefix;
"/F",
"-",
(char *)0
);
* sizeof(char *)
);
for (
*listp;
listp++
) {
num,
(char *)0
);
count++;
}
}
#ifdef LP_USE_PAPI_ATTR
/*
* Check if the PAPI job attribute file exists, if it does
* pass the file's pathname to the printer interface script
* in an environment variable. This file is created when
* print jobs are submitted via the PAPI interface.
*/
{
/*
* IPP job attribute file exists for this job so
* set the environment variable
*/
}
/*
* now set environment variable for the printer's PostScript
* Printer Description (PPD) file, this is used by the filter
* when forming the print data for this printer.
*/
{
{
}
}
#endif
if (request->printer_type)
register char * chset = 0;
register char * csp;
if (
)
else if (
)
if (chset) {
csp = search_cslist(
);
/*
* The "strtok()" below wrecks the string
* for future use, but this is a child
* process where it won't be needed again.
*/
);
}
}
/*
* Add the sensitivity label to the environment for
*/
/*
* Add the system name to the user name (ala system!user)
* unless it is already there. RFS users may have trouble
* here, sorry!
*/
/*
* Fix for 4137389
* Remove double quotes from title string.
*/
fr_flg = 1;
if (clean_title == NULL) {
/*
* strdup failed. We're probably hosed
* but try setting clean_title
* to original title and continuing.
*/
fr_flg = 0;
char *ct_p;
if (*ct_p == '"')
*ct_p = ' ';
}
}
/*
* Read the options field of the request
* In case of remote lpd request
* the options field will have
* job-id-requested. This is the
* id sent by the client
*/
/*
* Search for job-id-requested in
* options string
*/
/*
* Extract the ridno from the string
* job-id-requested=xxx
* In this case ridno = xxx
*/
/*
* Read job-id-requested
* successfully
*/
*tmprid = '\0';
setid = 0;
} else
/*
* could not read
* ridno from the string
* job-id-requested=xxx
*/
setid = 1;
} else
/*
* could not read
* ridno from the string
* job-id-requested=xxx
*/
setid = 1;
} else
/*
* No job-id-requested in
* request options
*/
setid = 1;
} else
/*
* options field in request structure
* not set
*/
setid = 1;
/*
* setid = 1 means the job-id-requested attribute
* is not set so read the request->secure->req_id
*/
if (setid)
else {
/*
* From request->secure->req_id extract the
* printer-name.
* request->secure->req_id = <printer-name>-<req_id>
* The final req-id will be
* <printer-name>-<ridno>
*/
/*
* Now r1 = <printer-name>-
*/
/*
* Here r3 = <printer-name>-<ridno>
*/
"%s", r3);
} else
} else
}
if (fr_flg)
free (clean_title);
sep = "";
/*
* Do the administrator defined key=value pair options
*/
argbuf[0] = '\0';
sep = " ";
}
}
/*
* Do the administrator defined ``stty'' stuff before
* the user's -o options, to allow the user to override.
*/
sep = " ";
sizeof (argbuf));
}
/*
* stuff, which is done separately.
*/
while (*listp) {
if (
) {
sep = " ";
sizeof (argbuf));
}
listp++;
}
}
/*
* The "pickfilter()" routine (from "validate()")
* used for this request. It chose form over user,
* and user over printer.
*/
sep = " ";
}
sep = " ";
}
sep = " ";
}
sep = " ";
}
/*
* Do the ``raw'' bit last, to ensure it gets
* done. If the user doesn't want this, then he or
* she can do the correct thing using -o stty=
* and leaving out the -r option.
*/
sep = " ";
}
/* the "options" */
break;
case EX_SLOWF:
cp = _alloc_files(
#ifdef LP_USE_PAPI_ATTR
/*
* Check if the PAPI job attribute file exists, if it does
* pass the file's pathname to the slow-filters in an
* environment variable. Note: this file is created when
* print jobs are submitted via the PAPI interface.
*/
{
/*
* IPP job attribute file exists for this job so
* set the environment variable
*/
}
/*
* now set environment variable for the printer's PostScript
* Printer Description (PPD) file, this is used by the filter
* when forming the print data for this printer.
*/
{
{
}
}
#endif
break;
case EX_ALERT:
break;
case EX_PALERT:
break;
case EX_FALERT:
break;
case EX_FORM_MESSAGE:
break;
case EX_FAULT_MESSAGE:
break;
case EX_NOTIFY:
} else {
"%s %s || %s %s",
);
} else if ((getzoneid() == GLOBAL_ZONEID) &&
/*
* If in the global zone and the system is
* labeled, mail is handled via a local
* labeled zone that is the same label as
* the request.
*/
if ((mail_zonename =
(char *)-1) {
/*
* Cannot find labeled zone, just
* return 0.
*/
return(0);
}
}
if (mail_zonename == NULL) {
} else {
BINMAIL);
user);
}
}
break;
}
Fork2 ();
/* only the child returns */
/*
* Correctly set up the supplemental group list
* for proper file access (before execl the interface program)
*/
}
/*
* The shell doesn't allow the "trap" builtin to set a trap
* for a signal ignored when the shell is started. Thus, don't
* turn off signals in the last child!
*/
#ifdef DEBUG
#endif
/*NOTREACHED*/
return (0);
}
/**
** addenv() - ADD A VARIABLE TO THE ENVIRONMENT
**/
static void
{
register char * cp;
return;
return;
}
/**
** Fork1() - FORK FIRST CHILD, SET UP CONNECTION TO IT
**/
static int
{
int pid;
return(-1);
}
case -1:
return (-1);
case 0:
return (0);
default:
return (pid);
}
}
/**
** Fork2() - FORK SECOND CHILD AND WAIT FOR IT
**/
static void
Fork2(void)
{
case -1:
/*NOTREACHED*/
case 0:
return;
default:
/*
* Delay calling "ignore_fault_signals()" as long
* as possible, to give the child a chance to exec
* the interface program and turn on traps.
*/
cool_heels ();
/*NOTREACHED*/
}
}
/**
** cool_heels() - WAIT FOR CHILD TO "DIE"
**/
static void
cool_heels(void)
{
int status;
/*
* At this point our only job is to wait for the child process.
* If we hang out for a bit longer, that's okay.
* By delaying before turning off the fault signals,
* we increase the chance that the child process has completed
* its exec and has turned on the fault traps. Nonetheless,
* we can't guarantee a zero chance of missing a fault.
* (We don't want to keep trapping the signals because the
* interface program is likely to have a better way to handle
* them; this process provides only rudimentary handling.)
*
* Note that on a very busy system, or with a very fast interface
* program, the tables could be turned: Our sleep below (coupled
* with a delay in the kernel scheduling us) may cause us to
* detect the fault instead of the interface program.
*
* What we need is a way to synchronize with the child process.
*/
sleep (1);
WaitedChildPid = 0;
;
if (
)
/*NOTREACHED*/
}
/**
** trap_fault_signals() - TRAP SIGNALS THAT CAN OCCUR ON PRINTER FAULT
** ignore_fault_signals() - IGNORE SAME
**/
static void
trap_fault_signals(void)
{
return;
}
static void
ignore_fault_signals(void)
{
return;
}
/**
** sigtrap() - TRAP VARIOUS SIGNALS
**/
static void
{
switch (sig) {
case SIGHUP:
Done (EXEC_EXIT_HUP, 0);
/*NOTREACHED*/
case SIGQUIT:
case SIGINT:
Done (EXEC_EXIT_INTR, 0);
/*NOTREACHED*/
case SIGPIPE:
Done (EXEC_EXIT_PIPE, 0);
/*NOTREACHED*/
case SIGTERM:
/*
* If we were killed with SIGTERM, it should have been
* via the Spooler who should have killed the entire
* process group. We have to wait for the children,
* since we're their parent, but WE MAY HAVE WAITED
* FOR THEM ALREADY (in cool_heels()).
*/
if (ChildPid != WaitedChildPid) {
register int cpid;
while (
)
;
}
/*
* We can't rely on getting SIGTERM back in the wait()
* above, because, for instance, some shells trap SIGTERM
* and exit instead. Thus we force it.
*/
/*NOTREACHED*/
}
}
/**
** done() - TELL SPOOLER THIS CHILD IS DONE
**/
static void
{
if (do_undial)
undial (1);
exit (0);
/*NOTREACHED*/
}
/**
** child_mallocfail()
**/
static void
child_mallocfail(void)
{
}