source: trunk/third/sendmail/smrsh/smrsh.c @ 12554

Revision 12554, 4.7 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12553, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1993 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)smrsh.c     8.11 (Berkeley) 5/19/1998";
15#endif /* not lint */
16
17/*
18**  SMRSH -- sendmail restricted shell
19**
20**      This is a patch to get around the prog mailer bugs in most
21**      versions of sendmail.
22**
23**      Use this in place of /bin/sh in the "prog" mailer definition
24**      in your sendmail.cf file.  You then create CMDDIR (owned by
25**      root, mode 755) and put links to any programs you want
26**      available to prog mailers in that directory.  This should
27**      include things like "vacation" and "procmail", but not "sed"
28**      or "sh".
29**
30**      Leading pathnames are stripped from program names so that
31**      existing .forward files that reference things like
32**      "/usr/ucb/vacation" will continue to work.
33**
34**      The following characters are completely illegal:
35**              <  >  |  ^  ;  &  $  `  (  ) \n \r
36**      This is more restrictive than strictly necessary.
37**
38**      To use this, edit /etc/sendmail.cf, search for ^Mprog, and
39**      change P=/bin/sh to P=/usr/local/etc/smrsh, where this compiled
40**      binary is installed /usr/local/etc/smrsh.
41**
42**      This can be used on any version of sendmail.
43**
44**      In loving memory of RTM.  11/02/93.
45*/
46
47#include <unistd.h>
48#include <stdio.h>
49#include <sys/file.h>
50#include <string.h>
51#include <ctype.h>
52#ifdef EX_OK
53# undef EX_OK
54#endif
55#include <sysexits.h>
56#include <syslog.h>
57#include <stdlib.h>
58
59/* directory in which all commands must reside */
60#ifndef CMDDIR
61# define CMDDIR         "/usr/adm/sm.bin"
62#endif
63
64/* characters disallowed in the shell "-c" argument */
65#define SPECIALS        "<|>^();&`$\r\n"
66
67/* default search path */
68#ifndef PATH
69# define PATH           "/bin:/usr/bin:/usr/ucb"
70#endif
71
72int
73main(argc, argv)
74        int argc;
75        char **argv;
76{
77        register char *p;
78        register char *q;
79        register char *cmd;
80        int i;
81        char *newenv[2];
82        char cmdbuf[1000];
83        char pathbuf[1000];
84
85#ifndef LOG_MAIL
86        openlog("smrsh", 0);
87#else
88        openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL);
89#endif
90
91        strcpy(pathbuf, "PATH=");
92        strcat(pathbuf, PATH);
93        newenv[0] = pathbuf;
94        newenv[1] = NULL;
95
96        /*
97        **  Do basic argv usage checking
98        */
99
100        if (argc != 3 || strcmp(argv[1], "-c") != 0)
101        {
102                fprintf(stderr, "Usage: %s -c command\n", argv[0]);
103                syslog(LOG_ERR, "usage");
104                exit(EX_USAGE);
105        }
106
107        /*
108        **  Disallow special shell syntax.  This is overly restrictive,
109        **  but it should shut down all attacks.
110        **  Be sure to include 8-bit versions, since many shells strip
111        **  the address to 7 bits before checking.
112        */
113
114        strcpy(cmdbuf, SPECIALS);
115        for (p = cmdbuf; *p != '\0'; p++)
116                *p |= '\200';
117        strcat(cmdbuf, SPECIALS);
118        p = strpbrk(argv[2], cmdbuf);
119        if (p != NULL)
120        {
121                fprintf(stderr, "%s: cannot use %c in command\n",
122                        argv[0], *p);
123                syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
124                        getuid(), *p, argv[2]);
125                exit(EX_UNAVAILABLE);
126        }
127
128        /*
129        **  Do a quick sanity check on command line length.
130        */
131
132        i = strlen(argv[2]);
133        if (i > (sizeof cmdbuf - sizeof CMDDIR - 2))
134        {
135                fprintf(stderr, "%s: command too long: %s\n", argv[0], argv[2]);
136                syslog(LOG_WARNING, "command too long: %.40s", argv[2]);
137                exit(EX_UNAVAILABLE);
138        }
139
140        /*
141        **  Strip off a leading pathname on the command name.  For
142        **  example, change /usr/ucb/vacation to vacation.
143        */
144
145        /* strip leading spaces */
146        for (q = argv[2]; *q != '\0' && isascii(*q) && isspace(*q); )
147                q++;
148
149        /* find the end of the command name */
150        p = strpbrk(q, " \t");
151        if (p == NULL)
152                cmd = &q[strlen(q)];
153        else
154        {
155                *p = '\0';
156                cmd = p;
157        }
158
159        /* search backwards for last / (allow for 0200 bit) */
160        while (cmd > q)
161        {
162                if ((*--cmd & 0177) == '/')
163                {
164                        cmd++;
165                        break;
166                }
167        }
168
169        /* cmd now points at final component of path name */
170
171        /*
172        **  Check to see if the command name is legal.
173        */
174
175        (void) strcpy(cmdbuf, CMDDIR);
176        (void) strcat(cmdbuf, "/");
177        (void) strcat(cmdbuf, cmd);
178#ifdef DEBUG
179        printf("Trying %s\n", cmdbuf);
180#endif
181        if (access(cmdbuf, X_OK) < 0)
182        {
183                /* oops....  crack attack possiblity */
184                fprintf(stderr, "%s: %s not available for sendmail programs\n",
185                        argv[0], cmd);
186                if (p != NULL)
187                        *p = ' ';
188                syslog(LOG_CRIT, "uid %d: attempt to use %s", getuid(), cmd);
189                exit(EX_UNAVAILABLE);
190        }
191        if (p != NULL)
192                *p = ' ';
193
194        /*
195        **  Create the actual shell input.
196        */
197
198        strcpy(cmdbuf, CMDDIR);
199        strcat(cmdbuf, "/");
200        strcat(cmdbuf, cmd);
201
202        /*
203        **  Now invoke the shell
204        */
205
206#ifdef DEBUG
207        printf("%s\n", cmdbuf);
208#endif
209        execle("/bin/sh", "/bin/sh", "-c", cmdbuf, NULL, newenv);
210        syslog(LOG_CRIT, "Cannot exec /bin/sh: %m");
211        perror("/bin/sh");
212        exit(EX_OSFILE);
213}
Note: See TracBrowser for help on using the repository browser.