smrsh.c revision 38081
138032Speter/* 238032Speter * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 338032Speter * Copyright (c) 1993 Eric P. Allman. All rights reserved. 438032Speter * Copyright (c) 1993 538032Speter * The Regents of the University of California. All rights reserved. 638032Speter * 738032Speter * By using this file, you agree to the terms and conditions set 838032Speter * forth in the LICENSE file which can be found at the top level of 938032Speter * the sendmail distribution. 1038032Speter * 1138032Speter */ 1238032Speter 1338032Speter#ifndef lint 1438032Speterstatic char sccsid[] = "@(#)smrsh.c 8.11 (Berkeley) 5/19/98"; 1538032Speter#endif /* not lint */ 1638032Speter 1738032Speter/* 1838032Speter** SMRSH -- sendmail restricted shell 1938032Speter** 2038032Speter** This is a patch to get around the prog mailer bugs in most 2138032Speter** versions of sendmail. 2238032Speter** 2338032Speter** Use this in place of /bin/sh in the "prog" mailer definition 2438032Speter** in your sendmail.cf file. You then create CMDDIR (owned by 2538032Speter** root, mode 755) and put links to any programs you want 2638032Speter** available to prog mailers in that directory. This should 2738032Speter** include things like "vacation" and "procmail", but not "sed" 2838032Speter** or "sh". 2938032Speter** 3038032Speter** Leading pathnames are stripped from program names so that 3138032Speter** existing .forward files that reference things like 3238081Speter** "/usr/bin/vacation" will continue to work. 3338032Speter** 3438032Speter** The following characters are completely illegal: 3538032Speter** < > | ^ ; & $ ` ( ) \n \r 3638032Speter** This is more restrictive than strictly necessary. 3738032Speter** 3838032Speter** To use this, edit /etc/sendmail.cf, search for ^Mprog, and 3938081Speter** change P=/bin/sh to P=/usr/libexec/smrsh, where this compiled 4038081Speter** binary is installed /usr/libexec/smrsh. 4138032Speter** 4238032Speter** This can be used on any version of sendmail. 4338032Speter** 4438032Speter** In loving memory of RTM. 11/02/93. 4538032Speter*/ 4638032Speter 4738032Speter#include <unistd.h> 4838032Speter#include <stdio.h> 4938032Speter#include <sys/file.h> 5038032Speter#include <string.h> 5138032Speter#include <ctype.h> 5238032Speter#ifdef EX_OK 5338032Speter# undef EX_OK 5438032Speter#endif 5538032Speter#include <sysexits.h> 5638032Speter#include <syslog.h> 5738032Speter#include <stdlib.h> 5838032Speter 5938032Speter/* directory in which all commands must reside */ 6038032Speter#ifndef CMDDIR 6138081Speter# define CMDDIR "/usr/libexec/sm.bin" 6238032Speter#endif 6338032Speter 6438032Speter/* characters disallowed in the shell "-c" argument */ 6538032Speter#define SPECIALS "<|>^();&`$\r\n" 6638032Speter 6738032Speter/* default search path */ 6838032Speter#ifndef PATH 6938081Speter# define PATH "/bin:/usr/bin" 7038032Speter#endif 7138032Speter 7238032Speterint 7338032Spetermain(argc, argv) 7438032Speter int argc; 7538032Speter char **argv; 7638032Speter{ 7738032Speter register char *p; 7838032Speter register char *q; 7938032Speter register char *cmd; 8038032Speter int i; 8138032Speter char *newenv[2]; 8238032Speter char cmdbuf[1000]; 8338032Speter char pathbuf[1000]; 8438032Speter 8538032Speter#ifndef LOG_MAIL 8638032Speter openlog("smrsh", 0); 8738032Speter#else 8838032Speter openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL); 8938032Speter#endif 9038032Speter 9138032Speter strcpy(pathbuf, "PATH="); 9238032Speter strcat(pathbuf, PATH); 9338032Speter newenv[0] = pathbuf; 9438032Speter newenv[1] = NULL; 9538032Speter 9638032Speter /* 9738032Speter ** Do basic argv usage checking 9838032Speter */ 9938032Speter 10038032Speter if (argc != 3 || strcmp(argv[1], "-c") != 0) 10138032Speter { 10238032Speter fprintf(stderr, "Usage: %s -c command\n", argv[0]); 10338032Speter syslog(LOG_ERR, "usage"); 10438032Speter exit(EX_USAGE); 10538032Speter } 10638032Speter 10738032Speter /* 10838032Speter ** Disallow special shell syntax. This is overly restrictive, 10938032Speter ** but it should shut down all attacks. 11038032Speter ** Be sure to include 8-bit versions, since many shells strip 11138032Speter ** the address to 7 bits before checking. 11238032Speter */ 11338032Speter 11438032Speter strcpy(cmdbuf, SPECIALS); 11538032Speter for (p = cmdbuf; *p != '\0'; p++) 11638032Speter *p |= '\200'; 11738032Speter strcat(cmdbuf, SPECIALS); 11838032Speter p = strpbrk(argv[2], cmdbuf); 11938032Speter if (p != NULL) 12038032Speter { 12138032Speter fprintf(stderr, "%s: cannot use %c in command\n", 12238032Speter argv[0], *p); 12338032Speter syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s", 12438032Speter getuid(), *p, argv[2]); 12538032Speter exit(EX_UNAVAILABLE); 12638032Speter } 12738032Speter 12838032Speter /* 12938032Speter ** Do a quick sanity check on command line length. 13038032Speter */ 13138032Speter 13238032Speter i = strlen(argv[2]); 13338032Speter if (i > (sizeof cmdbuf - sizeof CMDDIR - 2)) 13438032Speter { 13538032Speter fprintf(stderr, "%s: command too long: %s\n", argv[0], argv[2]); 13638032Speter syslog(LOG_WARNING, "command too long: %.40s", argv[2]); 13738032Speter exit(EX_UNAVAILABLE); 13838032Speter } 13938032Speter 14038032Speter /* 14138032Speter ** Strip off a leading pathname on the command name. For 14238032Speter ** example, change /usr/ucb/vacation to vacation. 14338032Speter */ 14438032Speter 14538032Speter /* strip leading spaces */ 14638032Speter for (q = argv[2]; *q != '\0' && isascii(*q) && isspace(*q); ) 14738032Speter q++; 14838032Speter 14938032Speter /* find the end of the command name */ 15038032Speter p = strpbrk(q, " \t"); 15138032Speter if (p == NULL) 15238032Speter cmd = &q[strlen(q)]; 15338032Speter else 15438032Speter { 15538032Speter *p = '\0'; 15638032Speter cmd = p; 15738032Speter } 15838032Speter 15938032Speter /* search backwards for last / (allow for 0200 bit) */ 16038032Speter while (cmd > q) 16138032Speter { 16238032Speter if ((*--cmd & 0177) == '/') 16338032Speter { 16438032Speter cmd++; 16538032Speter break; 16638032Speter } 16738032Speter } 16838032Speter 16938032Speter /* cmd now points at final component of path name */ 17038032Speter 17138032Speter /* 17238032Speter ** Check to see if the command name is legal. 17338032Speter */ 17438032Speter 17538032Speter (void) strcpy(cmdbuf, CMDDIR); 17638032Speter (void) strcat(cmdbuf, "/"); 17738032Speter (void) strcat(cmdbuf, cmd); 17838032Speter#ifdef DEBUG 17938032Speter printf("Trying %s\n", cmdbuf); 18038032Speter#endif 18138032Speter if (access(cmdbuf, X_OK) < 0) 18238032Speter { 18338032Speter /* oops.... crack attack possiblity */ 18438032Speter fprintf(stderr, "%s: %s not available for sendmail programs\n", 18538032Speter argv[0], cmd); 18638032Speter if (p != NULL) 18738032Speter *p = ' '; 18838032Speter syslog(LOG_CRIT, "uid %d: attempt to use %s", getuid(), cmd); 18938032Speter exit(EX_UNAVAILABLE); 19038032Speter } 19138032Speter if (p != NULL) 19238032Speter *p = ' '; 19338032Speter 19438032Speter /* 19538032Speter ** Create the actual shell input. 19638032Speter */ 19738032Speter 19838032Speter strcpy(cmdbuf, CMDDIR); 19938032Speter strcat(cmdbuf, "/"); 20038032Speter strcat(cmdbuf, cmd); 20138032Speter 20238032Speter /* 20338032Speter ** Now invoke the shell 20438032Speter */ 20538032Speter 20638032Speter#ifdef DEBUG 20738032Speter printf("%s\n", cmdbuf); 20838032Speter#endif 20938032Speter execle("/bin/sh", "/bin/sh", "-c", cmdbuf, NULL, newenv); 21038032Speter syslog(LOG_CRIT, "Cannot exec /bin/sh: %m"); 21138032Speter perror("/bin/sh"); 21238032Speter exit(EX_OSFILE); 21338032Speter} 214