The following code is a first attempt at a simple but flexible
suid wrapper which checks argv[] and environment. It might
introduce new security holes or have other bugs; using 1 as a
general failure exit value may be the wrong thing to do. The
wrapper reads a configuration file named /etc/wrapper.cfg; see
the comments in wrapper.c for the file''s format.
Flame, comment, or use at will.
tlr
------------------------------ wrapper.c ------------------------------
/*
* wrapper.c (c) 1997 Thomas Roessler <roessler@guug.de>
* $Id: wrapper.c,v 1.2 1997/05/26 17:39:09 roessler Exp $
*
* This program is free software. You may use, modify or distribute it
* at will as long as you give credit to the original author.
*
* format of /etc/wrapper.cfg:
* - leading white space is ignored.
* - lines starting with a hash sign (#) are ignored.
* - empty lines are ignored.
*
* Each line consists of three whitespace-separated fields:
* <program> <what> <size>
*
* <program> is the real path name as compiled into the wrapper as
REALPROG,
* <what> can either be the string "argv", a $ sign followed by
the name
* of an environment variable or a $ sign followed by an asterisk
* to match all environment variables passed to the program.
*
* Sample:
*
* /usr/X11R6/bin/xterm argv 1024
* /usr/X11R6/bin/xterm $HOME 1024
* /usr/X11R6/bin/xterm $* 2048
*
* To wrap, e.g., xterm, move /usr/X11R6/bin/xterm to
* /usr/X11R6/bin/xterm.wrapped, compile this wrapper by typing
* cc -DREALPROG=\"/usr/X11R6/bin/xterm\" wrapper.c -o xterm,
* and move it to /usr/X11R6/bin/xterm. Don''t forget to remove
* the suid bits from the wrapped program and to add them to the
* wrapper!
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <syslog.h>
#include <unistd.h>
#define BUFFSIZE 1024
#define CFGFILE "/etc/wrapper.cfg"
extern char **environ;
void syntax(const char *s)
{
syslog(LOG_ERR, "WRAPPER: error in %s: %s.", CFGFILE, s);
fprintf(stderr, "Syntax error in %s. Please notify the system\n"
"administration.\n", CFGFILE);
}
int main(int argc, char *argv[])
{
FILE *cfgfile;
char buff[BUFFSIZE];
char *f = NULL;
char *s;
char *t;
char *u;
char *key;
char *value;
char **e;
size_t len;
int i;
openlog(argv[0], 0, LOG_AUTHPRIV);
if(!(cfgfile = fopen(CFGFILE, "r"))) {
syslog(LOG_ERR, "WRAPPER: Can''t open %s: %m.", CFGFILE);
exit(1);
}
while(fgets(buff, sizeof(buff), cfgfile)) {
if(!(s = strchr(buff, ''\n''))) {
syntax("Long line.");
exit(1);
}
*s = ''\0'';
/* ignore leading whitespace */
for(s = buff; *s && isspace(*s); s++)
;
if(*s == ''\0'' || *s == ''#'')
continue;
if(!(s = strtok(s, " \t"))) {
syntax("Syntax error.");
exit(1);
}
if(!strcmp(s, REALPROG)) {
if(!(s = strtok(NULL, " \t")) || !(t = strtok(NULL, "
\t"))) {
syntax("Syntax error.");
exit(1);
}
len = strtoul(t, NULL, 0);
if(!len) {
syntax("Bad number.");
exit(1);
}
if(*s == ''$'') { /* environment variable */
s++;
for(e = environ; *e; e++) {
if((f = strdup(*e)) == NULL) {
syslog(LOG_ERR, "WRAPPER: Out of memory. %m.");
fprintf(stderr, "Out of memory.\n");
exit(1);
}
if(!(u = strchr(f, ''=''))) {
syslog(LOG_ALERT, "WRAPPER: Insane environment entry: %s.",
f);
exit(1);
}
key = f;
*u++ = ''\0'';
value = u;
if((*s == ''*'' || !strcmp(s, key)) && strlen(value)
> len) {
syslog(LOG_ALERT, "WRAPPER: $%s is too long.",
key);
exit(1);
}
free(f);
}
} else if(!strcasecmp(s, "argv")) { /* argument vector */
for(i = 0; i < argc; i++) {
if(strlen(argv[i]) > len) {
syslog(LOG_ALERT, "WRAPPER: Security violation: argument too
long."
"(uid = %d, euid = %d)",
(int) getuid(), (int) geteuid());
exit(1);
}
}
} else { /* syntax error */
syntax("Unknown check.");
exit(1);
}
}
}
fclose(cfgfile);
closelog();
execv(REALPROG ".wrapped", argv);
syslog(LOG_ERR, "WRAPPER: can''t exec %s: %m.",
REALPROG ".wrapped");
exit(1);
}
------------------------------ Makefile ------------------------------
SUID_PROGS=/usr/X11R6/bin/xterm
CFLAGS=-Wall -Wstrict-prototypes -pedantic
all: $(SUID_PROGS)
clean:
rm -f *~ *.o
for i in $(SUID_PROGS) ; do rm -f `basename $$i` ; done
$(SUID_PROGS): wrapper.c
$(CC) $(CFLAGS) -DREALPROG=\"$@\" -o `basename $@` $^
------------------------------ The End ------------------------------