/*++
/* NAME
/*	chrootuid 1
/* SUMMARY
/*	run command in restricted environment
/* SYNOPSIS
/*	\fBchrootuid\fR \fInewroot newuser command\fR...
/* DESCRIPTION
/*	The \fBchrootuid\fR command sets up a restricted environment for
/*	executing \fIcommand\fR. Access to the file system is restricted to
/*	the \fInewroot\fR subtree; privileges are restricted to those of
/*	the \fInewuser\fR account (which must be a known account in the
/*	unrestricted environment).
/*	The initial working directory is changed to \fInewroot\fR.
/*
/*	\fBchrootuid\fR combines chroot(8) and su(1) into one program, so
/*	that there is no need to have commands such as /usr/bin/su
/*	in the restricted environment.
/*
/*	Only the superuser can use the \fBchrootuid\fR command.
/* DIAGNOSTICS
/*	The exit status is 1 when \fBchrootuid\fR has a problem, otherwise 
/*	the exit status is the exit status of \fIcommand\fR.
/* SEE ALSO
/*	chroot(8), su(1)
/* DIAGNOSTICS
/*	Problems are reported to the syslog daemon.
/* AUTHOR(S)
/*	Wietse Venema
/*	Eindhoven University of Technology
/*	Department of Mathematics and Computer Science
/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/*
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/* CREATION DATE
/*	Tue Oct 13 11:37:29 MET 1992
/* LAST MODIFICATION
/*	Wed Jul 25 11:25:08 EDT 2001
/* VERSION/RELEASE
/*	1.3
/*--*/

#ifndef lint
static char sccsid[] = "@(#) chrootuid.c 1.3 2001/07/25 11:25:08";
#endif

/* System libraries. */

#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <syslog.h>

int     main(argc, argv)
int     argc;
char  **argv;
{
    struct passwd *pwd;

    /*
     * Open a channel to the syslog daemon. Older versions of openlog()
     * require only two arguments.
     */

#ifdef LOG_DAEMON
    (void) openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
#else
    (void) openlog(argv[0], LOG_PID);
#endif

    /*
     * Require proper amount of arguments. In all cases of error, exit with
     * zero status because we have already reported the problem via syslogd.
     * No need to make inetd complain, too.
     */

    if (argc < 4) {
	syslog(LOG_ERR, "usage: %s path user command", argv[0]);
	return (0);
    }
    /* Must step into the new subtree. */

    if (chdir(argv[1])) {
	syslog(LOG_ERR, "chdir(%s): %m", argv[1]);
	return (0);
    }
    /* The user must be known in the *unrestricted* universe... */

    if ((pwd = getpwnam(argv[2])) == 0) {
	syslog(LOG_ERR, "%s: user unknown", argv[2]);
	return (0);
    }
    /* initgroups() accesses the group file in the unrestricted universe... */

    if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) {
	syslog(LOG_ERR, "initgroups: %m");
	return (0);
    }
    endgrent();

    /* Do the chroot() before giving away root privileges. */

    if (chroot(argv[1])) {
	syslog(LOG_ERR, "chroot(%s): %m", argv[1]);
	return (0);
    }
    /* Switch group id then user id. */

    if (setgid(pwd->pw_gid)) {
	syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid);
	return (0);
    }
    if (setuid(pwd->pw_uid)) {
	syslog(LOG_ERR, "setuid(%d): %m", pwd->pw_uid);
	return (0);
    }
    /* In case we still have the /etc/passwd file still open. */

    endpwent();

    /* Run the command and hope for the best. */

    (void) execv(argv[3], argv + 3);
    syslog(LOG_ERR, "%s: %m", argv[3]);
    return (0);
}
