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