diff options
author | gshapiro <gshapiro@FreeBSD.org> | 2000-08-12 21:55:49 +0000 |
---|---|---|
committer | gshapiro <gshapiro@FreeBSD.org> | 2000-08-12 21:55:49 +0000 |
commit | 4332139a9a11f773ffe5109bed871561e3c290a1 (patch) | |
tree | 6d207932926718f38869bd08959330c09f4f3e0d /contrib/sendmail/smrsh/smrsh.c | |
parent | a392fe0bdb7081117c445f5dcc98d5ed4013dc17 (diff) | |
download | FreeBSD-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.c | 330 |
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; } |