safe_exec.c - execute programs in a secure environment with a specific uid/gid/user and you can specify a program to be executed before the chroot.
a237a905c377b8cdf4065c45fb6568e482cec4b7ed56166967add7160a81033b
/* SAFE EXECUTION by lamagra <access-granted@geocities.com>
*
* Execute programs in a more secure environment, a chrooted environment.
* You can run daemons, shells, whatever inside a dir with some uid/gid
* When the program is exploited the attacker will be trapped inside that dir.
*
* http://lamagra.seKure.de
*/
#include <stdio.h>
#include <getopt.h>
#include <pwd.h>
#include <sys/stat.h>
#include <stdarg.h>
#define VERSION "v0.01"
extern char *optarg;
extern int optind, errno;
char opts[] = "?u:hg:p:l:i:";
static struct option opt_long[] =
{
{"uid",1,0,'u'},
{"user",1,0,'l'},
{"gid",1,0,'g'},
{"prog",1,0,'p'},
{"help",0,0,'?'},
{"init",1,0,'i'},
{0,0,0,0}
};
char *safe_env[] = {"HOME=/","PATH=/bin:.","SHELL=safe_env","PS1=[\\u@\\h \\W]\\$","TERM=linux",NULL};
fatal(char *msg, ...)
{
va_list ap;
va_start(ap,msg);
vprintf(msg,ap);
va_end(ap);
exit(-1);
}
void usage(char *name)
{
printf("Usage: %s [options] <dir>\n",name);
printf("Options:\n"
" --uid | -u: uid to change to\n"
" --gid | -g: gid to change to\n"
" --user | -l: user to change to\n"
" --init | -i: program to execute before chroot() and uid/gid change\n"
" --prog | -p: program to execute after chroot()\n"
" --help | -h | -?: this screen\n"
);
exit(-1);
}
int main(int argc,char **argv, char **env)
{
long uid = 0,gid = 0;
int optidx = 0, initexec = 0;
char ch;
struct passwd *pass;
char *program = "/bin/sh";
char *args[2];
printf("Safe execution %s by lamagra\n\n",VERSION);
while((ch = getopt_long(argc,argv,opts,opt_long,&optidx)) != EOF)
{
switch(ch)
{
case 'u': uid = atol(optarg);
break;
case 'g': gid = atol(optarg);
break;
case 'l': pass = getpwnam(optarg);
uid = pass->pw_uid;
gid = pass->pw_gid;
break;
case 'p': program = optarg;
break;
case 'i': initexec = 1;
args[0] = optarg; args[1] = NULL;
break;
case '?':
case 'h': usage(argv[0]); /* doesn't return */
}
}
if(!(argc - optind)) usage(argv[0]);
if(getuid() && geteuid()) fatal("You gotta be root, dude\n");
#ifdef SET_NOBODY
if(!uid || !gid)
{
pass = getpwnam("nobody");
if(!uid) uid = pass->pw_uid;
if(!gid) gid = pass->pw_gid;
}
#endif
printf("Executing %s in %s\nwith uid = %ld and gid = %ld\n",program,argv[optind],uid,gid);
if(chdir(argv[optind]) == -1)
fatal("changing file: %s\n",strerror(errno));
if(initexec)
{
if(!check_perms(args[0],uid,gid))
fatal("Bad perms on (initprogram) %s\n",args[0]);
else if(!fork())
{
execve(args[0],args,env);
fatal("execve <%s>: %s",args[0],strerror(errno));
}
wait(NULL);
}
if(chroot(".") == -1)
fatal("Couldn't set new rootdir: %s\n",strerror(errno));
if((setregid(gid,gid) == -1) || (setreuid(uid,uid) == -1))
fatal("Couldn't change uid/gid: %s\n",strerror(errno));
if(!check_perms(program,uid,gid))
fatal("Bad perms on %s\n",program);
args[0]= program; args[1] = NULL;
execve(program,args,safe_env);
fatal("execve <%s>: %s",program,strerror(errno));
}
int check_perms(char *program, long uid, long gid)
{
struct stat st;
if(stat(program,&st) == -1)
fatal("Stat() failed: %s\n",strerror(errno));
/* Check permissions */
if((uid == st.st_uid) && (st.st_mode & S_IXUSR)) return 1;
else if((gid == st.st_gid) && (st.st_mode & S_IXGRP)) return 1;
else if(st.st_mode & S_IXOTH) return 1;
return 0;
}