1 /*++
2 /* NAME
3 /*	chrootuid 1
4 /* SUMMARY
5 /*	run command in restricted environment
6 /* SYNOPSIS
7 /*	\fBchrootuid\fR \fInewroot newuser command\fR...
8 /* DESCRIPTION
9 /*	The \fBchrootuid\fR command sets up a restricted environment for
10 /*	executing \fIcommand\fR. Access to the file system is restricted to
11 /*	the \fInewroot\fR subtree; privileges are restricted to those of
12 /*	the \fInewuser\fR account (which must be a known account in the
13 /*	unrestricted environment).
14 /*	The initial working directory is changed to \fInewroot\fR.
15 /*
16 /*	\fBchrootuid\fR combines chroot(8) and su(1) into one program, so
17 /*	that there is no need to have commands such as /usr/bin/su
18 /*	in the restricted environment.
19 /*
20 /*	Only the superuser can use the \fBchrootuid\fR command.
21 /* DIAGNOSTICS
22 /*	The exit status is 1 when \fBchrootuid\fR has a problem, otherwise
23 /*	the exit status is the exit status of \fIcommand\fR.
24 /* SEE ALSO
25 /*	chroot(8), su(1)
26 /* DIAGNOSTICS
27 /*	Problems are reported to the syslog daemon.
28 /* AUTHOR(S)
29 /*	Wietse Venema
30 /*	Eindhoven University of Technology
31 /*	Department of Mathematics and Computer Science
32 /*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
33 /*
34 /*	IBM T.J. Watson Research
35 /*	P.O. Box 704
36 /*	Yorktown Heights, NY 10598, USA
37 /* CREATION DATE
38 /*	Tue Oct 13 11:37:29 MET 1992
39 /* LAST MODIFICATION
40 /*	Wed Jul 25 11:25:08 EDT 2001
41 /* VERSION/RELEASE
42 /*	1.3
43 /*--*/
44 
45 #ifndef lint
46 static char sccsid[] = "@(#) chrootuid.c 1.3 2001/07/25 11:25:08";
47 #endif
48 
49 /* System libraries. */
50 
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <pwd.h>
54 #include <grp.h>
55 #include <syslog.h>
56 
main(argc,argv)57 int     main(argc, argv)
58 int     argc;
59 char  **argv;
60 {
61     struct passwd *pwd;
62 
63     /*
64      * Open a channel to the syslog daemon. Older versions of openlog()
65      * require only two arguments.
66      */
67 
68 #ifdef LOG_DAEMON
69     (void) openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
70 #else
71     (void) openlog(argv[0], LOG_PID);
72 #endif
73 
74     /*
75      * Require proper amount of arguments. In all cases of error, exit with
76      * zero status because we have already reported the problem via syslogd.
77      * No need to make inetd complain, too.
78      */
79 
80     if (argc < 4) {
81 	syslog(LOG_ERR, "usage: %s path user command", argv[0]);
82 	return (0);
83     }
84 
85     syslog(LOG_NOTICE, "chrootuid: dir(%s) user(%s) command(%s)",
86 	argv[1], argv[2], argv[3]);
87 
88     /* Must step into the new subtree. */
89 
90     if (chdir(argv[1])) {
91 	syslog(LOG_ERR, "chdir(%s): %m", argv[1]);
92 	return (0);
93     }
94     /* The user must be known in the *unrestricted* universe... */
95 
96     if ((pwd = getpwnam(argv[2])) == 0) {
97 	syslog(LOG_ERR, "%s: user unknown", argv[2]);
98 	return (0);
99     }
100     /* initgroups() accesses the group file in the unrestricted universe... */
101 
102     if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) {
103 	syslog(LOG_ERR, "initgroups: %m");
104 	return (0);
105     }
106     endgrent();
107 
108     /* Do the chroot() before giving away root privileges. */
109 
110     if (chroot(argv[1])) {
111 	syslog(LOG_ERR, "chroot(%s): %m", argv[1]);
112 	return (0);
113     }
114     /* Switch group id then user id. */
115 
116     if (setgid(pwd->pw_gid)) {
117 	syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid);
118 	return (0);
119     }
120     if (setuid(pwd->pw_uid)) {
121 	syslog(LOG_ERR, "setuid(%d): %m", pwd->pw_uid);
122 	return (0);
123     }
124     /* In case we still have the /etc/passwd file still open. */
125 
126     endpwent();
127 
128     /* Run the command and hope for the best. */
129 
130     (void) execv(argv[3], argv + 3);
131     syslog(LOG_ERR, "%s: %m", argv[3]);
132     return (0);
133 }
134