1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.
3*0Sstevel@tonic-gate * All rights reserved.
4*0Sstevel@tonic-gate * Copyright (c) 1993 Eric P. Allman. All rights reserved.
5*0Sstevel@tonic-gate * Copyright (c) 1993
6*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
7*0Sstevel@tonic-gate *
8*0Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
9*0Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
10*0Sstevel@tonic-gate * the sendmail distribution.
11*0Sstevel@tonic-gate *
12*0Sstevel@tonic-gate */
13*0Sstevel@tonic-gate
14*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
15*0Sstevel@tonic-gate
16*0Sstevel@tonic-gate #include <sm/gen.h>
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gate SM_IDSTR(copyright,
19*0Sstevel@tonic-gate "@(#) Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.\n\
20*0Sstevel@tonic-gate All rights reserved.\n\
21*0Sstevel@tonic-gate Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\
22*0Sstevel@tonic-gate Copyright (c) 1993\n\
23*0Sstevel@tonic-gate The Regents of the University of California. All rights reserved.\n")
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gate SM_IDSTR(id, "@(#)$Id: smrsh.c,v 8.65 2004/08/06 18:54:22 ca Exp $")
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate /*
28*0Sstevel@tonic-gate ** SMRSH -- sendmail restricted shell
29*0Sstevel@tonic-gate **
30*0Sstevel@tonic-gate ** This is a patch to get around the prog mailer bugs in most
31*0Sstevel@tonic-gate ** versions of sendmail.
32*0Sstevel@tonic-gate **
33*0Sstevel@tonic-gate ** Use this in place of /bin/sh in the "prog" mailer definition
34*0Sstevel@tonic-gate ** in your sendmail.cf file. You then create CMDDIR (owned by
35*0Sstevel@tonic-gate ** root, mode 755) and put links to any programs you want
36*0Sstevel@tonic-gate ** available to prog mailers in that directory. This should
37*0Sstevel@tonic-gate ** include things like "vacation" and "procmail", but not "sed"
38*0Sstevel@tonic-gate ** or "sh".
39*0Sstevel@tonic-gate **
40*0Sstevel@tonic-gate ** Leading pathnames are stripped from program names so that
41*0Sstevel@tonic-gate ** existing .forward files that reference things like
42*0Sstevel@tonic-gate ** "/usr/bin/vacation" will continue to work.
43*0Sstevel@tonic-gate **
44*0Sstevel@tonic-gate ** The following characters are completely illegal:
45*0Sstevel@tonic-gate ** < > ^ & ` ( ) \n \r
46*0Sstevel@tonic-gate ** The following characters are sometimes illegal:
47*0Sstevel@tonic-gate ** | &
48*0Sstevel@tonic-gate ** This is more restrictive than strictly necessary.
49*0Sstevel@tonic-gate **
50*0Sstevel@tonic-gate ** To use this, add FEATURE(`smrsh') to your .mc file.
51*0Sstevel@tonic-gate **
52*0Sstevel@tonic-gate ** This can be used on any version of sendmail.
53*0Sstevel@tonic-gate **
54*0Sstevel@tonic-gate ** In loving memory of RTM. 11/02/93.
55*0Sstevel@tonic-gate */
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gate #include <unistd.h>
58*0Sstevel@tonic-gate #include <sm/io.h>
59*0Sstevel@tonic-gate #include <sm/limits.h>
60*0Sstevel@tonic-gate #include <sm/string.h>
61*0Sstevel@tonic-gate #include <sys/file.h>
62*0Sstevel@tonic-gate #include <sys/types.h>
63*0Sstevel@tonic-gate #include <sys/stat.h>
64*0Sstevel@tonic-gate #include <string.h>
65*0Sstevel@tonic-gate #include <ctype.h>
66*0Sstevel@tonic-gate #include <errno.h>
67*0Sstevel@tonic-gate #ifdef EX_OK
68*0Sstevel@tonic-gate # undef EX_OK
69*0Sstevel@tonic-gate #endif /* EX_OK */
70*0Sstevel@tonic-gate #include <sysexits.h>
71*0Sstevel@tonic-gate #include <syslog.h>
72*0Sstevel@tonic-gate #include <stdlib.h>
73*0Sstevel@tonic-gate
74*0Sstevel@tonic-gate #include <sm/conf.h>
75*0Sstevel@tonic-gate #include <sm/errstring.h>
76*0Sstevel@tonic-gate
77*0Sstevel@tonic-gate /* directory in which all commands must reside */
78*0Sstevel@tonic-gate #ifndef CMDDIR
79*0Sstevel@tonic-gate # ifdef SMRSH_CMDDIR
80*0Sstevel@tonic-gate # define CMDDIR SMRSH_CMDDIR
81*0Sstevel@tonic-gate # else /* SMRSH_CMDDIR */
82*0Sstevel@tonic-gate # define CMDDIR "/usr/adm/sm.bin"
83*0Sstevel@tonic-gate # endif /* SMRSH_CMDDIR */
84*0Sstevel@tonic-gate #endif /* ! CMDDIR */
85*0Sstevel@tonic-gate
86*0Sstevel@tonic-gate /* characters disallowed in the shell "-c" argument */
87*0Sstevel@tonic-gate #define SPECIALS "<|>^();&`$\r\n"
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate /* default search path */
90*0Sstevel@tonic-gate #ifndef PATH
91*0Sstevel@tonic-gate # ifdef SMRSH_PATH
92*0Sstevel@tonic-gate # define PATH SMRSH_PATH
93*0Sstevel@tonic-gate # else /* SMRSH_PATH */
94*0Sstevel@tonic-gate # define PATH "/bin:/usr/bin:/usr/ucb"
95*0Sstevel@tonic-gate # endif /* SMRSH_PATH */
96*0Sstevel@tonic-gate #endif /* ! PATH */
97*0Sstevel@tonic-gate
98*0Sstevel@tonic-gate char newcmdbuf[1000];
99*0Sstevel@tonic-gate char *prg, *par;
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate static void addcmd __P((char *, bool, size_t));
102*0Sstevel@tonic-gate
103*0Sstevel@tonic-gate /*
104*0Sstevel@tonic-gate ** ADDCMD -- add a string to newcmdbuf, check for overflow
105*0Sstevel@tonic-gate **
106*0Sstevel@tonic-gate ** Parameters:
107*0Sstevel@tonic-gate ** s -- string to add
108*0Sstevel@tonic-gate ** cmd -- it's a command: prepend CMDDIR/
109*0Sstevel@tonic-gate ** len -- length of string to add
110*0Sstevel@tonic-gate **
111*0Sstevel@tonic-gate ** Side Effects:
112*0Sstevel@tonic-gate ** changes newcmdbuf or exits with a failure.
113*0Sstevel@tonic-gate **
114*0Sstevel@tonic-gate */
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate static void
addcmd(s,cmd,len)117*0Sstevel@tonic-gate addcmd(s, cmd, len)
118*0Sstevel@tonic-gate char *s;
119*0Sstevel@tonic-gate bool cmd;
120*0Sstevel@tonic-gate size_t len;
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate if (s == NULL || *s == '\0')
123*0Sstevel@tonic-gate return;
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate /* enough space for s (len) and CMDDIR + "/" and '\0'? */
126*0Sstevel@tonic-gate if (sizeof newcmdbuf - strlen(newcmdbuf) <=
127*0Sstevel@tonic-gate len + 1 + (cmd ? (strlen(CMDDIR) + 1) : 0))
128*0Sstevel@tonic-gate {
129*0Sstevel@tonic-gate (void)sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
130*0Sstevel@tonic-gate "%s: command too long: %s\n", prg, par);
131*0Sstevel@tonic-gate #ifndef DEBUG
132*0Sstevel@tonic-gate syslog(LOG_WARNING, "command too long: %.40s", par);
133*0Sstevel@tonic-gate #endif /* ! DEBUG */
134*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
135*0Sstevel@tonic-gate }
136*0Sstevel@tonic-gate if (cmd)
137*0Sstevel@tonic-gate (void) sm_strlcat2(newcmdbuf, CMDDIR, "/", sizeof newcmdbuf);
138*0Sstevel@tonic-gate (void) strncat(newcmdbuf, s, len);
139*0Sstevel@tonic-gate }
140*0Sstevel@tonic-gate
141*0Sstevel@tonic-gate int
main(argc,argv)142*0Sstevel@tonic-gate main(argc, argv)
143*0Sstevel@tonic-gate int argc;
144*0Sstevel@tonic-gate char **argv;
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate register char *p;
147*0Sstevel@tonic-gate register char *q;
148*0Sstevel@tonic-gate register char *r;
149*0Sstevel@tonic-gate register char *cmd;
150*0Sstevel@tonic-gate int isexec;
151*0Sstevel@tonic-gate int save_errno;
152*0Sstevel@tonic-gate char *newenv[2];
153*0Sstevel@tonic-gate char pathbuf[1000];
154*0Sstevel@tonic-gate char specialbuf[32];
155*0Sstevel@tonic-gate struct stat st;
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate #ifndef DEBUG
158*0Sstevel@tonic-gate # ifndef LOG_MAIL
159*0Sstevel@tonic-gate openlog("smrsh", 0);
160*0Sstevel@tonic-gate # else /* ! LOG_MAIL */
161*0Sstevel@tonic-gate openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL);
162*0Sstevel@tonic-gate # endif /* ! LOG_MAIL */
163*0Sstevel@tonic-gate #endif /* ! DEBUG */
164*0Sstevel@tonic-gate
165*0Sstevel@tonic-gate (void) sm_strlcpyn(pathbuf, sizeof pathbuf, 2, "PATH=", PATH);
166*0Sstevel@tonic-gate newenv[0] = pathbuf;
167*0Sstevel@tonic-gate newenv[1] = NULL;
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate /*
170*0Sstevel@tonic-gate ** Do basic argv usage checking
171*0Sstevel@tonic-gate */
172*0Sstevel@tonic-gate
173*0Sstevel@tonic-gate prg = argv[0];
174*0Sstevel@tonic-gate
175*0Sstevel@tonic-gate if (argc != 3 || strcmp(argv[1], "-c") != 0)
176*0Sstevel@tonic-gate {
177*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
178*0Sstevel@tonic-gate "Usage: %s -c command\n", prg);
179*0Sstevel@tonic-gate #ifndef DEBUG
180*0Sstevel@tonic-gate syslog(LOG_ERR, "usage");
181*0Sstevel@tonic-gate #endif /* ! DEBUG */
182*0Sstevel@tonic-gate exit(EX_USAGE);
183*0Sstevel@tonic-gate }
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate par = argv[2];
186*0Sstevel@tonic-gate
187*0Sstevel@tonic-gate /*
188*0Sstevel@tonic-gate ** Disallow special shell syntax. This is overly restrictive,
189*0Sstevel@tonic-gate ** but it should shut down all attacks.
190*0Sstevel@tonic-gate ** Be sure to include 8-bit versions, since many shells strip
191*0Sstevel@tonic-gate ** the address to 7 bits before checking.
192*0Sstevel@tonic-gate */
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate if (strlen(SPECIALS) * 2 >= sizeof specialbuf)
195*0Sstevel@tonic-gate {
196*0Sstevel@tonic-gate #ifndef DEBUG
197*0Sstevel@tonic-gate syslog(LOG_ERR, "too many specials: %.40s", SPECIALS);
198*0Sstevel@tonic-gate #endif /* ! DEBUG */
199*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
200*0Sstevel@tonic-gate }
201*0Sstevel@tonic-gate (void) sm_strlcpy(specialbuf, SPECIALS, sizeof specialbuf);
202*0Sstevel@tonic-gate for (p = specialbuf; *p != '\0'; p++)
203*0Sstevel@tonic-gate *p |= '\200';
204*0Sstevel@tonic-gate (void) sm_strlcat(specialbuf, SPECIALS, sizeof specialbuf);
205*0Sstevel@tonic-gate
206*0Sstevel@tonic-gate /*
207*0Sstevel@tonic-gate ** Do a quick sanity check on command line length.
208*0Sstevel@tonic-gate */
209*0Sstevel@tonic-gate
210*0Sstevel@tonic-gate if (strlen(par) > (sizeof newcmdbuf - sizeof CMDDIR - 2))
211*0Sstevel@tonic-gate {
212*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
213*0Sstevel@tonic-gate "%s: command too long: %s\n", prg, par);
214*0Sstevel@tonic-gate #ifndef DEBUG
215*0Sstevel@tonic-gate syslog(LOG_WARNING, "command too long: %.40s", par);
216*0Sstevel@tonic-gate #endif /* ! DEBUG */
217*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate
220*0Sstevel@tonic-gate q = par;
221*0Sstevel@tonic-gate newcmdbuf[0] = '\0';
222*0Sstevel@tonic-gate isexec = false;
223*0Sstevel@tonic-gate
224*0Sstevel@tonic-gate while (*q != '\0')
225*0Sstevel@tonic-gate {
226*0Sstevel@tonic-gate /*
227*0Sstevel@tonic-gate ** Strip off a leading pathname on the command name. For
228*0Sstevel@tonic-gate ** example, change /usr/ucb/vacation to vacation.
229*0Sstevel@tonic-gate */
230*0Sstevel@tonic-gate
231*0Sstevel@tonic-gate /* strip leading spaces */
232*0Sstevel@tonic-gate while (*q != '\0' && isascii(*q) && isspace(*q))
233*0Sstevel@tonic-gate q++;
234*0Sstevel@tonic-gate if (*q == '\0')
235*0Sstevel@tonic-gate {
236*0Sstevel@tonic-gate if (isexec)
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
239*0Sstevel@tonic-gate "%s: missing command to exec\n",
240*0Sstevel@tonic-gate prg);
241*0Sstevel@tonic-gate #ifndef DEBUG
242*0Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: missing command to exec", (int) getuid());
243*0Sstevel@tonic-gate #endif /* ! DEBUG */
244*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
245*0Sstevel@tonic-gate }
246*0Sstevel@tonic-gate break;
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate
249*0Sstevel@tonic-gate /* find the end of the command name */
250*0Sstevel@tonic-gate p = strpbrk(q, " \t");
251*0Sstevel@tonic-gate if (p == NULL)
252*0Sstevel@tonic-gate cmd = &q[strlen(q)];
253*0Sstevel@tonic-gate else
254*0Sstevel@tonic-gate {
255*0Sstevel@tonic-gate *p = '\0';
256*0Sstevel@tonic-gate cmd = p;
257*0Sstevel@tonic-gate }
258*0Sstevel@tonic-gate /* search backwards for last / (allow for 0200 bit) */
259*0Sstevel@tonic-gate while (cmd > q)
260*0Sstevel@tonic-gate {
261*0Sstevel@tonic-gate if ((*--cmd & 0177) == '/')
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate cmd++;
264*0Sstevel@tonic-gate break;
265*0Sstevel@tonic-gate }
266*0Sstevel@tonic-gate }
267*0Sstevel@tonic-gate /* cmd now points at final component of path name */
268*0Sstevel@tonic-gate
269*0Sstevel@tonic-gate /* allow a few shell builtins */
270*0Sstevel@tonic-gate if (strcmp(q, "exec") == 0 && p != NULL)
271*0Sstevel@tonic-gate {
272*0Sstevel@tonic-gate addcmd("exec ", false, strlen("exec "));
273*0Sstevel@tonic-gate
274*0Sstevel@tonic-gate /* test _next_ arg */
275*0Sstevel@tonic-gate q = ++p;
276*0Sstevel@tonic-gate isexec = true;
277*0Sstevel@tonic-gate continue;
278*0Sstevel@tonic-gate }
279*0Sstevel@tonic-gate else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0)
280*0Sstevel@tonic-gate {
281*0Sstevel@tonic-gate addcmd(cmd, false, strlen(cmd));
282*0Sstevel@tonic-gate
283*0Sstevel@tonic-gate /* test following chars */
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate else
286*0Sstevel@tonic-gate {
287*0Sstevel@tonic-gate char cmdbuf[MAXPATHLEN];
288*0Sstevel@tonic-gate
289*0Sstevel@tonic-gate /*
290*0Sstevel@tonic-gate ** Check to see if the command name is legal.
291*0Sstevel@tonic-gate */
292*0Sstevel@tonic-gate
293*0Sstevel@tonic-gate if (sm_strlcpyn(cmdbuf, sizeof cmdbuf, 3, CMDDIR,
294*0Sstevel@tonic-gate "/", cmd) >= sizeof cmdbuf)
295*0Sstevel@tonic-gate {
296*0Sstevel@tonic-gate /* too long */
297*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
298*0Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs (filename too long)\n",
299*0Sstevel@tonic-gate prg, cmd);
300*0Sstevel@tonic-gate if (p != NULL)
301*0Sstevel@tonic-gate *p = ' ';
302*0Sstevel@tonic-gate #ifndef DEBUG
303*0Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (filename too long)",
304*0Sstevel@tonic-gate (int) getuid(), cmd);
305*0Sstevel@tonic-gate #endif /* ! DEBUG */
306*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
307*0Sstevel@tonic-gate }
308*0Sstevel@tonic-gate
309*0Sstevel@tonic-gate #ifdef DEBUG
310*0Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
311*0Sstevel@tonic-gate "Trying %s\n", cmdbuf);
312*0Sstevel@tonic-gate #endif /* DEBUG */
313*0Sstevel@tonic-gate if (stat(cmdbuf, &st) < 0)
314*0Sstevel@tonic-gate {
315*0Sstevel@tonic-gate /* can't stat it */
316*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
317*0Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs (stat failed)\n",
318*0Sstevel@tonic-gate prg, cmd);
319*0Sstevel@tonic-gate if (p != NULL)
320*0Sstevel@tonic-gate *p = ' ';
321*0Sstevel@tonic-gate #ifndef DEBUG
322*0Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (stat failed)",
323*0Sstevel@tonic-gate (int) getuid(), cmd);
324*0Sstevel@tonic-gate #endif /* ! DEBUG */
325*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
326*0Sstevel@tonic-gate }
327*0Sstevel@tonic-gate if (!S_ISREG(st.st_mode)
328*0Sstevel@tonic-gate #ifdef S_ISLNK
329*0Sstevel@tonic-gate && !S_ISLNK(st.st_mode)
330*0Sstevel@tonic-gate #endif /* S_ISLNK */
331*0Sstevel@tonic-gate )
332*0Sstevel@tonic-gate {
333*0Sstevel@tonic-gate /* can't stat it */
334*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
335*0Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs (not a file)\n",
336*0Sstevel@tonic-gate prg, cmd);
337*0Sstevel@tonic-gate if (p != NULL)
338*0Sstevel@tonic-gate *p = ' ';
339*0Sstevel@tonic-gate #ifndef DEBUG
340*0Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (not a file)",
341*0Sstevel@tonic-gate (int) getuid(), cmd);
342*0Sstevel@tonic-gate #endif /* ! DEBUG */
343*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate if (access(cmdbuf, X_OK) < 0)
346*0Sstevel@tonic-gate {
347*0Sstevel@tonic-gate /* oops.... crack attack possiblity */
348*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
349*0Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs\n",
350*0Sstevel@tonic-gate prg, cmd);
351*0Sstevel@tonic-gate if (p != NULL)
352*0Sstevel@tonic-gate *p = ' ';
353*0Sstevel@tonic-gate #ifndef DEBUG
354*0Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\"",
355*0Sstevel@tonic-gate (int) getuid(), cmd);
356*0Sstevel@tonic-gate #endif /* ! DEBUG */
357*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
358*0Sstevel@tonic-gate }
359*0Sstevel@tonic-gate
360*0Sstevel@tonic-gate /*
361*0Sstevel@tonic-gate ** Create the actual shell input.
362*0Sstevel@tonic-gate */
363*0Sstevel@tonic-gate
364*0Sstevel@tonic-gate addcmd(cmd, true, strlen(cmd));
365*0Sstevel@tonic-gate }
366*0Sstevel@tonic-gate isexec = false;
367*0Sstevel@tonic-gate
368*0Sstevel@tonic-gate if (p != NULL)
369*0Sstevel@tonic-gate *p = ' ';
370*0Sstevel@tonic-gate else
371*0Sstevel@tonic-gate break;
372*0Sstevel@tonic-gate
373*0Sstevel@tonic-gate r = strpbrk(p, specialbuf);
374*0Sstevel@tonic-gate if (r == NULL)
375*0Sstevel@tonic-gate {
376*0Sstevel@tonic-gate addcmd(p, false, strlen(p));
377*0Sstevel@tonic-gate break;
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate #if ALLOWSEMI
380*0Sstevel@tonic-gate if (*r == ';')
381*0Sstevel@tonic-gate {
382*0Sstevel@tonic-gate addcmd(p, false, r - p + 1);
383*0Sstevel@tonic-gate q = r + 1;
384*0Sstevel@tonic-gate continue;
385*0Sstevel@tonic-gate }
386*0Sstevel@tonic-gate #endif /* ALLOWSEMI */
387*0Sstevel@tonic-gate if ((*r == '&' && *(r + 1) == '&') ||
388*0Sstevel@tonic-gate (*r == '|' && *(r + 1) == '|'))
389*0Sstevel@tonic-gate {
390*0Sstevel@tonic-gate addcmd(p, false, r - p + 2);
391*0Sstevel@tonic-gate q = r + 2;
392*0Sstevel@tonic-gate continue;
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate
395*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
396*0Sstevel@tonic-gate "%s: cannot use %c in command\n", prg, *r);
397*0Sstevel@tonic-gate #ifndef DEBUG
398*0Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
399*0Sstevel@tonic-gate (int) getuid(), *r, par);
400*0Sstevel@tonic-gate #endif /* ! DEBUG */
401*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
402*0Sstevel@tonic-gate }
403*0Sstevel@tonic-gate if (isexec)
404*0Sstevel@tonic-gate {
405*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
406*0Sstevel@tonic-gate "%s: missing command to exec\n", prg);
407*0Sstevel@tonic-gate #ifndef DEBUG
408*0Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: missing command to exec",
409*0Sstevel@tonic-gate (int) getuid());
410*0Sstevel@tonic-gate #endif /* ! DEBUG */
411*0Sstevel@tonic-gate exit(EX_UNAVAILABLE);
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate /* make sure we created something */
414*0Sstevel@tonic-gate if (newcmdbuf[0] == '\0')
415*0Sstevel@tonic-gate {
416*0Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
417*0Sstevel@tonic-gate "Usage: %s -c command\n", prg);
418*0Sstevel@tonic-gate #ifndef DEBUG
419*0Sstevel@tonic-gate syslog(LOG_ERR, "usage");
420*0Sstevel@tonic-gate #endif /* ! DEBUG */
421*0Sstevel@tonic-gate exit(EX_USAGE);
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gate /*
425*0Sstevel@tonic-gate ** Now invoke the shell
426*0Sstevel@tonic-gate */
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gate #ifdef DEBUG
429*0Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", newcmdbuf);
430*0Sstevel@tonic-gate #endif /* DEBUG */
431*0Sstevel@tonic-gate (void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf,
432*0Sstevel@tonic-gate (char *)NULL, newenv);
433*0Sstevel@tonic-gate save_errno = errno;
434*0Sstevel@tonic-gate #ifndef DEBUG
435*0Sstevel@tonic-gate syslog(LOG_CRIT, "Cannot exec /bin/sh: %s", sm_errstring(errno));
436*0Sstevel@tonic-gate #endif /* ! DEBUG */
437*0Sstevel@tonic-gate errno = save_errno;
438*0Sstevel@tonic-gate sm_perror("/bin/sh");
439*0Sstevel@tonic-gate exit(EX_OSFILE);
440*0Sstevel@tonic-gate /* NOTREACHED */
441*0Sstevel@tonic-gate return EX_OSFILE;
442*0Sstevel@tonic-gate }
443