xref: /netbsd-src/usr.sbin/chroot/chroot.c (revision 3584aaaf1cc69ad18a60709bab6598cccc7e7372)
1*3584aaafSchristos /*	$NetBSD: chroot.c,v 1.19 2011/09/20 14:28:52 christos Exp $	*/
24e24c8f4Smrg 
361f28255Scgd /*
4e65788c5Smikel  * Copyright (c) 1988, 1993
5e65788c5Smikel  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15326b2259Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
32acbb5683Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
349c194566Slukem __COPYRIGHT("@(#) Copyright (c) 1988, 1993\
359c194566Slukem  The Regents of the University of California.  All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd 
3861f28255Scgd #ifndef lint
39acbb5683Slukem #if 0
40acbb5683Slukem static char sccsid[] = "@(#)chroot.c	8.1 (Berkeley) 6/9/93";
41acbb5683Slukem #else
42*3584aaafSchristos __RCSID("$NetBSD: chroot.c,v 1.19 2011/09/20 14:28:52 christos Exp $");
43acbb5683Slukem #endif
4461f28255Scgd #endif /* not lint */
4561f28255Scgd 
4616d7f0c2Smrg #include <sys/param.h>
47e65788c5Smikel 
48e65788c5Smikel #include <err.h>
49e65788c5Smikel #include <errno.h>
5016d7f0c2Smrg #include <grp.h>
51e65788c5Smikel #include <paths.h>
5216d7f0c2Smrg #include <pwd.h>
5361f28255Scgd #include <stdio.h>
54fbdf4e03Sjtc #include <stdlib.h>
55*3584aaafSchristos #include <inttypes.h>
56804c4234Smycroft #include <string.h>
57e65788c5Smikel #include <unistd.h>
5861f28255Scgd 
59b71455acSjoerg static void	usage(void) __dead;
60e65788c5Smikel 
61*3584aaafSchristos static int
getnum(const char * str,uintmax_t * num)62*3584aaafSchristos getnum(const char *str, uintmax_t *num)
63*3584aaafSchristos {
64*3584aaafSchristos 	char *ep;
65*3584aaafSchristos 
66*3584aaafSchristos 	errno = 0;
67*3584aaafSchristos 
68*3584aaafSchristos 	*num = strtoumax(str, &ep, 0);
69*3584aaafSchristos 	if (str[0] == '\0' || *ep != '\0') {
70*3584aaafSchristos 		errno = EINVAL;
71*3584aaafSchristos 		return -1;
72*3584aaafSchristos 	}
73*3584aaafSchristos 
74*3584aaafSchristos 	if (errno == ERANGE && *num == UINTMAX_MAX)
75*3584aaafSchristos 		return -1;
76*3584aaafSchristos 
77*3584aaafSchristos 	return 0;
78*3584aaafSchristos }
79*3584aaafSchristos 
80*3584aaafSchristos 
81*3584aaafSchristos static gid_t
getgroup(const char * group)82*3584aaafSchristos getgroup(const char *group)
83*3584aaafSchristos {
84*3584aaafSchristos 	uintmax_t	num;
85*3584aaafSchristos 	struct group	*gp;
86*3584aaafSchristos 
87*3584aaafSchristos 	if ((gp = getgrnam(group)) != NULL)
88*3584aaafSchristos 		return gp->gr_gid;
89*3584aaafSchristos 
90*3584aaafSchristos 	if (getnum(group, &num) == -1)
91*3584aaafSchristos 	    errx(1, "no such group `%s'", group);
92*3584aaafSchristos 
93*3584aaafSchristos 	return (gid_t)num;
94*3584aaafSchristos }
95*3584aaafSchristos 
96*3584aaafSchristos static uid_t
getuser(const char * user)97*3584aaafSchristos getuser(const char *user)
98*3584aaafSchristos {
99*3584aaafSchristos 	uintmax_t	num;
100*3584aaafSchristos 	struct passwd	*pw;
101*3584aaafSchristos 
102*3584aaafSchristos 	if ((pw = getpwnam(user)) != NULL)
103*3584aaafSchristos 		return pw->pw_uid;
104*3584aaafSchristos 
105*3584aaafSchristos 	if (getnum(user, &num) == -1)
106*3584aaafSchristos 		errx(1, "no such user `%s'", user);
107*3584aaafSchristos 
108*3584aaafSchristos 	return (uid_t)num;
109*3584aaafSchristos }
110*3584aaafSchristos 
111e65788c5Smikel int
main(int argc,char * argv[])112b990482cSlukem main(int argc, char *argv[])
11361f28255Scgd {
114b71455acSjoerg 	char	*user;		/* user to switch to before running program */
115b71455acSjoerg 	char	*group;		/* group to switch to ... */
116b71455acSjoerg 	char	*grouplist;	/* group list to switch to ... */
117*3584aaafSchristos 	char		*p;
118b990482cSlukem 	const char	*shell;
119b990482cSlukem 	gid_t		gid, gidlist[NGROUPS_MAX];
120b990482cSlukem 	uid_t		uid;
12116d7f0c2Smrg 	int		ch, gids;
12261f28255Scgd 
123b6211abfSmbalmer 	user = NULL;
124b6211abfSmbalmer 	group = NULL;
125*3584aaafSchristos 	grouplist = NULL;
126b990482cSlukem 	gid = 0;
127b990482cSlukem 	uid = 0;
128*3584aaafSchristos 	gids = 0;
129b990482cSlukem 	while ((ch = getopt(argc, argv, "G:g:u:")) != -1) {
130e65788c5Smikel 		switch(ch) {
13116d7f0c2Smrg 		case 'u':
13216d7f0c2Smrg 			user = optarg;
133847cf986Slukem 			if (*user == '\0')
134847cf986Slukem 				usage();
13516d7f0c2Smrg 			break;
13616d7f0c2Smrg 		case 'g':
13716d7f0c2Smrg 			group = optarg;
138847cf986Slukem 			if (*group == '\0')
139847cf986Slukem 				usage();
14016d7f0c2Smrg 			break;
14116d7f0c2Smrg 		case 'G':
14216d7f0c2Smrg 			grouplist = optarg;
143847cf986Slukem 			if (*grouplist == '\0')
144847cf986Slukem 				usage();
14516d7f0c2Smrg 			break;
146e65788c5Smikel 		case '?':
147e65788c5Smikel 		default:
148e65788c5Smikel 			usage();
14961f28255Scgd 		}
150b990482cSlukem 	}
151e65788c5Smikel 	argc -= optind;
152e65788c5Smikel 	argv += optind;
153e65788c5Smikel 
154e65788c5Smikel 	if (argc < 1)
155e65788c5Smikel 		usage();
156e65788c5Smikel 
157*3584aaafSchristos 	if (user != NULL)
158*3584aaafSchristos 		uid = getuser(user);
15916d7f0c2Smrg 
160*3584aaafSchristos 	if (group != NULL)
161*3584aaafSchristos 		gid = getgroup(group);
162*3584aaafSchristos 
163*3584aaafSchristos 	if (grouplist != NULL) {
164*3584aaafSchristos 		while ((p = strsep(&grouplist, ",")) != NULL) {
165847cf986Slukem 			if (*p == '\0')
166847cf986Slukem 				continue;
16716d7f0c2Smrg 
168*3584aaafSchristos 			if (gids == NGROUPS_MAX)
169*3584aaafSchristos 				errx(1,
170*3584aaafSchristos 				    "too many supplementary groups provided");
17116d7f0c2Smrg 
172*3584aaafSchristos 			gidlist[gids++] = getgroup(p);
17316d7f0c2Smrg 		}
17416d7f0c2Smrg 	}
17516d7f0c2Smrg 
176b990482cSlukem 	if (chdir(argv[0]) == -1 || chroot(".") == -1)
177e65788c5Smikel 		err(1, "%s", argv[0]);
178e65788c5Smikel 
179b990482cSlukem 	if (gids && setgroups(gids, gidlist) == -1)
18016d7f0c2Smrg 		err(1, "setgroups");
181b990482cSlukem 	if (group && setgid(gid) == -1)
18216d7f0c2Smrg 		err(1, "setgid");
183b990482cSlukem 	if (user && setuid(uid) == -1)
18416d7f0c2Smrg 		err(1, "setuid");
18516d7f0c2Smrg 
186e65788c5Smikel 	if (argv[1]) {
187e65788c5Smikel 		execvp(argv[1], &argv[1]);
188fbdf4e03Sjtc 		err(1, "%s", argv[1]);
189e65788c5Smikel 	}
190e65788c5Smikel 
191b990482cSlukem 	if ((shell = getenv("SHELL")) == NULL)
19261f28255Scgd 		shell = _PATH_BSHELL;
193e65788c5Smikel 	execlp(shell, shell, "-i", NULL);
194fbdf4e03Sjtc 	err(1, "%s", shell);
19561f28255Scgd 	/* NOTREACHED */
19661f28255Scgd }
197e65788c5Smikel 
198b71455acSjoerg static void
usage(void)199b990482cSlukem usage(void)
200e65788c5Smikel {
201b990482cSlukem 
202*3584aaafSchristos 	(void)fprintf(stderr, "Usage: %s [-G group,group,...] [-g group] "
203*3584aaafSchristos 	    "[-u user] newroot [command]\n", getprogname());
204e65788c5Smikel 	exit(1);
205e65788c5Smikel }
206