/* Tova e wrapper za clientski cgi skriptove
 * koito se izpulnqvat s pravata na user-a
 * maniax@bastun.net - inicial source
 * dobber@bastun.net - fix a bug
 */
/*
 ideqta e , che thttpd-to bachka chroot-nato v /home/web
 i suotvetno, vutre ima /$username
 i nie trebe tam da chroot-vame
 sled tova trqbva da se vurnem, i da exec-nem
 bwwww...
 */

/*
 XXX:
 imame podadeno x.cgi
 i se namirame v /pichka/si/lelina
 trqbva da chroot-nem v /pichka
 da idem pak v si/lelina
 i da exec-nem
 ($username=pichka )
 *
 */


#define _GNU_SOURCE
#define MAX 50
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <pwd.h>
#include <syslog.h>




void err (char *arg)
{
	perror (arg);
	exit (3);
}



char *strip(char * str, char * dir)
{
	char * new_str;
	int j=0;

	new_str = (char *) malloc(strlen(str)+1);

	while (str[j]==dir[j]) j++;
	strcpy(new_str,(str+j));

	return new_str;
}

extern char **environ;

int main (int argc, char *argv[])
{
	struct stat xfile;
	int uid, gid, size=255;
	char chrootdir[255];
	char *tmp;
	struct passwd *pw;
	static char *arg[MAX];
	int arglen = 0;
	char * edir;
	char *resu;

#ifdef DEBUG
	openlog ("wrap", LOG_PID, LOG_DAEMON);
	syslog (LOG_NOTICE, "Wrap running");
#endif
	if (argc < 2)	return 1;

	argv++;

	if (stat (*argv, &xfile) != 0)	err ("stat");

	if (xfile.st_mode & S_IWOTH)  err ("world writable");	/* world writable */
	uid = xfile.st_uid;
	gid = xfile.st_gid;

	pw = getpwuid (xfile.st_uid);
	if (pw == NULL) err ("getpwuid");

	edir=(char *) malloc(size);
	while ( getcwd(edir,size) == NULL) {
		size*=2;
		realloc(edir,size);
	}

	resu=strip(edir,chrootdir);

	snprintf (chrootdir, 254, "/%s", pw->pw_name);
	if (chdir (chrootdir)<0) err ("chdir1");

	if (chroot (".")<0) err ("chroot");

	if (chdir("/")<0) err ("chdir2");

	if (chdir(resu)<0)  err ("chdir3");


	arg[0] = (char *) malloc (strlen (argv[0])+ 1);
	tmp = strchr ((*argv) + 1, '/');
	if (tmp != NULL) strcpy (arg[0], tmp);
	            else strcpy (arg[0], *argv);

	arglen = 1;
	argv++;
	while (*argv != NULL)
	{
		arg[arglen] = (char *) malloc (strlen (*argv) + 1);
		strcpy (arg[arglen], *argv);
		argv++;
		arglen++;
	}
	arg[arglen] = NULL;

	setgid (gid);
	setuid (uid);

	if (execve (arg[0], arg, environ) == -1) err ("exec faild");

	/* should never happen */
	return 123;
}
