xref: /freebsd/usr.sbin/chroot/chroot.c (revision 0b8224d1)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
4dea673e9SRodney W. Grimes  * Copyright (c) 1988, 1993
5dea673e9SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
6dea673e9SRodney W. Grimes  *
7dea673e9SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
8dea673e9SRodney W. Grimes  * modification, are permitted provided that the following conditions
9dea673e9SRodney W. Grimes  * are met:
10dea673e9SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
11dea673e9SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
12dea673e9SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
13dea673e9SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
14dea673e9SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
16dea673e9SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
17dea673e9SRodney W. Grimes  *    without specific prior written permission.
18dea673e9SRodney W. Grimes  *
19dea673e9SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20dea673e9SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21dea673e9SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22dea673e9SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23dea673e9SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24dea673e9SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25dea673e9SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26dea673e9SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27dea673e9SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28dea673e9SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29dea673e9SRodney W. Grimes  * SUCH DAMAGE.
30dea673e9SRodney W. Grimes  */
31dea673e9SRodney W. Grimes 
32dea673e9SRodney W. Grimes #include <sys/types.h>
33a40cf417SEdward Tomasz Napierala #include <sys/procctl.h>
34dea673e9SRodney W. Grimes 
354fb3a306SMike Makonnen #include <ctype.h>
36dea673e9SRodney W. Grimes #include <err.h>
374fb3a306SMike Makonnen #include <grp.h>
384fb3a306SMike Makonnen #include <limits.h>
39dea673e9SRodney W. Grimes #include <paths.h>
404fb3a306SMike Makonnen #include <pwd.h>
41a40cf417SEdward Tomasz Napierala #include <stdbool.h>
42dea673e9SRodney W. Grimes #include <stdio.h>
43dea673e9SRodney W. Grimes #include <stdlib.h>
44dea673e9SRodney W. Grimes #include <string.h>
45dea673e9SRodney W. Grimes #include <unistd.h>
46dea673e9SRodney W. Grimes 
4772e1ea2fSAlfonso Gregory static void usage(void) __dead2;
48dea673e9SRodney W. Grimes 
49dea673e9SRodney W. Grimes int
main(int argc,char * argv[])509a958de5SEd Schouten main(int argc, char *argv[])
51dea673e9SRodney W. Grimes {
524fb3a306SMike Makonnen 	struct group	*gp;
534fb3a306SMike Makonnen 	struct passwd	*pw;
544c46bfb6SEd Schouten 	char		*endp, *p, *user, *group, *grouplist;
55408d219eSMike Heffner 	const char	*shell;
5654404cfbSBrooks Davis 	gid_t		gid, *gidlist;
574fb3a306SMike Makonnen 	uid_t		uid;
58a40cf417SEdward Tomasz Napierala 	int		arg, ch, error, gids;
5954404cfbSBrooks Davis 	long		ngroups_max;
6006343905SEdward Tomasz Napierala 	bool		nonprivileged;
61dea673e9SRodney W. Grimes 
624fb3a306SMike Makonnen 	gid = 0;
634fb3a306SMike Makonnen 	uid = 0;
644c46bfb6SEd Schouten 	user = group = grouplist = NULL;
6506343905SEdward Tomasz Napierala 	nonprivileged = false;
66a40cf417SEdward Tomasz Napierala 	while ((ch = getopt(argc, argv, "G:g:u:n")) != -1) {
67dea673e9SRodney W. Grimes 		switch(ch) {
684fb3a306SMike Makonnen 		case 'u':
694fb3a306SMike Makonnen 			user = optarg;
704fb3a306SMike Makonnen 			if (*user == '\0')
714fb3a306SMike Makonnen 				usage();
724fb3a306SMike Makonnen 			break;
734fb3a306SMike Makonnen 		case 'g':
744fb3a306SMike Makonnen 			group = optarg;
754fb3a306SMike Makonnen 			if (*group == '\0')
764fb3a306SMike Makonnen 				usage();
774fb3a306SMike Makonnen 			break;
784fb3a306SMike Makonnen 		case 'G':
794fb3a306SMike Makonnen 			grouplist = optarg;
804fb3a306SMike Makonnen 			if (*grouplist == '\0')
814fb3a306SMike Makonnen 				usage();
824fb3a306SMike Makonnen 			break;
83a40cf417SEdward Tomasz Napierala 		case 'n':
8406343905SEdward Tomasz Napierala 			nonprivileged = true;
85a40cf417SEdward Tomasz Napierala 			break;
86dea673e9SRodney W. Grimes 		case '?':
87dea673e9SRodney W. Grimes 		default:
88dea673e9SRodney W. Grimes 			usage();
89dea673e9SRodney W. Grimes 		}
904fb3a306SMike Makonnen 	}
91dea673e9SRodney W. Grimes 	argc -= optind;
92dea673e9SRodney W. Grimes 	argv += optind;
93dea673e9SRodney W. Grimes 
94dea673e9SRodney W. Grimes 	if (argc < 1)
95dea673e9SRodney W. Grimes 		usage();
96dea673e9SRodney W. Grimes 
974fb3a306SMike Makonnen 	if (group != NULL) {
984fb3a306SMike Makonnen 		if (isdigit((unsigned char)*group)) {
994fb3a306SMike Makonnen 			gid = (gid_t)strtoul(group, &endp, 0);
1004fb3a306SMike Makonnen 			if (*endp != '\0')
1014fb3a306SMike Makonnen 				goto getgroup;
1024fb3a306SMike Makonnen 		} else {
1034fb3a306SMike Makonnen  getgroup:
1044fb3a306SMike Makonnen 			if ((gp = getgrnam(group)) != NULL)
1054fb3a306SMike Makonnen 				gid = gp->gr_gid;
1064fb3a306SMike Makonnen 			else
1074fb3a306SMike Makonnen 				errx(1, "no such group `%s'", group);
1084fb3a306SMike Makonnen 		}
1094fb3a306SMike Makonnen 	}
1104fb3a306SMike Makonnen 
11154404cfbSBrooks Davis 	ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
11254404cfbSBrooks Davis 	if ((gidlist = malloc(sizeof(gid_t) * ngroups_max)) == NULL)
11354404cfbSBrooks Davis 		err(1, "malloc");
1144fb3a306SMike Makonnen 	for (gids = 0;
11554404cfbSBrooks Davis 	    (p = strsep(&grouplist, ",")) != NULL && gids < ngroups_max; ) {
1164fb3a306SMike Makonnen 		if (*p == '\0')
1174fb3a306SMike Makonnen 			continue;
1184fb3a306SMike Makonnen 
1194fb3a306SMike Makonnen 		if (isdigit((unsigned char)*p)) {
1204fb3a306SMike Makonnen 			gidlist[gids] = (gid_t)strtoul(p, &endp, 0);
1214fb3a306SMike Makonnen 			if (*endp != '\0')
1224fb3a306SMike Makonnen 				goto getglist;
1234fb3a306SMike Makonnen 		} else {
1244fb3a306SMike Makonnen  getglist:
1254fb3a306SMike Makonnen 			if ((gp = getgrnam(p)) != NULL)
1264fb3a306SMike Makonnen 				gidlist[gids] = gp->gr_gid;
1274fb3a306SMike Makonnen 			else
1284fb3a306SMike Makonnen 				errx(1, "no such group `%s'", p);
1294fb3a306SMike Makonnen 		}
1304fb3a306SMike Makonnen 		gids++;
1314fb3a306SMike Makonnen 	}
13254404cfbSBrooks Davis 	if (p != NULL && gids == ngroups_max)
1334fb3a306SMike Makonnen 		errx(1, "too many supplementary groups provided");
1344fb3a306SMike Makonnen 
1354fb3a306SMike Makonnen 	if (user != NULL) {
1364fb3a306SMike Makonnen 		if (isdigit((unsigned char)*user)) {
1374fb3a306SMike Makonnen 			uid = (uid_t)strtoul(user, &endp, 0);
1384fb3a306SMike Makonnen 			if (*endp != '\0')
1394fb3a306SMike Makonnen 				goto getuser;
1404fb3a306SMike Makonnen 		} else {
1414fb3a306SMike Makonnen  getuser:
1424fb3a306SMike Makonnen 			if ((pw = getpwnam(user)) != NULL)
1434fb3a306SMike Makonnen 				uid = pw->pw_uid;
1444fb3a306SMike Makonnen 			else
1454fb3a306SMike Makonnen 				errx(1, "no such user `%s'", user);
1464fb3a306SMike Makonnen 		}
1474fb3a306SMike Makonnen 	}
1484fb3a306SMike Makonnen 
14906343905SEdward Tomasz Napierala 	if (nonprivileged) {
150a40cf417SEdward Tomasz Napierala 		arg = PROC_NO_NEW_PRIVS_ENABLE;
151a40cf417SEdward Tomasz Napierala 		error = procctl(P_PID, getpid(), PROC_NO_NEW_PRIVS_CTL, &arg);
152a40cf417SEdward Tomasz Napierala 		if (error != 0)
153a40cf417SEdward Tomasz Napierala 			err(1, "procctl");
154a40cf417SEdward Tomasz Napierala 	}
155a40cf417SEdward Tomasz Napierala 
156fe6983deSMike Makonnen 	if (chdir(argv[0]) == -1 || chroot(".") == -1)
157dea673e9SRodney W. Grimes 		err(1, "%s", argv[0]);
158dea673e9SRodney W. Grimes 
1594fb3a306SMike Makonnen 	if (gids && setgroups(gids, gidlist) == -1)
1604fb3a306SMike Makonnen 		err(1, "setgroups");
1614fb3a306SMike Makonnen 	if (group && setgid(gid) == -1)
1624fb3a306SMike Makonnen 		err(1, "setgid");
1634fb3a306SMike Makonnen 	if (user && setuid(uid) == -1)
1644fb3a306SMike Makonnen 		err(1, "setuid");
1654fb3a306SMike Makonnen 
166dea673e9SRodney W. Grimes 	if (argv[1]) {
167dea673e9SRodney W. Grimes 		execvp(argv[1], &argv[1]);
168dea673e9SRodney W. Grimes 		err(1, "%s", argv[1]);
169dea673e9SRodney W. Grimes 	}
170dea673e9SRodney W. Grimes 
171dea673e9SRodney W. Grimes 	if (!(shell = getenv("SHELL")))
172dea673e9SRodney W. Grimes 		shell = _PATH_BSHELL;
1737bc6d015SBrian Somers 	execlp(shell, shell, "-i", (char *)NULL);
174dea673e9SRodney W. Grimes 	err(1, "%s", shell);
175dea673e9SRodney W. Grimes 	/* NOTREACHED */
176dea673e9SRodney W. Grimes }
177dea673e9SRodney W. Grimes 
17814b374a5SPhilippe Charnier static void
usage(void)1799a958de5SEd Schouten usage(void)
180dea673e9SRodney W. Grimes {
1814fb3a306SMike Makonnen 	(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
182a40cf417SEdward Tomasz Napierala 	    "[-u user] [-n] newroot [command]\n");
183dea673e9SRodney W. Grimes 	exit(1);
184dea673e9SRodney W. Grimes }
185