/*
* Copyright (c) 1998-2004 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1993 Eric P. Allman. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
"@(#) Copyright (c) 1998-2004 Proofpoint, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\
Copyright (c) 1993\n\
The Regents of the University of California. All rights reserved.\n")
/*
** SMRSH -- sendmail restricted shell
**
** This is a patch to get around the prog mailer bugs in most
** versions of sendmail.
**
** in your sendmail.cf file. You then create CMDDIR (owned by
** root, mode 755) and put links to any programs you want
** available to prog mailers in that directory. This should
** include things like "vacation" and "procmail", but not "sed"
** or "sh".
**
** Leading pathnames are stripped from program names so that
** existing .forward files that reference things like
**
** The following characters are completely illegal:
** < > ^ & ` ( ) \n \r
** The following characters are sometimes illegal:
** | &
** This is more restrictive than strictly necessary.
**
** To use this, add FEATURE(`smrsh') to your .mc file.
**
** This can be used on any version of sendmail.
**
** In loving memory of RTM. 11/02/93.
*/
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#ifdef EX_OK
#endif /* EX_OK */
#include <sysexits.h>
#include <syslog.h>
#include <stdlib.h>
#include <sm/errstring.h>
/* directory in which all commands must reside */
#ifndef CMDDIR
# ifdef SMRSH_CMDDIR
# else /* SMRSH_CMDDIR */
# endif /* SMRSH_CMDDIR */
#endif /* ! CMDDIR */
/* characters disallowed in the shell "-c" argument */
/* default search path */
#ifndef PATH
# ifdef SMRSH_PATH
# else /* SMRSH_PATH */
# endif /* SMRSH_PATH */
#endif /* ! PATH */
/*
** ADDCMD -- add a string to newcmdbuf, check for overflow
**
** Parameters:
** s -- string to add
** cmd -- it's a command: prepend CMDDIR/
** len -- length of string to add
**
** Side Effects:
** changes newcmdbuf or exits with a failure.
**
*/
static void
char *s;
bool cmd;
{
if (s == NULL || *s == '\0')
return;
/* enough space for s (len) and CMDDIR + "/" and '\0'? */
{
#ifndef DEBUG
#endif /* ! DEBUG */
}
if (cmd)
}
int
int argc;
char **argv;
{
register char *p;
register char *q;
register char *r;
register char *cmd;
int isexec;
int save_errno;
#ifndef DEBUG
# ifndef LOG_MAIL
openlog("smrsh", 0);
# else /* ! LOG_MAIL */
# endif /* ! LOG_MAIL */
#endif /* ! DEBUG */
/*
** Do basic argv usage checking
*/
{
"Usage: %s -c command\n", prg);
#ifndef DEBUG
#endif /* ! DEBUG */
}
/*
** Disallow special shell syntax. This is overly restrictive,
** but it should shut down all attacks.
** Be sure to include 8-bit versions, since many shells strip
** the address to 7 bits before checking.
*/
{
#ifndef DEBUG
#endif /* ! DEBUG */
}
for (p = specialbuf; *p != '\0'; p++)
*p |= '\200';
/*
** Do a quick sanity check on command line length.
*/
{
#ifndef DEBUG
#endif /* ! DEBUG */
}
q = par;
newcmdbuf[0] = '\0';
isexec = false;
while (*q != '\0')
{
/*
** Strip off a leading pathname on the command name. For
*/
/* strip leading spaces */
q++;
if (*q == '\0')
{
if (isexec)
{
"%s: missing command to exec\n",
prg);
#ifndef DEBUG
#endif /* ! DEBUG */
}
break;
}
/* find the end of the command name */
p = strpbrk(q, " \t");
if (p == NULL)
else
{
*p = '\0';
cmd = p;
}
/* search backwards for last / (allow for 0200 bit) */
while (cmd > q)
{
{
cmd++;
break;
}
}
/* cmd now points at final component of path name */
/* allow a few shell builtins */
{
/* test _next_ arg */
q = ++p;
isexec = true;
continue;
}
{
/* test following chars */
}
else
{
/*
** Check to see if the command name is legal.
*/
{
/* too long */
"%s: \"%s\" not available for sendmail programs (filename too long)\n",
if (p != NULL)
*p = ' ';
#ifndef DEBUG
#endif /* ! DEBUG */
}
#ifdef DEBUG
"Trying %s\n", cmdbuf);
#endif /* DEBUG */
{
/* can't stat it */
"%s: \"%s\" not available for sendmail programs (stat failed)\n",
if (p != NULL)
*p = ' ';
#ifndef DEBUG
#endif /* ! DEBUG */
}
#ifdef S_ISLNK
#endif /* S_ISLNK */
)
{
/* can't stat it */
"%s: \"%s\" not available for sendmail programs (not a file)\n",
if (p != NULL)
*p = ' ';
#ifndef DEBUG
#endif /* ! DEBUG */
}
{
/* oops.... crack attack possiblity */
"%s: \"%s\" not available for sendmail programs\n",
if (p != NULL)
*p = ' ';
#ifndef DEBUG
#endif /* ! DEBUG */
}
/*
** Create the actual shell input.
*/
}
isexec = false;
if (p != NULL)
*p = ' ';
else
break;
r = strpbrk(p, specialbuf);
if (r == NULL)
{
break;
}
#if ALLOWSEMI
if (*r == ';')
{
addcmd(p, false, r - p + 1);
q = r + 1;
continue;
}
#endif /* ALLOWSEMI */
if ((*r == '&' && *(r + 1) == '&') ||
(*r == '|' && *(r + 1) == '|'))
{
addcmd(p, false, r - p + 2);
q = r + 2;
continue;
}
"%s: cannot use %c in command\n", prg, *r);
#ifndef DEBUG
#endif /* ! DEBUG */
}
if (isexec)
{
"%s: missing command to exec\n", prg);
#ifndef DEBUG
(int) getuid());
#endif /* ! DEBUG */
}
/* make sure we created something */
if (newcmdbuf[0] == '\0')
{
"Usage: %s -c command\n", prg);
#ifndef DEBUG
#endif /* ! DEBUG */
}
/*
** Now invoke the shell
*/
#ifdef DEBUG
#endif /* DEBUG */
save_errno = errno;
#ifndef DEBUG
#endif /* ! DEBUG */
errno = save_errno;
/* NOTREACHED */
return EX_OSFILE;
}