smrsh.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:8k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1993 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #ifndef lint
  14. static char copyright[] =
  15. "@(#) Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.n
  16. All rights reserved.n
  17.      Copyright (c) 1993 Eric P. Allman.  All rights reserved.n
  18.      Copyright (c) 1993n
  19. The Regents of the University of California.  All rights reserved.n";
  20. #endif /* ! lint */
  21. #ifndef lint
  22. static char id[] = "@(#)$Id: smrsh.c,v 8.28 1999/10/26 16:11:32 ca Exp $";
  23. #endif /* ! lint */
  24. /*
  25. **  SMRSH -- sendmail restricted shell
  26. **
  27. ** This is a patch to get around the prog mailer bugs in most
  28. ** versions of sendmail.
  29. **
  30. ** Use this in place of /bin/sh in the "prog" mailer definition
  31. ** in your sendmail.cf file.  You then create CMDDIR (owned by
  32. ** root, mode 755) and put links to any programs you want
  33. ** available to prog mailers in that directory.  This should
  34. ** include things like "vacation" and "procmail", but not "sed"
  35. ** or "sh".
  36. **
  37. ** Leading pathnames are stripped from program names so that
  38. ** existing .forward files that reference things like
  39. ** "/usr/ucb/vacation" will continue to work.
  40. **
  41. ** The following characters are completely illegal:
  42. ** <  >  ^  &  `  (  ) n r
  43. ** The following characters are sometimes illegal:
  44. ** |  &
  45. ** This is more restrictive than strictly necessary.
  46. **
  47. ** To use this, edit /etc/sendmail.cf, search for ^Mprog, and
  48. ** change P=/bin/sh to P=/usr/local/etc/smrsh, where this compiled
  49. ** binary is installed /usr/local/etc/smrsh.
  50. **
  51. ** This can be used on any version of sendmail.
  52. **
  53. ** In loving memory of RTM.  11/02/93.
  54. */
  55. #include <unistd.h>
  56. #include <stdio.h>
  57. #include <sys/file.h>
  58. #include <string.h>
  59. #include <ctype.h>
  60. #include <errno.h>
  61. #ifdef EX_OK
  62. # undef EX_OK
  63. #endif /* EX_OK */
  64. #include <sysexits.h>
  65. #include <syslog.h>
  66. #include <stdlib.h>
  67. #ifndef TRUE
  68. # define TRUE 1
  69. # define FALSE 0
  70. #endif /* ! TRUE */
  71. /* directory in which all commands must reside */
  72. #ifndef CMDDIR
  73. # define CMDDIR "/usr/adm/sm.bin"
  74. #endif /* ! CMDDIR */
  75. /* characters disallowed in the shell "-c" argument */
  76. #define SPECIALS "<|>^();&`$rn"
  77. /* default search path */
  78. #ifndef PATH
  79. # define PATH "/bin:/usr/bin:/usr/ucb"
  80. #endif /* ! PATH */
  81. #ifndef __P
  82. # include "sendmail/cdefs.h"
  83. #endif /* ! __P */
  84. extern size_t strlcpy __P((char *, const char *, size_t));
  85. extern size_t strlcat __P((char *, const char *, size_t));
  86. char newcmdbuf[1000];
  87. char *prg, *par;
  88. /*
  89. **  ADDCMD -- add a string to newcmdbuf, check for overflow
  90. **
  91. **    Parameters:
  92. ** s -- string to add
  93. ** cmd -- it's a command: prepend CMDDIR/
  94. ** len -- length of string to add
  95. **
  96. **    Side Effects:
  97. ** changes newcmdbuf or exits with a failure.
  98. **
  99. */
  100. void
  101. addcmd(s, cmd, len)
  102. char *s;
  103. int cmd;
  104. int len;
  105. {
  106. if (s == NULL || *s == '')
  107. return;
  108. if (sizeof newcmdbuf - strlen(newcmdbuf) <=
  109.     len + (cmd ? (strlen(CMDDIR) + 1) : 0))
  110. {
  111. fprintf(stderr, "%s: command too long: %sn", prg, par);
  112. #ifndef DEBUG
  113. syslog(LOG_WARNING, "command too long: %.40s", par);
  114. #endif /* ! DEBUG */
  115. exit(EX_UNAVAILABLE);
  116. }
  117. if (cmd)
  118. {
  119. (void) strlcat(newcmdbuf, CMDDIR, sizeof newcmdbuf);
  120. (void) strlcat(newcmdbuf, "/", sizeof newcmdbuf);
  121. }
  122. (void) strlcat(newcmdbuf, s, sizeof newcmdbuf);
  123. }
  124. int
  125. main(argc, argv)
  126. int argc;
  127. char **argv;
  128. {
  129. register char *p;
  130. register char *q;
  131. register char *r;
  132. register char *cmd;
  133. int i;
  134. int isexec;
  135. int save_errno;
  136. char *newenv[2];
  137. char cmdbuf[1000];
  138. char pathbuf[1000];
  139. char specialbuf[32];
  140. #ifndef DEBUG
  141. # ifndef LOG_MAIL
  142. openlog("smrsh", 0);
  143. # else /* ! LOG_MAIL */
  144. openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL);
  145. # endif /* ! LOG_MAIL */
  146. #endif /* ! DEBUG */
  147. (void) strlcpy(pathbuf, "PATH=", sizeof pathbuf);
  148. (void) strlcat(pathbuf, PATH, sizeof pathbuf);
  149. newenv[0] = pathbuf;
  150. newenv[1] = NULL;
  151. /*
  152. **  Do basic argv usage checking
  153. */
  154. prg = argv[0];
  155. par = argv[2];
  156. if (argc != 3 || strcmp(argv[1], "-c") != 0)
  157. {
  158. fprintf(stderr, "Usage: %s -c commandn", prg);
  159. #ifndef DEBUG
  160. syslog(LOG_ERR, "usage");
  161. #endif /* ! DEBUG */
  162. exit(EX_USAGE);
  163. }
  164. /*
  165. **  Disallow special shell syntax.  This is overly restrictive,
  166. **  but it should shut down all attacks.
  167. **  Be sure to include 8-bit versions, since many shells strip
  168. **  the address to 7 bits before checking.
  169. */
  170. if (strlen(SPECIALS) * 2 >= sizeof specialbuf)
  171. {
  172. #ifndef DEBUG
  173. syslog(LOG_ERR, "too many specials: %.40s", SPECIALS);
  174. #endif /* ! DEBUG */
  175. exit(EX_UNAVAILABLE);
  176. }
  177. (void) strlcpy(specialbuf, SPECIALS, sizeof specialbuf);
  178. for (p = specialbuf; *p != ''; p++)
  179. *p |= '200';
  180. (void) strlcat(specialbuf, SPECIALS, sizeof specialbuf);
  181. /*
  182. **  Do a quick sanity check on command line length.
  183. */
  184. i = strlen(par);
  185. if (i > (sizeof newcmdbuf - sizeof CMDDIR - 2))
  186. {
  187. fprintf(stderr, "%s: command too long: %sn", prg, par);
  188. #ifndef DEBUG
  189. syslog(LOG_WARNING, "command too long: %.40s", par);
  190. #endif /* ! DEBUG */
  191. exit(EX_UNAVAILABLE);
  192. }
  193. q = par;
  194. newcmdbuf[0] = '';
  195. isexec = FALSE;
  196. while (*q)
  197. {
  198. /*
  199. **  Strip off a leading pathname on the command name.  For
  200. **  example, change /usr/ucb/vacation to vacation.
  201. */
  202. /* strip leading spaces */
  203. while (*q != '' && isascii(*q) && isspace(*q))
  204. q++;
  205. if (*q == '')
  206. {
  207. if (isexec)
  208. {
  209. fprintf(stderr, "%s: missing command to execn",
  210. prg);
  211. #ifndef DEBUG
  212. syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
  213. #endif /* ! DEBUG */
  214. exit(EX_UNAVAILABLE);
  215. }
  216. break;
  217. }
  218. /* find the end of the command name */
  219. p = strpbrk(q, " t");
  220. if (p == NULL)
  221. cmd = &q[strlen(q)];
  222. else
  223. {
  224. *p = '';
  225. cmd = p;
  226. }
  227. /* search backwards for last / (allow for 0200 bit) */
  228. while (cmd > q)
  229. {
  230. if ((*--cmd & 0177) == '/')
  231. {
  232. cmd++;
  233. break;
  234. }
  235. }
  236. /* cmd now points at final component of path name */
  237. /* allow a few shell builtins */
  238. if (strcmp(q, "exec") == 0 && p != NULL)
  239. {
  240. addcmd("exec ", FALSE, strlen("exec "));
  241. /* test _next_ arg */
  242. q = ++p;
  243. isexec = TRUE;
  244. continue;
  245. }
  246. else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0)
  247. {
  248. addcmd(cmd, FALSE, strlen(cmd));
  249. /* test following chars */
  250. }
  251. else
  252. {
  253. /*
  254. **  Check to see if the command name is legal.
  255. */
  256. (void) strlcpy(cmdbuf, CMDDIR, sizeof cmdbuf);
  257. (void) strlcat(cmdbuf, "/", sizeof cmdbuf);
  258. (void) strlcat(cmdbuf, cmd, sizeof cmdbuf);
  259. #ifdef DEBUG
  260. printf("Trying %sn", cmdbuf);
  261. #endif /* DEBUG */
  262. if (access(cmdbuf, X_OK) < 0)
  263. {
  264. /* oops....  crack attack possiblity */
  265. fprintf(stderr,
  266. "%s: %s not available for sendmail programsn",
  267. prg, cmd);
  268. if (p != NULL)
  269. *p = ' ';
  270. #ifndef DEBUG
  271. syslog(LOG_CRIT, "uid %d: attempt to use %s",
  272.        getuid(), cmd);
  273. #endif /* ! DEBUG */
  274. exit(EX_UNAVAILABLE);
  275. }
  276. /*
  277. **  Create the actual shell input.
  278. */
  279. addcmd(cmd, TRUE, strlen(cmd));
  280. }
  281. isexec = FALSE;
  282. if (p != NULL)
  283. *p = ' ';
  284. else
  285. break;
  286. r = strpbrk(p, specialbuf);
  287. if (r == NULL) {
  288. addcmd(p, FALSE, strlen(p));
  289. break;
  290. }
  291. #if ALLOWSEMI
  292. if (*r == ';') {
  293. addcmd(p, FALSE,  r - p + 1);
  294. q = r + 1;
  295. continue;
  296. }
  297. #endif /* ALLOWSEMI */
  298. if ((*r == '&' && *(r + 1) == '&') ||
  299.     (*r == '|' && *(r + 1) == '|'))
  300. {
  301. addcmd(p, FALSE,  r - p + 2);
  302. q = r + 2;
  303. continue;
  304. }
  305. fprintf(stderr, "%s: cannot use %c in commandn", prg, *r);
  306. #ifndef DEBUG
  307. syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
  308. getuid(), *r, par);
  309. #endif /* ! DEBUG */
  310. exit(EX_UNAVAILABLE);
  311. } /* end of while *q */
  312. if (isexec)
  313. {
  314. fprintf(stderr, "%s: missing command to execn", prg);
  315. #ifndef DEBUG
  316. syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
  317. #endif /* ! DEBUG */
  318. exit(EX_UNAVAILABLE);
  319. }
  320. /* make sure we created something */
  321. if (newcmdbuf[0] == '')
  322. {
  323. fprintf(stderr, "Usage: %s -c commandn", prg);
  324. #ifndef DEBUG
  325. syslog(LOG_ERR, "usage");
  326. #endif /* ! DEBUG */
  327. exit(EX_USAGE);
  328. }
  329. /*
  330. **  Now invoke the shell
  331. */
  332. #ifdef DEBUG
  333. printf("%sn", newcmdbuf);
  334. #endif /* DEBUG */
  335. (void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf, NULL, newenv);
  336. save_errno = errno;
  337. #ifndef DEBUG
  338. syslog(LOG_CRIT, "Cannot exec /bin/sh: %m");
  339. #endif /* ! DEBUG */
  340. errno = save_errno;
  341. perror("/bin/sh");
  342. exit(EX_OSFILE);
  343. /* NOTREACHED */
  344. return EX_OSFILE;
  345. }