1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1993 Eric P. Allman. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Copyright (c) 1993 6*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 7*7c478bd9Sstevel@tonic-gate * 8*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 9*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 10*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate */ 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include <sm/gen.h> 17*7c478bd9Sstevel@tonic-gate 18*7c478bd9Sstevel@tonic-gate SM_IDSTR(copyright, 19*7c478bd9Sstevel@tonic-gate "@(#) Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.\n\ 20*7c478bd9Sstevel@tonic-gate All rights reserved.\n\ 21*7c478bd9Sstevel@tonic-gate Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\ 22*7c478bd9Sstevel@tonic-gate Copyright (c) 1993\n\ 23*7c478bd9Sstevel@tonic-gate The Regents of the University of California. All rights reserved.\n") 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate SM_IDSTR(id, "@(#)$Id: smrsh.c,v 8.65 2004/08/06 18:54:22 ca Exp $") 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* 28*7c478bd9Sstevel@tonic-gate ** SMRSH -- sendmail restricted shell 29*7c478bd9Sstevel@tonic-gate ** 30*7c478bd9Sstevel@tonic-gate ** This is a patch to get around the prog mailer bugs in most 31*7c478bd9Sstevel@tonic-gate ** versions of sendmail. 32*7c478bd9Sstevel@tonic-gate ** 33*7c478bd9Sstevel@tonic-gate ** Use this in place of /bin/sh in the "prog" mailer definition 34*7c478bd9Sstevel@tonic-gate ** in your sendmail.cf file. You then create CMDDIR (owned by 35*7c478bd9Sstevel@tonic-gate ** root, mode 755) and put links to any programs you want 36*7c478bd9Sstevel@tonic-gate ** available to prog mailers in that directory. This should 37*7c478bd9Sstevel@tonic-gate ** include things like "vacation" and "procmail", but not "sed" 38*7c478bd9Sstevel@tonic-gate ** or "sh". 39*7c478bd9Sstevel@tonic-gate ** 40*7c478bd9Sstevel@tonic-gate ** Leading pathnames are stripped from program names so that 41*7c478bd9Sstevel@tonic-gate ** existing .forward files that reference things like 42*7c478bd9Sstevel@tonic-gate ** "/usr/bin/vacation" will continue to work. 43*7c478bd9Sstevel@tonic-gate ** 44*7c478bd9Sstevel@tonic-gate ** The following characters are completely illegal: 45*7c478bd9Sstevel@tonic-gate ** < > ^ & ` ( ) \n \r 46*7c478bd9Sstevel@tonic-gate ** The following characters are sometimes illegal: 47*7c478bd9Sstevel@tonic-gate ** | & 48*7c478bd9Sstevel@tonic-gate ** This is more restrictive than strictly necessary. 49*7c478bd9Sstevel@tonic-gate ** 50*7c478bd9Sstevel@tonic-gate ** To use this, add FEATURE(`smrsh') to your .mc file. 51*7c478bd9Sstevel@tonic-gate ** 52*7c478bd9Sstevel@tonic-gate ** This can be used on any version of sendmail. 53*7c478bd9Sstevel@tonic-gate ** 54*7c478bd9Sstevel@tonic-gate ** In loving memory of RTM. 11/02/93. 55*7c478bd9Sstevel@tonic-gate */ 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #include <unistd.h> 58*7c478bd9Sstevel@tonic-gate #include <sm/io.h> 59*7c478bd9Sstevel@tonic-gate #include <sm/limits.h> 60*7c478bd9Sstevel@tonic-gate #include <sm/string.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 64*7c478bd9Sstevel@tonic-gate #include <string.h> 65*7c478bd9Sstevel@tonic-gate #include <ctype.h> 66*7c478bd9Sstevel@tonic-gate #include <errno.h> 67*7c478bd9Sstevel@tonic-gate #ifdef EX_OK 68*7c478bd9Sstevel@tonic-gate # undef EX_OK 69*7c478bd9Sstevel@tonic-gate #endif /* EX_OK */ 70*7c478bd9Sstevel@tonic-gate #include <sysexits.h> 71*7c478bd9Sstevel@tonic-gate #include <syslog.h> 72*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate #include <sm/conf.h> 75*7c478bd9Sstevel@tonic-gate #include <sm/errstring.h> 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* directory in which all commands must reside */ 78*7c478bd9Sstevel@tonic-gate #ifndef CMDDIR 79*7c478bd9Sstevel@tonic-gate # ifdef SMRSH_CMDDIR 80*7c478bd9Sstevel@tonic-gate # define CMDDIR SMRSH_CMDDIR 81*7c478bd9Sstevel@tonic-gate # else /* SMRSH_CMDDIR */ 82*7c478bd9Sstevel@tonic-gate # define CMDDIR "/usr/adm/sm.bin" 83*7c478bd9Sstevel@tonic-gate # endif /* SMRSH_CMDDIR */ 84*7c478bd9Sstevel@tonic-gate #endif /* ! CMDDIR */ 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* characters disallowed in the shell "-c" argument */ 87*7c478bd9Sstevel@tonic-gate #define SPECIALS "<|>^();&`$\r\n" 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* default search path */ 90*7c478bd9Sstevel@tonic-gate #ifndef PATH 91*7c478bd9Sstevel@tonic-gate # ifdef SMRSH_PATH 92*7c478bd9Sstevel@tonic-gate # define PATH SMRSH_PATH 93*7c478bd9Sstevel@tonic-gate # else /* SMRSH_PATH */ 94*7c478bd9Sstevel@tonic-gate # define PATH "/bin:/usr/bin:/usr/ucb" 95*7c478bd9Sstevel@tonic-gate # endif /* SMRSH_PATH */ 96*7c478bd9Sstevel@tonic-gate #endif /* ! PATH */ 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate char newcmdbuf[1000]; 99*7c478bd9Sstevel@tonic-gate char *prg, *par; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate static void addcmd __P((char *, bool, size_t)); 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate /* 104*7c478bd9Sstevel@tonic-gate ** ADDCMD -- add a string to newcmdbuf, check for overflow 105*7c478bd9Sstevel@tonic-gate ** 106*7c478bd9Sstevel@tonic-gate ** Parameters: 107*7c478bd9Sstevel@tonic-gate ** s -- string to add 108*7c478bd9Sstevel@tonic-gate ** cmd -- it's a command: prepend CMDDIR/ 109*7c478bd9Sstevel@tonic-gate ** len -- length of string to add 110*7c478bd9Sstevel@tonic-gate ** 111*7c478bd9Sstevel@tonic-gate ** Side Effects: 112*7c478bd9Sstevel@tonic-gate ** changes newcmdbuf or exits with a failure. 113*7c478bd9Sstevel@tonic-gate ** 114*7c478bd9Sstevel@tonic-gate */ 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate static void 117*7c478bd9Sstevel@tonic-gate addcmd(s, cmd, len) 118*7c478bd9Sstevel@tonic-gate char *s; 119*7c478bd9Sstevel@tonic-gate bool cmd; 120*7c478bd9Sstevel@tonic-gate size_t len; 121*7c478bd9Sstevel@tonic-gate { 122*7c478bd9Sstevel@tonic-gate if (s == NULL || *s == '\0') 123*7c478bd9Sstevel@tonic-gate return; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* enough space for s (len) and CMDDIR + "/" and '\0'? */ 126*7c478bd9Sstevel@tonic-gate if (sizeof newcmdbuf - strlen(newcmdbuf) <= 127*7c478bd9Sstevel@tonic-gate len + 1 + (cmd ? (strlen(CMDDIR) + 1) : 0)) 128*7c478bd9Sstevel@tonic-gate { 129*7c478bd9Sstevel@tonic-gate (void)sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 130*7c478bd9Sstevel@tonic-gate "%s: command too long: %s\n", prg, par); 131*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 132*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "command too long: %.40s", par); 133*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 134*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate if (cmd) 137*7c478bd9Sstevel@tonic-gate (void) sm_strlcat2(newcmdbuf, CMDDIR, "/", sizeof newcmdbuf); 138*7c478bd9Sstevel@tonic-gate (void) strncat(newcmdbuf, s, len); 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate int 142*7c478bd9Sstevel@tonic-gate main(argc, argv) 143*7c478bd9Sstevel@tonic-gate int argc; 144*7c478bd9Sstevel@tonic-gate char **argv; 145*7c478bd9Sstevel@tonic-gate { 146*7c478bd9Sstevel@tonic-gate register char *p; 147*7c478bd9Sstevel@tonic-gate register char *q; 148*7c478bd9Sstevel@tonic-gate register char *r; 149*7c478bd9Sstevel@tonic-gate register char *cmd; 150*7c478bd9Sstevel@tonic-gate int isexec; 151*7c478bd9Sstevel@tonic-gate int save_errno; 152*7c478bd9Sstevel@tonic-gate char *newenv[2]; 153*7c478bd9Sstevel@tonic-gate char pathbuf[1000]; 154*7c478bd9Sstevel@tonic-gate char specialbuf[32]; 155*7c478bd9Sstevel@tonic-gate struct stat st; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 158*7c478bd9Sstevel@tonic-gate # ifndef LOG_MAIL 159*7c478bd9Sstevel@tonic-gate openlog("smrsh", 0); 160*7c478bd9Sstevel@tonic-gate # else /* ! LOG_MAIL */ 161*7c478bd9Sstevel@tonic-gate openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL); 162*7c478bd9Sstevel@tonic-gate # endif /* ! LOG_MAIL */ 163*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(pathbuf, sizeof pathbuf, 2, "PATH=", PATH); 166*7c478bd9Sstevel@tonic-gate newenv[0] = pathbuf; 167*7c478bd9Sstevel@tonic-gate newenv[1] = NULL; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate /* 170*7c478bd9Sstevel@tonic-gate ** Do basic argv usage checking 171*7c478bd9Sstevel@tonic-gate */ 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate prg = argv[0]; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate if (argc != 3 || strcmp(argv[1], "-c") != 0) 176*7c478bd9Sstevel@tonic-gate { 177*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 178*7c478bd9Sstevel@tonic-gate "Usage: %s -c command\n", prg); 179*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 180*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "usage"); 181*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 182*7c478bd9Sstevel@tonic-gate exit(EX_USAGE); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate par = argv[2]; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate ** Disallow special shell syntax. This is overly restrictive, 189*7c478bd9Sstevel@tonic-gate ** but it should shut down all attacks. 190*7c478bd9Sstevel@tonic-gate ** Be sure to include 8-bit versions, since many shells strip 191*7c478bd9Sstevel@tonic-gate ** the address to 7 bits before checking. 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate if (strlen(SPECIALS) * 2 >= sizeof specialbuf) 195*7c478bd9Sstevel@tonic-gate { 196*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 197*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "too many specials: %.40s", SPECIALS); 198*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 199*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(specialbuf, SPECIALS, sizeof specialbuf); 202*7c478bd9Sstevel@tonic-gate for (p = specialbuf; *p != '\0'; p++) 203*7c478bd9Sstevel@tonic-gate *p |= '\200'; 204*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(specialbuf, SPECIALS, sizeof specialbuf); 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate ** Do a quick sanity check on command line length. 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate if (strlen(par) > (sizeof newcmdbuf - sizeof CMDDIR - 2)) 211*7c478bd9Sstevel@tonic-gate { 212*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 213*7c478bd9Sstevel@tonic-gate "%s: command too long: %s\n", prg, par); 214*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 215*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "command too long: %.40s", par); 216*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 217*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate q = par; 221*7c478bd9Sstevel@tonic-gate newcmdbuf[0] = '\0'; 222*7c478bd9Sstevel@tonic-gate isexec = false; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate while (*q != '\0') 225*7c478bd9Sstevel@tonic-gate { 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate ** Strip off a leading pathname on the command name. For 228*7c478bd9Sstevel@tonic-gate ** example, change /usr/ucb/vacation to vacation. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate /* strip leading spaces */ 232*7c478bd9Sstevel@tonic-gate while (*q != '\0' && isascii(*q) && isspace(*q)) 233*7c478bd9Sstevel@tonic-gate q++; 234*7c478bd9Sstevel@tonic-gate if (*q == '\0') 235*7c478bd9Sstevel@tonic-gate { 236*7c478bd9Sstevel@tonic-gate if (isexec) 237*7c478bd9Sstevel@tonic-gate { 238*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 239*7c478bd9Sstevel@tonic-gate "%s: missing command to exec\n", 240*7c478bd9Sstevel@tonic-gate prg); 241*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 242*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: missing command to exec", (int) getuid()); 243*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 244*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate break; 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* find the end of the command name */ 250*7c478bd9Sstevel@tonic-gate p = strpbrk(q, " \t"); 251*7c478bd9Sstevel@tonic-gate if (p == NULL) 252*7c478bd9Sstevel@tonic-gate cmd = &q[strlen(q)]; 253*7c478bd9Sstevel@tonic-gate else 254*7c478bd9Sstevel@tonic-gate { 255*7c478bd9Sstevel@tonic-gate *p = '\0'; 256*7c478bd9Sstevel@tonic-gate cmd = p; 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate /* search backwards for last / (allow for 0200 bit) */ 259*7c478bd9Sstevel@tonic-gate while (cmd > q) 260*7c478bd9Sstevel@tonic-gate { 261*7c478bd9Sstevel@tonic-gate if ((*--cmd & 0177) == '/') 262*7c478bd9Sstevel@tonic-gate { 263*7c478bd9Sstevel@tonic-gate cmd++; 264*7c478bd9Sstevel@tonic-gate break; 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate /* cmd now points at final component of path name */ 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* allow a few shell builtins */ 270*7c478bd9Sstevel@tonic-gate if (strcmp(q, "exec") == 0 && p != NULL) 271*7c478bd9Sstevel@tonic-gate { 272*7c478bd9Sstevel@tonic-gate addcmd("exec ", false, strlen("exec ")); 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* test _next_ arg */ 275*7c478bd9Sstevel@tonic-gate q = ++p; 276*7c478bd9Sstevel@tonic-gate isexec = true; 277*7c478bd9Sstevel@tonic-gate continue; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0) 280*7c478bd9Sstevel@tonic-gate { 281*7c478bd9Sstevel@tonic-gate addcmd(cmd, false, strlen(cmd)); 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate /* test following chars */ 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate else 286*7c478bd9Sstevel@tonic-gate { 287*7c478bd9Sstevel@tonic-gate char cmdbuf[MAXPATHLEN]; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate /* 290*7c478bd9Sstevel@tonic-gate ** Check to see if the command name is legal. 291*7c478bd9Sstevel@tonic-gate */ 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate if (sm_strlcpyn(cmdbuf, sizeof cmdbuf, 3, CMDDIR, 294*7c478bd9Sstevel@tonic-gate "/", cmd) >= sizeof cmdbuf) 295*7c478bd9Sstevel@tonic-gate { 296*7c478bd9Sstevel@tonic-gate /* too long */ 297*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 298*7c478bd9Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs (filename too long)\n", 299*7c478bd9Sstevel@tonic-gate prg, cmd); 300*7c478bd9Sstevel@tonic-gate if (p != NULL) 301*7c478bd9Sstevel@tonic-gate *p = ' '; 302*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 303*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (filename too long)", 304*7c478bd9Sstevel@tonic-gate (int) getuid(), cmd); 305*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 306*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 310*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 311*7c478bd9Sstevel@tonic-gate "Trying %s\n", cmdbuf); 312*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 313*7c478bd9Sstevel@tonic-gate if (stat(cmdbuf, &st) < 0) 314*7c478bd9Sstevel@tonic-gate { 315*7c478bd9Sstevel@tonic-gate /* can't stat it */ 316*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 317*7c478bd9Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs (stat failed)\n", 318*7c478bd9Sstevel@tonic-gate prg, cmd); 319*7c478bd9Sstevel@tonic-gate if (p != NULL) 320*7c478bd9Sstevel@tonic-gate *p = ' '; 321*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 322*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (stat failed)", 323*7c478bd9Sstevel@tonic-gate (int) getuid(), cmd); 324*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 325*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate if (!S_ISREG(st.st_mode) 328*7c478bd9Sstevel@tonic-gate #ifdef S_ISLNK 329*7c478bd9Sstevel@tonic-gate && !S_ISLNK(st.st_mode) 330*7c478bd9Sstevel@tonic-gate #endif /* S_ISLNK */ 331*7c478bd9Sstevel@tonic-gate ) 332*7c478bd9Sstevel@tonic-gate { 333*7c478bd9Sstevel@tonic-gate /* can't stat it */ 334*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 335*7c478bd9Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs (not a file)\n", 336*7c478bd9Sstevel@tonic-gate prg, cmd); 337*7c478bd9Sstevel@tonic-gate if (p != NULL) 338*7c478bd9Sstevel@tonic-gate *p = ' '; 339*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 340*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (not a file)", 341*7c478bd9Sstevel@tonic-gate (int) getuid(), cmd); 342*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 343*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate if (access(cmdbuf, X_OK) < 0) 346*7c478bd9Sstevel@tonic-gate { 347*7c478bd9Sstevel@tonic-gate /* oops.... crack attack possiblity */ 348*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 349*7c478bd9Sstevel@tonic-gate "%s: \"%s\" not available for sendmail programs\n", 350*7c478bd9Sstevel@tonic-gate prg, cmd); 351*7c478bd9Sstevel@tonic-gate if (p != NULL) 352*7c478bd9Sstevel@tonic-gate *p = ' '; 353*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 354*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use \"%s\"", 355*7c478bd9Sstevel@tonic-gate (int) getuid(), cmd); 356*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 357*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate /* 361*7c478bd9Sstevel@tonic-gate ** Create the actual shell input. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate addcmd(cmd, true, strlen(cmd)); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate isexec = false; 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (p != NULL) 369*7c478bd9Sstevel@tonic-gate *p = ' '; 370*7c478bd9Sstevel@tonic-gate else 371*7c478bd9Sstevel@tonic-gate break; 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate r = strpbrk(p, specialbuf); 374*7c478bd9Sstevel@tonic-gate if (r == NULL) 375*7c478bd9Sstevel@tonic-gate { 376*7c478bd9Sstevel@tonic-gate addcmd(p, false, strlen(p)); 377*7c478bd9Sstevel@tonic-gate break; 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate #if ALLOWSEMI 380*7c478bd9Sstevel@tonic-gate if (*r == ';') 381*7c478bd9Sstevel@tonic-gate { 382*7c478bd9Sstevel@tonic-gate addcmd(p, false, r - p + 1); 383*7c478bd9Sstevel@tonic-gate q = r + 1; 384*7c478bd9Sstevel@tonic-gate continue; 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate #endif /* ALLOWSEMI */ 387*7c478bd9Sstevel@tonic-gate if ((*r == '&' && *(r + 1) == '&') || 388*7c478bd9Sstevel@tonic-gate (*r == '|' && *(r + 1) == '|')) 389*7c478bd9Sstevel@tonic-gate { 390*7c478bd9Sstevel@tonic-gate addcmd(p, false, r - p + 2); 391*7c478bd9Sstevel@tonic-gate q = r + 2; 392*7c478bd9Sstevel@tonic-gate continue; 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 396*7c478bd9Sstevel@tonic-gate "%s: cannot use %c in command\n", prg, *r); 397*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 398*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s", 399*7c478bd9Sstevel@tonic-gate (int) getuid(), *r, par); 400*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 401*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate if (isexec) 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 406*7c478bd9Sstevel@tonic-gate "%s: missing command to exec\n", prg); 407*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 408*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "uid %d: missing command to exec", 409*7c478bd9Sstevel@tonic-gate (int) getuid()); 410*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 411*7c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate /* make sure we created something */ 414*7c478bd9Sstevel@tonic-gate if (newcmdbuf[0] == '\0') 415*7c478bd9Sstevel@tonic-gate { 416*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 417*7c478bd9Sstevel@tonic-gate "Usage: %s -c command\n", prg); 418*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 419*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "usage"); 420*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 421*7c478bd9Sstevel@tonic-gate exit(EX_USAGE); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* 425*7c478bd9Sstevel@tonic-gate ** Now invoke the shell 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 429*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", newcmdbuf); 430*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 431*7c478bd9Sstevel@tonic-gate (void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf, 432*7c478bd9Sstevel@tonic-gate (char *)NULL, newenv); 433*7c478bd9Sstevel@tonic-gate save_errno = errno; 434*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 435*7c478bd9Sstevel@tonic-gate syslog(LOG_CRIT, "Cannot exec /bin/sh: %s", sm_errstring(errno)); 436*7c478bd9Sstevel@tonic-gate #endif /* ! DEBUG */ 437*7c478bd9Sstevel@tonic-gate errno = save_errno; 438*7c478bd9Sstevel@tonic-gate sm_perror("/bin/sh"); 439*7c478bd9Sstevel@tonic-gate exit(EX_OSFILE); 440*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 441*7c478bd9Sstevel@tonic-gate return EX_OSFILE; 442*7c478bd9Sstevel@tonic-gate } 443