summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/smrsh/smrsh.c
diff options
context:
space:
mode:
authorgshapiro <gshapiro@FreeBSD.org>2000-08-12 21:55:49 +0000
committergshapiro <gshapiro@FreeBSD.org>2000-08-12 21:55:49 +0000
commit4332139a9a11f773ffe5109bed871561e3c290a1 (patch)
tree6d207932926718f38869bd08959330c09f4f3e0d /contrib/sendmail/smrsh/smrsh.c
parenta392fe0bdb7081117c445f5dcc98d5ed4013dc17 (diff)
downloadFreeBSD-src-4332139a9a11f773ffe5109bed871561e3c290a1.zip
FreeBSD-src-4332139a9a11f773ffe5109bed871561e3c290a1.tar.gz
Import of sendmail version 8.11.0 into vendor branch SENDMAIL with
release tag v8_11_0. Obtained from: ftp://ftp.sendmail.org/pub/sendmail/
Diffstat (limited to 'contrib/sendmail/smrsh/smrsh.c')
-rw-r--r--contrib/sendmail/smrsh/smrsh.c330
1 files changed, 248 insertions, 82 deletions
diff --git a/contrib/sendmail/smrsh/smrsh.c b/contrib/sendmail/smrsh/smrsh.c
index d4af285..be48ab1 100644
--- a/contrib/sendmail/smrsh/smrsh.c
+++ b/contrib/sendmail/smrsh/smrsh.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
+ * Copyright (c) 1998-2000 Sendmail, 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.
@@ -11,8 +12,17 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)smrsh.c 8.11 (Berkeley) 5/19/1998";
-#endif /* not lint */
+static char copyright[] =
+"@(#) Copyright (c) 1998, 1999 Sendmail, 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";
+#endif /* ! lint */
+
+#ifndef lint
+static char id[] = "@(#)$Id: smrsh.c,v 8.31.4.4 2000/05/25 21:44:29 gshapiro Exp $";
+#endif /* ! lint */
/*
** SMRSH -- sendmail restricted shell
@@ -29,15 +39,15 @@ static char sccsid[] = "@(#)smrsh.c 8.11 (Berkeley) 5/19/1998";
**
** Leading pathnames are stripped from program names so that
** existing .forward files that reference things like
-** "/usr/ucb/vacation" will continue to work.
+** "/usr/bin/vacation" will continue to work.
**
** The following characters are completely illegal:
-** < > | ^ ; & $ ` ( ) \n \r
+** < > ^ & ` ( ) \n \r
+** The following characters are sometimes illegal:
+** | &
** This is more restrictive than strictly necessary.
**
-** To use this, edit /etc/sendmail.cf, search for ^Mprog, and
-** change P=/bin/sh to P=/usr/local/etc/smrsh, where this compiled
-** binary is installed /usr/local/etc/smrsh.
+** To use this, add FEATURE(`smrsh') to your .mc file.
**
** This can be used on any version of sendmail.
**
@@ -49,17 +59,23 @@ static char sccsid[] = "@(#)smrsh.c 8.11 (Berkeley) 5/19/1998";
#include <sys/file.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#ifdef EX_OK
# undef EX_OK
-#endif
+#endif /* EX_OK */
#include <sysexits.h>
#include <syslog.h>
#include <stdlib.h>
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif /* ! TRUE */
+
/* directory in which all commands must reside */
#ifndef CMDDIR
# define CMDDIR "/usr/adm/sm.bin"
-#endif
+#endif /* ! CMDDIR */
/* characters disallowed in the shell "-c" argument */
#define SPECIALS "<|>^();&`$\r\n"
@@ -67,7 +83,56 @@ static char sccsid[] = "@(#)smrsh.c 8.11 (Berkeley) 5/19/1998";
/* default search path */
#ifndef PATH
# define PATH "/bin:/usr/bin:/usr/ucb"
-#endif
+#endif /* ! PATH */
+
+#ifndef __P
+# include "sendmail/cdefs.h"
+#endif /* ! __P */
+
+extern size_t strlcpy __P((char *, const char *, size_t));
+extern size_t strlcat __P((char *, const char *, size_t));
+
+char newcmdbuf[1000];
+char *prg, *par;
+
+/*
+** 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.
+**
+*/
+
+void
+addcmd(s, cmd, len)
+ char *s;
+ int cmd;
+ int len;
+{
+ if (s == NULL || *s == '\0')
+ return;
+
+ if (sizeof newcmdbuf - strlen(newcmdbuf) <=
+ len + (cmd ? (strlen(CMDDIR) + 1) : 0))
+ {
+ fprintf(stderr, "%s: command too long: %s\n", prg, par);
+#ifndef DEBUG
+ syslog(LOG_WARNING, "command too long: %.40s", par);
+#endif /* ! DEBUG */
+ exit(EX_UNAVAILABLE);
+ }
+ if (cmd)
+ {
+ (void) strlcat(newcmdbuf, CMDDIR, sizeof newcmdbuf);
+ (void) strlcat(newcmdbuf, "/", sizeof newcmdbuf);
+ }
+ (void) strlcat(newcmdbuf, s, sizeof newcmdbuf);
+}
int
main(argc, argv)
@@ -76,20 +141,26 @@ main(argc, argv)
{
register char *p;
register char *q;
+ register char *r;
register char *cmd;
int i;
+ int isexec;
+ int save_errno;
char *newenv[2];
char cmdbuf[1000];
char pathbuf[1000];
+ char specialbuf[32];
-#ifndef LOG_MAIL
+#ifndef DEBUG
+# ifndef LOG_MAIL
openlog("smrsh", 0);
-#else
+# else /* ! LOG_MAIL */
openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL);
-#endif
+# endif /* ! LOG_MAIL */
+#endif /* ! DEBUG */
- strcpy(pathbuf, "PATH=");
- strcat(pathbuf, PATH);
+ (void) strlcpy(pathbuf, "PATH=", sizeof pathbuf);
+ (void) strlcat(pathbuf, PATH, sizeof pathbuf);
newenv[0] = pathbuf;
newenv[1] = NULL;
@@ -97,10 +168,15 @@ main(argc, argv)
** Do basic argv usage checking
*/
+ prg = argv[0];
+ par = argv[2];
+
if (argc != 3 || strcmp(argv[1], "-c") != 0)
{
- fprintf(stderr, "Usage: %s -c command\n", argv[0]);
+ fprintf(stderr, "Usage: %s -c command\n", prg);
+#ifndef DEBUG
syslog(LOG_ERR, "usage");
+#endif /* ! DEBUG */
exit(EX_USAGE);
}
@@ -111,103 +187,193 @@ main(argc, argv)
** the address to 7 bits before checking.
*/
- strcpy(cmdbuf, SPECIALS);
- for (p = cmdbuf; *p != '\0'; p++)
- *p |= '\200';
- strcat(cmdbuf, SPECIALS);
- p = strpbrk(argv[2], cmdbuf);
- if (p != NULL)
+ if (strlen(SPECIALS) * 2 >= sizeof specialbuf)
{
- fprintf(stderr, "%s: cannot use %c in command\n",
- argv[0], *p);
- syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
- getuid(), *p, argv[2]);
+#ifndef DEBUG
+ syslog(LOG_ERR, "too many specials: %.40s", SPECIALS);
+#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
+ (void) strlcpy(specialbuf, SPECIALS, sizeof specialbuf);
+ for (p = specialbuf; *p != '\0'; p++)
+ *p |= '\200';
+ (void) strlcat(specialbuf, SPECIALS, sizeof specialbuf);
/*
** Do a quick sanity check on command line length.
*/
- i = strlen(argv[2]);
- if (i > (sizeof cmdbuf - sizeof CMDDIR - 2))
+ i = strlen(par);
+ if (i > (sizeof newcmdbuf - sizeof CMDDIR - 2))
{
- fprintf(stderr, "%s: command too long: %s\n", argv[0], argv[2]);
- syslog(LOG_WARNING, "command too long: %.40s", argv[2]);
+ fprintf(stderr, "%s: command too long: %s\n", prg, par);
+#ifndef DEBUG
+ syslog(LOG_WARNING, "command too long: %.40s", par);
+#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
- /*
- ** Strip off a leading pathname on the command name. For
- ** example, change /usr/ucb/vacation to vacation.
- */
-
- /* strip leading spaces */
- for (q = argv[2]; *q != '\0' && isascii(*q) && isspace(*q); )
- q++;
+ q = par;
+ newcmdbuf[0] = '\0';
+ isexec = FALSE;
- /* find the end of the command name */
- p = strpbrk(q, " \t");
- if (p == NULL)
- cmd = &q[strlen(q)];
- else
+ while (*q)
{
- *p = '\0';
- cmd = p;
- }
+ /*
+ ** Strip off a leading pathname on the command name. For
+ ** example, change /usr/ucb/vacation to vacation.
+ */
- /* search backwards for last / (allow for 0200 bit) */
- while (cmd > q)
- {
- if ((*--cmd & 0177) == '/')
+ /* strip leading spaces */
+ while (*q != '\0' && isascii(*q) && isspace(*q))
+ q++;
+ if (*q == '\0')
{
- cmd++;
+ if (isexec)
+ {
+ fprintf(stderr, "%s: missing command to exec\n",
+ prg);
+#ifndef DEBUG
+ syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
+#endif /* ! DEBUG */
+ exit(EX_UNAVAILABLE);
+ }
break;
}
- }
-
- /* cmd now points at final component of path name */
- /*
- ** Check to see if the command name is legal.
- */
+ /* find the end of the command name */
+ p = strpbrk(q, " \t");
+ if (p == NULL)
+ cmd = &q[strlen(q)];
+ else
+ {
+ *p = '\0';
+ cmd = p;
+ }
+ /* search backwards for last / (allow for 0200 bit) */
+ while (cmd > q)
+ {
+ if ((*--cmd & 0177) == '/')
+ {
+ cmd++;
+ break;
+ }
+ }
+ /* cmd now points at final component of path name */
- (void) strcpy(cmdbuf, CMDDIR);
- (void) strcat(cmdbuf, "/");
- (void) strcat(cmdbuf, cmd);
+ /* allow a few shell builtins */
+ if (strcmp(q, "exec") == 0 && p != NULL)
+ {
+ addcmd("exec ", FALSE, strlen("exec "));
+ /* test _next_ arg */
+ q = ++p;
+ isexec = TRUE;
+ continue;
+ }
+ else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0)
+ {
+ addcmd(cmd, FALSE, strlen(cmd));
+ /* test following chars */
+ }
+ else
+ {
+ /*
+ ** Check to see if the command name is legal.
+ */
+ (void) strlcpy(cmdbuf, CMDDIR, sizeof cmdbuf);
+ (void) strlcat(cmdbuf, "/", sizeof cmdbuf);
+ (void) strlcat(cmdbuf, cmd, sizeof cmdbuf);
#ifdef DEBUG
- printf("Trying %s\n", cmdbuf);
-#endif
- if (access(cmdbuf, X_OK) < 0)
- {
- /* oops.... crack attack possiblity */
- fprintf(stderr, "%s: %s not available for sendmail programs\n",
- argv[0], cmd);
+ printf("Trying %s\n", cmdbuf);
+#endif /* DEBUG */
+ if (access(cmdbuf, X_OK) < 0)
+ {
+ /* oops.... crack attack possiblity */
+ fprintf(stderr,
+ "%s: %s not available for sendmail programs\n",
+ prg, cmd);
+ if (p != NULL)
+ *p = ' ';
+#ifndef DEBUG
+ syslog(LOG_CRIT, "uid %d: attempt to use %s",
+ getuid(), cmd);
+#endif /* ! DEBUG */
+ exit(EX_UNAVAILABLE);
+ }
+
+ /*
+ ** Create the actual shell input.
+ */
+
+ addcmd(cmd, TRUE, strlen(cmd));
+ }
+ isexec = FALSE;
+
if (p != NULL)
*p = ' ';
- syslog(LOG_CRIT, "uid %d: attempt to use %s", getuid(), cmd);
- exit(EX_UNAVAILABLE);
- }
- if (p != NULL)
- *p = ' ';
+ else
+ break;
- /*
- ** Create the actual shell input.
- */
+ r = strpbrk(p, specialbuf);
+ if (r == NULL) {
+ addcmd(p, FALSE, strlen(p));
+ 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;
+ }
- strcpy(cmdbuf, CMDDIR);
- strcat(cmdbuf, "/");
- strcat(cmdbuf, cmd);
+ fprintf(stderr, "%s: cannot use %c in command\n", prg, *r);
+#ifndef DEBUG
+ syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
+ getuid(), *r, par);
+#endif /* ! DEBUG */
+ exit(EX_UNAVAILABLE);
+ } /* end of while *q */
+ if (isexec)
+ {
+ fprintf(stderr, "%s: missing command to exec\n", prg);
+#ifndef DEBUG
+ syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
+#endif /* ! DEBUG */
+ exit(EX_UNAVAILABLE);
+ }
+ /* make sure we created something */
+ if (newcmdbuf[0] == '\0')
+ {
+ fprintf(stderr, "Usage: %s -c command\n", prg);
+#ifndef DEBUG
+ syslog(LOG_ERR, "usage");
+#endif /* ! DEBUG */
+ exit(EX_USAGE);
+ }
/*
** Now invoke the shell
*/
#ifdef DEBUG
- printf("%s\n", cmdbuf);
-#endif
- execle("/bin/sh", "/bin/sh", "-c", cmdbuf, NULL, newenv);
+ printf("%s\n", newcmdbuf);
+#endif /* DEBUG */
+ (void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf, NULL, newenv);
+ save_errno = errno;
+#ifndef DEBUG
syslog(LOG_CRIT, "Cannot exec /bin/sh: %m");
+#endif /* ! DEBUG */
+ errno = save_errno;
perror("/bin/sh");
exit(EX_OSFILE);
+ /* NOTREACHED */
+ return EX_OSFILE;
}
OpenPOWER on IntegriCloud