#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>

unsigned char path[1024];
unsigned char buf[1024];

int main(int argc, unsigned char **argv)
{
    DIR *dir;
    struct dirent *dentry;
    struct stat st;
    struct passwd *pwd;
    int ret;
    int fd;
    
    if(argc < 2)
    {
	printf("usage: userinit initdir\n");
	return(1);
    }
    if(chdir(argv[1]) < 0)
    {
	perror(argv[1]);
	return(1);
    }
    if(getcwd(path, 1024) == NULL)
    {
	perror("getcwd");
	return(1);
    }
    if((dir = opendir(".")) == NULL)
    {
	perror("opendir");
	return(1);
    }
    while((dentry = readdir(dir)) != NULL)
    {
	if(stat(dentry->d_name, &st) < 0)
	    perror(dentry->d_name);
	if((S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) && ((st.st_mode & 0111) == 0111))
	{
	    if(!(ret = fork()))
	    {
		if((pwd = getpwuid(st.st_uid)) == NULL)
		{
		    fprintf(stderr, "No such user: %i\n", st.st_uid);
		    exit(1);
		}
		initgroups(pwd->pw_name, pwd->pw_gid);
		setgid(st.st_gid);
		setuid(st.st_uid);
		chdir(pwd->pw_dir);
		if(snprintf(buf, 1024, "HOME=%s", pwd->pw_dir) < 1024)
		    putenv(strdup(buf));
		if(snprintf(buf, 1024, "SHELL=%s", pwd->pw_shell) < 1024)
		    putenv(strdup(buf));
		if(snprintf(buf, 1024, "USER=%s", pwd->pw_name) < 1024)
		    putenv(strdup(buf));
		if(snprintf(buf, 1024, "LOGNAME=%s", pwd->pw_name) < 1024)
		    putenv(strdup(buf));
		if(snprintf(buf, 1024, "PATH=/usr/local/bin:/bin:/usr/bin") < 1024)
		    putenv(strdup(buf));
		if(snprintf(buf, 1024, "%s/%s", path, dentry->d_name) > 1023)
		{
		    fprintf(stderr, "Could not fit exec path in 1023 bytes\n");
		    exit(1);
		}
		daemon(0, 0);
		execl(buf, NULL);
		perror(dentry->d_name);
		exit(127);
	    }
	    if(ret < 0)
	    {
		perror("fork");
		exit(1);
	    }
	}
    }
    closedir(dir);
    return(0);
}

