xref: /freebsd/contrib/sendmail/smrsh/smrsh.c (revision 2fb4f839f3fc72ce2bab12f9ba4760f97f73e97f)
1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2004 Proofpoint, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1993 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1412ed1c7cSGregory Neil Shapiro #include <sm/gen.h>
1512ed1c7cSGregory Neil Shapiro 
1612ed1c7cSGregory Neil Shapiro SM_IDSTR(copyright,
175dd76dd0SGregory Neil Shapiro "@(#) Copyright (c) 1998-2004 Proofpoint, Inc. and its suppliers.\n\
183299c2f1SGregory Neil Shapiro 	All rights reserved.\n\
193299c2f1SGregory Neil Shapiro      Copyright (c) 1993 Eric P. Allman.  All rights reserved.\n\
203299c2f1SGregory Neil Shapiro      Copyright (c) 1993\n\
2112ed1c7cSGregory Neil Shapiro 	The Regents of the University of California.  All rights reserved.\n")
223299c2f1SGregory Neil Shapiro 
234313cc83SGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: smrsh.c,v 8.66 2013-11-22 20:52:00 ca Exp $")
243299c2f1SGregory Neil Shapiro 
25c2aa98e2SPeter Wemm /*
26c2aa98e2SPeter Wemm **  SMRSH -- sendmail restricted shell
27c2aa98e2SPeter Wemm **
28c2aa98e2SPeter Wemm **	This is a patch to get around the prog mailer bugs in most
29c2aa98e2SPeter Wemm **	versions of sendmail.
30c2aa98e2SPeter Wemm **
31c2aa98e2SPeter Wemm **	Use this in place of /bin/sh in the "prog" mailer definition
32c2aa98e2SPeter Wemm **	in your sendmail.cf file.  You then create CMDDIR (owned by
33c2aa98e2SPeter Wemm **	root, mode 755) and put links to any programs you want
34c2aa98e2SPeter Wemm **	available to prog mailers in that directory.  This should
35c2aa98e2SPeter Wemm **	include things like "vacation" and "procmail", but not "sed"
36c2aa98e2SPeter Wemm **	or "sh".
37c2aa98e2SPeter Wemm **
38c2aa98e2SPeter Wemm **	Leading pathnames are stripped from program names so that
39c2aa98e2SPeter Wemm **	existing .forward files that reference things like
401bceb5b2SPeter Wemm **	"/usr/bin/vacation" will continue to work.
41c2aa98e2SPeter Wemm **
42c2aa98e2SPeter Wemm **	The following characters are completely illegal:
433299c2f1SGregory Neil Shapiro **		<  >  ^  &  `  (  ) \n \r
443299c2f1SGregory Neil Shapiro **	The following characters are sometimes illegal:
453299c2f1SGregory Neil Shapiro **		|  &
46c2aa98e2SPeter Wemm **	This is more restrictive than strictly necessary.
47c2aa98e2SPeter Wemm **
483299c2f1SGregory Neil Shapiro **	To use this, add FEATURE(`smrsh') to your .mc file.
49c2aa98e2SPeter Wemm **
50c2aa98e2SPeter Wemm **	This can be used on any version of sendmail.
51c2aa98e2SPeter Wemm **
52c2aa98e2SPeter Wemm **	In loving memory of RTM.  11/02/93.
53c2aa98e2SPeter Wemm */
54c2aa98e2SPeter Wemm 
55c2aa98e2SPeter Wemm #include <unistd.h>
5612ed1c7cSGregory Neil Shapiro #include <sm/io.h>
5788ad41d4SGregory Neil Shapiro #include <sm/limits.h>
5812ed1c7cSGregory Neil Shapiro #include <sm/string.h>
59c2aa98e2SPeter Wemm #include <sys/file.h>
60509cae37SGregory Neil Shapiro #include <sys/types.h>
61509cae37SGregory Neil Shapiro #include <sys/stat.h>
62c2aa98e2SPeter Wemm #include <string.h>
63c2aa98e2SPeter Wemm #include <ctype.h>
643299c2f1SGregory Neil Shapiro #include <errno.h>
65c2aa98e2SPeter Wemm #ifdef EX_OK
66c2aa98e2SPeter Wemm # undef EX_OK
67*5b0945b5SGregory Neil Shapiro #endif
68c2aa98e2SPeter Wemm #include <sysexits.h>
69c2aa98e2SPeter Wemm #include <syslog.h>
70c2aa98e2SPeter Wemm #include <stdlib.h>
71c2aa98e2SPeter Wemm 
7212ed1c7cSGregory Neil Shapiro #include <sm/conf.h>
7312ed1c7cSGregory Neil Shapiro #include <sm/errstring.h>
743299c2f1SGregory Neil Shapiro 
75c2aa98e2SPeter Wemm /* directory in which all commands must reside */
76c2aa98e2SPeter Wemm #ifndef CMDDIR
7712ed1c7cSGregory Neil Shapiro # ifdef SMRSH_CMDDIR
7812ed1c7cSGregory Neil Shapiro #  define CMDDIR	SMRSH_CMDDIR
79*5b0945b5SGregory Neil Shapiro # else
8012ed1c7cSGregory Neil Shapiro #  define CMDDIR	"/usr/adm/sm.bin"
81*5b0945b5SGregory Neil Shapiro # endif
823299c2f1SGregory Neil Shapiro #endif /* ! CMDDIR */
83c2aa98e2SPeter Wemm 
84c2aa98e2SPeter Wemm /* characters disallowed in the shell "-c" argument */
85c2aa98e2SPeter Wemm #define SPECIALS	"<|>^();&`$\r\n"
86c2aa98e2SPeter Wemm 
87c2aa98e2SPeter Wemm /* default search path */
88c2aa98e2SPeter Wemm #ifndef PATH
8912ed1c7cSGregory Neil Shapiro # ifdef SMRSH_PATH
9012ed1c7cSGregory Neil Shapiro #  define PATH		SMRSH_PATH
91*5b0945b5SGregory Neil Shapiro # else
9212ed1c7cSGregory Neil Shapiro #  define PATH		"/bin:/usr/bin:/usr/ucb"
93*5b0945b5SGregory Neil Shapiro # endif
943299c2f1SGregory Neil Shapiro #endif /* ! PATH */
953299c2f1SGregory Neil Shapiro 
963299c2f1SGregory Neil Shapiro char newcmdbuf[1000];
973299c2f1SGregory Neil Shapiro char *prg, *par;
983299c2f1SGregory Neil Shapiro 
99684b2a5fSGregory Neil Shapiro static void	addcmd __P((char *, bool, size_t));
100684b2a5fSGregory Neil Shapiro 
1013299c2f1SGregory Neil Shapiro /*
1023299c2f1SGregory Neil Shapiro **  ADDCMD -- add a string to newcmdbuf, check for overflow
1033299c2f1SGregory Neil Shapiro **
1043299c2f1SGregory Neil Shapiro **    Parameters:
1053299c2f1SGregory Neil Shapiro **	s -- string to add
1063299c2f1SGregory Neil Shapiro **	cmd -- it's a command: prepend CMDDIR/
1073299c2f1SGregory Neil Shapiro **	len -- length of string to add
1083299c2f1SGregory Neil Shapiro **
1093299c2f1SGregory Neil Shapiro **    Side Effects:
1103299c2f1SGregory Neil Shapiro **	changes newcmdbuf or exits with a failure.
1113299c2f1SGregory Neil Shapiro **
1123299c2f1SGregory Neil Shapiro */
1133299c2f1SGregory Neil Shapiro 
114684b2a5fSGregory Neil Shapiro static void
addcmd(s,cmd,len)1153299c2f1SGregory Neil Shapiro addcmd(s, cmd, len)
1163299c2f1SGregory Neil Shapiro 	char *s;
11712ed1c7cSGregory Neil Shapiro 	bool cmd;
11812ed1c7cSGregory Neil Shapiro 	size_t len;
1193299c2f1SGregory Neil Shapiro {
1203299c2f1SGregory Neil Shapiro 	if (s == NULL || *s == '\0')
1213299c2f1SGregory Neil Shapiro 		return;
1223299c2f1SGregory Neil Shapiro 
1231ae5b8d4SGregory Neil Shapiro 	/* enough space for s (len) and CMDDIR + "/" and '\0'? */
1243299c2f1SGregory Neil Shapiro 	if (sizeof newcmdbuf - strlen(newcmdbuf) <=
1251ae5b8d4SGregory Neil Shapiro 	    len + 1 + (cmd ? (strlen(CMDDIR) + 1) : 0))
1263299c2f1SGregory Neil Shapiro 	{
12712ed1c7cSGregory Neil Shapiro 		(void)sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
12812ed1c7cSGregory Neil Shapiro 				    "%s: command too long: %s\n", prg, par);
1293299c2f1SGregory Neil Shapiro #ifndef DEBUG
1303299c2f1SGregory Neil Shapiro 		syslog(LOG_WARNING, "command too long: %.40s", par);
131*5b0945b5SGregory Neil Shapiro #endif
1323299c2f1SGregory Neil Shapiro 		exit(EX_UNAVAILABLE);
1333299c2f1SGregory Neil Shapiro 	}
1343299c2f1SGregory Neil Shapiro 	if (cmd)
13588ad41d4SGregory Neil Shapiro 		(void) sm_strlcat2(newcmdbuf, CMDDIR, "/", sizeof newcmdbuf);
1361ae5b8d4SGregory Neil Shapiro 	(void) strncat(newcmdbuf, s, len);
1373299c2f1SGregory Neil Shapiro }
138c2aa98e2SPeter Wemm 
139c2aa98e2SPeter Wemm int
main(argc,argv)140c2aa98e2SPeter Wemm main(argc, argv)
141c2aa98e2SPeter Wemm 	int argc;
142c2aa98e2SPeter Wemm 	char **argv;
143c2aa98e2SPeter Wemm {
144c2aa98e2SPeter Wemm 	register char *p;
145c2aa98e2SPeter Wemm 	register char *q;
1463299c2f1SGregory Neil Shapiro 	register char *r;
147c2aa98e2SPeter Wemm 	register char *cmd;
1483299c2f1SGregory Neil Shapiro 	int isexec;
1493299c2f1SGregory Neil Shapiro 	int save_errno;
150c2aa98e2SPeter Wemm 	char *newenv[2];
151c2aa98e2SPeter Wemm 	char pathbuf[1000];
1523299c2f1SGregory Neil Shapiro 	char specialbuf[32];
153509cae37SGregory Neil Shapiro 	struct stat st;
154c2aa98e2SPeter Wemm 
1553299c2f1SGregory Neil Shapiro #ifndef DEBUG
156c2aa98e2SPeter Wemm # ifndef LOG_MAIL
157c2aa98e2SPeter Wemm 	openlog("smrsh", 0);
158*5b0945b5SGregory Neil Shapiro # else
159c2aa98e2SPeter Wemm 	openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL);
160*5b0945b5SGregory Neil Shapiro # endif
1613299c2f1SGregory Neil Shapiro #endif /* ! DEBUG */
162c2aa98e2SPeter Wemm 
16388ad41d4SGregory Neil Shapiro 	(void) sm_strlcpyn(pathbuf, sizeof pathbuf, 2, "PATH=", PATH);
164c2aa98e2SPeter Wemm 	newenv[0] = pathbuf;
165c2aa98e2SPeter Wemm 	newenv[1] = NULL;
166c2aa98e2SPeter Wemm 
167c2aa98e2SPeter Wemm 	/*
168c2aa98e2SPeter Wemm 	**  Do basic argv usage checking
169c2aa98e2SPeter Wemm 	*/
170c2aa98e2SPeter Wemm 
1713299c2f1SGregory Neil Shapiro 	prg = argv[0];
1723299c2f1SGregory Neil Shapiro 
173c2aa98e2SPeter Wemm 	if (argc != 3 || strcmp(argv[1], "-c") != 0)
174c2aa98e2SPeter Wemm 	{
17512ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
17612ed1c7cSGregory Neil Shapiro 				     "Usage: %s -c command\n", prg);
1773299c2f1SGregory Neil Shapiro #ifndef DEBUG
178c2aa98e2SPeter Wemm 		syslog(LOG_ERR, "usage");
179*5b0945b5SGregory Neil Shapiro #endif
180c2aa98e2SPeter Wemm 		exit(EX_USAGE);
181c2aa98e2SPeter Wemm 	}
182c2aa98e2SPeter Wemm 
183c0c4794dSGregory Neil Shapiro 	par = argv[2];
184c0c4794dSGregory Neil Shapiro 
185c2aa98e2SPeter Wemm 	/*
186c2aa98e2SPeter Wemm 	**  Disallow special shell syntax.  This is overly restrictive,
187c2aa98e2SPeter Wemm 	**  but it should shut down all attacks.
188c2aa98e2SPeter Wemm 	**  Be sure to include 8-bit versions, since many shells strip
189c2aa98e2SPeter Wemm 	**  the address to 7 bits before checking.
190c2aa98e2SPeter Wemm 	*/
191c2aa98e2SPeter Wemm 
1923299c2f1SGregory Neil Shapiro 	if (strlen(SPECIALS) * 2 >= sizeof specialbuf)
193c2aa98e2SPeter Wemm 	{
1943299c2f1SGregory Neil Shapiro #ifndef DEBUG
1953299c2f1SGregory Neil Shapiro 		syslog(LOG_ERR, "too many specials: %.40s", SPECIALS);
196*5b0945b5SGregory Neil Shapiro #endif
197c2aa98e2SPeter Wemm 		exit(EX_UNAVAILABLE);
198c2aa98e2SPeter Wemm 	}
19912ed1c7cSGregory Neil Shapiro 	(void) sm_strlcpy(specialbuf, SPECIALS, sizeof specialbuf);
2003299c2f1SGregory Neil Shapiro 	for (p = specialbuf; *p != '\0'; p++)
2013299c2f1SGregory Neil Shapiro 		*p |= '\200';
20212ed1c7cSGregory Neil Shapiro 	(void) sm_strlcat(specialbuf, SPECIALS, sizeof specialbuf);
203c2aa98e2SPeter Wemm 
204c2aa98e2SPeter Wemm 	/*
205c2aa98e2SPeter Wemm 	**  Do a quick sanity check on command line length.
206c2aa98e2SPeter Wemm 	*/
207c2aa98e2SPeter Wemm 
20812ed1c7cSGregory Neil Shapiro 	if (strlen(par) > (sizeof newcmdbuf - sizeof CMDDIR - 2))
209c2aa98e2SPeter Wemm 	{
21012ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
21112ed1c7cSGregory Neil Shapiro 				     "%s: command too long: %s\n", prg, par);
2123299c2f1SGregory Neil Shapiro #ifndef DEBUG
2133299c2f1SGregory Neil Shapiro 		syslog(LOG_WARNING, "command too long: %.40s", par);
214*5b0945b5SGregory Neil Shapiro #endif
215c2aa98e2SPeter Wemm 		exit(EX_UNAVAILABLE);
216c2aa98e2SPeter Wemm 	}
217c2aa98e2SPeter Wemm 
2183299c2f1SGregory Neil Shapiro 	q = par;
2193299c2f1SGregory Neil Shapiro 	newcmdbuf[0] = '\0';
22012ed1c7cSGregory Neil Shapiro 	isexec = false;
2213299c2f1SGregory Neil Shapiro 
22288ad41d4SGregory Neil Shapiro 	while (*q != '\0')
2233299c2f1SGregory Neil Shapiro 	{
224c2aa98e2SPeter Wemm 		/*
225c2aa98e2SPeter Wemm 		**  Strip off a leading pathname on the command name.  For
226c2aa98e2SPeter Wemm 		**  example, change /usr/ucb/vacation to vacation.
227c2aa98e2SPeter Wemm 		*/
228c2aa98e2SPeter Wemm 
229c2aa98e2SPeter Wemm 		/* strip leading spaces */
2303299c2f1SGregory Neil Shapiro 		while (*q != '\0' && isascii(*q) && isspace(*q))
231c2aa98e2SPeter Wemm 			q++;
2323299c2f1SGregory Neil Shapiro 		if (*q == '\0')
2333299c2f1SGregory Neil Shapiro 		{
2343299c2f1SGregory Neil Shapiro 			if (isexec)
2353299c2f1SGregory Neil Shapiro 			{
23612ed1c7cSGregory Neil Shapiro 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
23712ed1c7cSGregory Neil Shapiro 						     "%s: missing command to exec\n",
2383299c2f1SGregory Neil Shapiro 						     prg);
2393299c2f1SGregory Neil Shapiro #ifndef DEBUG
24012ed1c7cSGregory Neil Shapiro 				syslog(LOG_CRIT, "uid %d: missing command to exec", (int) getuid());
241*5b0945b5SGregory Neil Shapiro #endif
2423299c2f1SGregory Neil Shapiro 				exit(EX_UNAVAILABLE);
2433299c2f1SGregory Neil Shapiro 			}
2443299c2f1SGregory Neil Shapiro 			break;
2453299c2f1SGregory Neil Shapiro 		}
246c2aa98e2SPeter Wemm 
247c2aa98e2SPeter Wemm 		/* find the end of the command name */
248c2aa98e2SPeter Wemm 		p = strpbrk(q, " \t");
249c2aa98e2SPeter Wemm 		if (p == NULL)
250c2aa98e2SPeter Wemm 			cmd = &q[strlen(q)];
251c2aa98e2SPeter Wemm 		else
252c2aa98e2SPeter Wemm 		{
253c2aa98e2SPeter Wemm 			*p = '\0';
254c2aa98e2SPeter Wemm 			cmd = p;
255c2aa98e2SPeter Wemm 		}
256c2aa98e2SPeter Wemm 		/* search backwards for last / (allow for 0200 bit) */
257c2aa98e2SPeter Wemm 		while (cmd > q)
258c2aa98e2SPeter Wemm 		{
259c2aa98e2SPeter Wemm 			if ((*--cmd & 0177) == '/')
260c2aa98e2SPeter Wemm 			{
261c2aa98e2SPeter Wemm 				cmd++;
262c2aa98e2SPeter Wemm 				break;
263c2aa98e2SPeter Wemm 			}
264c2aa98e2SPeter Wemm 		}
265c2aa98e2SPeter Wemm 		/* cmd now points at final component of path name */
266c2aa98e2SPeter Wemm 
2673299c2f1SGregory Neil Shapiro 		/* allow a few shell builtins */
2683299c2f1SGregory Neil Shapiro 		if (strcmp(q, "exec") == 0 && p != NULL)
2693299c2f1SGregory Neil Shapiro 		{
27012ed1c7cSGregory Neil Shapiro 			addcmd("exec ", false, strlen("exec "));
27188ad41d4SGregory Neil Shapiro 
2723299c2f1SGregory Neil Shapiro 			/* test _next_ arg */
2733299c2f1SGregory Neil Shapiro 			q = ++p;
27412ed1c7cSGregory Neil Shapiro 			isexec = true;
2753299c2f1SGregory Neil Shapiro 			continue;
2763299c2f1SGregory Neil Shapiro 		}
2773299c2f1SGregory Neil Shapiro 		else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0)
2783299c2f1SGregory Neil Shapiro 		{
27912ed1c7cSGregory Neil Shapiro 			addcmd(cmd, false, strlen(cmd));
28088ad41d4SGregory Neil Shapiro 
2813299c2f1SGregory Neil Shapiro 			/* test following chars */
2823299c2f1SGregory Neil Shapiro 		}
2833299c2f1SGregory Neil Shapiro 		else
2843299c2f1SGregory Neil Shapiro 		{
28588ad41d4SGregory Neil Shapiro 			char cmdbuf[MAXPATHLEN];
28688ad41d4SGregory Neil Shapiro 
287c2aa98e2SPeter Wemm 			/*
288c2aa98e2SPeter Wemm 			**  Check to see if the command name is legal.
289c2aa98e2SPeter Wemm 			*/
29088ad41d4SGregory Neil Shapiro 
29188ad41d4SGregory Neil Shapiro 			if (sm_strlcpyn(cmdbuf, sizeof cmdbuf, 3, CMDDIR,
29288ad41d4SGregory Neil Shapiro 					"/", cmd) >= sizeof cmdbuf)
29388ad41d4SGregory Neil Shapiro 			{
29488ad41d4SGregory Neil Shapiro 				/* too long */
29588ad41d4SGregory Neil Shapiro 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
2962ef40764SGregory Neil Shapiro 						     "%s: \"%s\" not available for sendmail programs (filename too long)\n",
29788ad41d4SGregory Neil Shapiro 						      prg, cmd);
29888ad41d4SGregory Neil Shapiro 				if (p != NULL)
29988ad41d4SGregory Neil Shapiro 					*p = ' ';
30088ad41d4SGregory Neil Shapiro #ifndef DEBUG
3012ef40764SGregory Neil Shapiro 				syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (filename too long)",
30288ad41d4SGregory Neil Shapiro 				       (int) getuid(), cmd);
303*5b0945b5SGregory Neil Shapiro #endif
30488ad41d4SGregory Neil Shapiro 				exit(EX_UNAVAILABLE);
30588ad41d4SGregory Neil Shapiro 			}
30688ad41d4SGregory Neil Shapiro 
307c2aa98e2SPeter Wemm #ifdef DEBUG
30812ed1c7cSGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
30912ed1c7cSGregory Neil Shapiro 					     "Trying %s\n", cmdbuf);
310*5b0945b5SGregory Neil Shapiro #endif
311509cae37SGregory Neil Shapiro 			if (stat(cmdbuf, &st) < 0)
312509cae37SGregory Neil Shapiro 			{
313509cae37SGregory Neil Shapiro 				/* can't stat it */
314509cae37SGregory Neil Shapiro 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3152ef40764SGregory Neil Shapiro 						     "%s: \"%s\" not available for sendmail programs (stat failed)\n",
316509cae37SGregory Neil Shapiro 						      prg, cmd);
317509cae37SGregory Neil Shapiro 				if (p != NULL)
318509cae37SGregory Neil Shapiro 					*p = ' ';
319509cae37SGregory Neil Shapiro #ifndef DEBUG
3202ef40764SGregory Neil Shapiro 				syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (stat failed)",
321509cae37SGregory Neil Shapiro 				       (int) getuid(), cmd);
322*5b0945b5SGregory Neil Shapiro #endif
323509cae37SGregory Neil Shapiro 				exit(EX_UNAVAILABLE);
324509cae37SGregory Neil Shapiro 			}
325509cae37SGregory Neil Shapiro 			if (!S_ISREG(st.st_mode)
326509cae37SGregory Neil Shapiro #ifdef S_ISLNK
327509cae37SGregory Neil Shapiro 			    && !S_ISLNK(st.st_mode)
328*5b0945b5SGregory Neil Shapiro #endif
329509cae37SGregory Neil Shapiro 			   )
330509cae37SGregory Neil Shapiro 			{
331509cae37SGregory Neil Shapiro 				/* can't stat it */
332509cae37SGregory Neil Shapiro 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3332ef40764SGregory Neil Shapiro 						     "%s: \"%s\" not available for sendmail programs (not a file)\n",
334509cae37SGregory Neil Shapiro 						      prg, cmd);
335509cae37SGregory Neil Shapiro 				if (p != NULL)
336509cae37SGregory Neil Shapiro 					*p = ' ';
337509cae37SGregory Neil Shapiro #ifndef DEBUG
3382ef40764SGregory Neil Shapiro 				syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (not a file)",
339509cae37SGregory Neil Shapiro 				       (int) getuid(), cmd);
340*5b0945b5SGregory Neil Shapiro #endif
341509cae37SGregory Neil Shapiro 				exit(EX_UNAVAILABLE);
342509cae37SGregory Neil Shapiro 			}
343c2aa98e2SPeter Wemm 			if (access(cmdbuf, X_OK) < 0)
344c2aa98e2SPeter Wemm 			{
345*5b0945b5SGregory Neil Shapiro 				/* oops....  crack attack possibility */
34612ed1c7cSGregory Neil Shapiro 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3472ef40764SGregory Neil Shapiro 						     "%s: \"%s\" not available for sendmail programs\n",
3483299c2f1SGregory Neil Shapiro 						      prg, cmd);
349c2aa98e2SPeter Wemm 				if (p != NULL)
350c2aa98e2SPeter Wemm 					*p = ' ';
3513299c2f1SGregory Neil Shapiro #ifndef DEBUG
3522ef40764SGregory Neil Shapiro 				syslog(LOG_CRIT, "uid %d: attempt to use \"%s\"",
35312ed1c7cSGregory Neil Shapiro 				       (int) getuid(), cmd);
354*5b0945b5SGregory Neil Shapiro #endif
355c2aa98e2SPeter Wemm 				exit(EX_UNAVAILABLE);
356c2aa98e2SPeter Wemm 			}
357c2aa98e2SPeter Wemm 
358c2aa98e2SPeter Wemm 			/*
359c2aa98e2SPeter Wemm 			**  Create the actual shell input.
360c2aa98e2SPeter Wemm 			*/
361c2aa98e2SPeter Wemm 
36212ed1c7cSGregory Neil Shapiro 			addcmd(cmd, true, strlen(cmd));
3633299c2f1SGregory Neil Shapiro 		}
36412ed1c7cSGregory Neil Shapiro 		isexec = false;
3653299c2f1SGregory Neil Shapiro 
3663299c2f1SGregory Neil Shapiro 		if (p != NULL)
3673299c2f1SGregory Neil Shapiro 			*p = ' ';
3683299c2f1SGregory Neil Shapiro 		else
3693299c2f1SGregory Neil Shapiro 			break;
3703299c2f1SGregory Neil Shapiro 
3713299c2f1SGregory Neil Shapiro 		r = strpbrk(p, specialbuf);
37212ed1c7cSGregory Neil Shapiro 		if (r == NULL)
37312ed1c7cSGregory Neil Shapiro 		{
37412ed1c7cSGregory Neil Shapiro 			addcmd(p, false, strlen(p));
3753299c2f1SGregory Neil Shapiro 			break;
3763299c2f1SGregory Neil Shapiro 		}
3773299c2f1SGregory Neil Shapiro #if ALLOWSEMI
37812ed1c7cSGregory Neil Shapiro 		if (*r == ';')
37912ed1c7cSGregory Neil Shapiro 		{
38012ed1c7cSGregory Neil Shapiro 			addcmd(p, false, r - p + 1);
3813299c2f1SGregory Neil Shapiro 			q = r + 1;
3823299c2f1SGregory Neil Shapiro 			continue;
3833299c2f1SGregory Neil Shapiro 		}
3843299c2f1SGregory Neil Shapiro #endif /* ALLOWSEMI */
3853299c2f1SGregory Neil Shapiro 		if ((*r == '&' && *(r + 1) == '&') ||
3863299c2f1SGregory Neil Shapiro 		    (*r == '|' && *(r + 1) == '|'))
3873299c2f1SGregory Neil Shapiro 		{
38812ed1c7cSGregory Neil Shapiro 			addcmd(p, false, r - p + 2);
3893299c2f1SGregory Neil Shapiro 			q = r + 2;
3903299c2f1SGregory Neil Shapiro 			continue;
3913299c2f1SGregory Neil Shapiro 		}
3923299c2f1SGregory Neil Shapiro 
39312ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
39412ed1c7cSGregory Neil Shapiro 				     "%s: cannot use %c in command\n", prg, *r);
3953299c2f1SGregory Neil Shapiro #ifndef DEBUG
3963299c2f1SGregory Neil Shapiro 		syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
39712ed1c7cSGregory Neil Shapiro 		       (int) getuid(), *r, par);
398*5b0945b5SGregory Neil Shapiro #endif
3993299c2f1SGregory Neil Shapiro 		exit(EX_UNAVAILABLE);
40088ad41d4SGregory Neil Shapiro 	}
4013299c2f1SGregory Neil Shapiro 	if (isexec)
4023299c2f1SGregory Neil Shapiro 	{
40312ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
40412ed1c7cSGregory Neil Shapiro 				     "%s: missing command to exec\n", prg);
4053299c2f1SGregory Neil Shapiro #ifndef DEBUG
40612ed1c7cSGregory Neil Shapiro 		syslog(LOG_CRIT, "uid %d: missing command to exec",
40712ed1c7cSGregory Neil Shapiro 		       (int) getuid());
408*5b0945b5SGregory Neil Shapiro #endif
4093299c2f1SGregory Neil Shapiro 		exit(EX_UNAVAILABLE);
4103299c2f1SGregory Neil Shapiro 	}
4113299c2f1SGregory Neil Shapiro 	/* make sure we created something */
4123299c2f1SGregory Neil Shapiro 	if (newcmdbuf[0] == '\0')
4133299c2f1SGregory Neil Shapiro 	{
41412ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
41512ed1c7cSGregory Neil Shapiro 				     "Usage: %s -c command\n", prg);
4163299c2f1SGregory Neil Shapiro #ifndef DEBUG
4173299c2f1SGregory Neil Shapiro 		syslog(LOG_ERR, "usage");
418*5b0945b5SGregory Neil Shapiro #endif
4193299c2f1SGregory Neil Shapiro 		exit(EX_USAGE);
4203299c2f1SGregory Neil Shapiro 	}
421c2aa98e2SPeter Wemm 
422c2aa98e2SPeter Wemm 	/*
423c2aa98e2SPeter Wemm 	**  Now invoke the shell
424c2aa98e2SPeter Wemm 	*/
425c2aa98e2SPeter Wemm 
426c2aa98e2SPeter Wemm #ifdef DEBUG
42712ed1c7cSGregory Neil Shapiro 	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", newcmdbuf);
428*5b0945b5SGregory Neil Shapiro #endif
4293fdb3903SGregory Neil Shapiro 	(void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf,
4303fdb3903SGregory Neil Shapiro 		      (char *)NULL, newenv);
4313299c2f1SGregory Neil Shapiro 	save_errno = errno;
4323299c2f1SGregory Neil Shapiro #ifndef DEBUG
43312ed1c7cSGregory Neil Shapiro 	syslog(LOG_CRIT, "Cannot exec /bin/sh: %s", sm_errstring(errno));
434*5b0945b5SGregory Neil Shapiro #endif
4353299c2f1SGregory Neil Shapiro 	errno = save_errno;
43612ed1c7cSGregory Neil Shapiro 	sm_perror("/bin/sh");
437c2aa98e2SPeter Wemm 	exit(EX_OSFILE);
4383299c2f1SGregory Neil Shapiro 	/* NOTREACHED */
4393299c2f1SGregory Neil Shapiro 	return EX_OSFILE;
440c2aa98e2SPeter Wemm }
441