xref: /freebsd/usr.sbin/jexec/jexec.c (revision 1f406de782450cd61fefef718db659621c6ab4ff)
1ebf5d9bcSMike Barcroft /*-
2ebf5d9bcSMike Barcroft  * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
3ebf5d9bcSMike Barcroft  * All rights reserved.
4ebf5d9bcSMike Barcroft  *
5ebf5d9bcSMike Barcroft  * Redistribution and use in source and binary forms, with or without
6ebf5d9bcSMike Barcroft  * modification, are permitted provided that the following conditions
7ebf5d9bcSMike Barcroft  * are met:
8ebf5d9bcSMike Barcroft  * 1. Redistributions of source code must retain the above copyright
9ebf5d9bcSMike Barcroft  *    notice, this list of conditions and the following disclaimer.
10ebf5d9bcSMike Barcroft  * 2. Redistributions in binary form must reproduce the above copyright
11ebf5d9bcSMike Barcroft  *    notice, this list of conditions and the following disclaimer in the
12ebf5d9bcSMike Barcroft  *    documentation and/or other materials provided with the distribution.
13ebf5d9bcSMike Barcroft  *
14ebf5d9bcSMike Barcroft  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ebf5d9bcSMike Barcroft  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ebf5d9bcSMike Barcroft  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ebf5d9bcSMike Barcroft  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ebf5d9bcSMike Barcroft  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ebf5d9bcSMike Barcroft  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ebf5d9bcSMike Barcroft  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ebf5d9bcSMike Barcroft  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ebf5d9bcSMike Barcroft  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ebf5d9bcSMike Barcroft  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ebf5d9bcSMike Barcroft  * SUCH DAMAGE.
25ebf5d9bcSMike Barcroft  *
26ebf5d9bcSMike Barcroft  * $FreeBSD$
27ebf5d9bcSMike Barcroft  */
28ebf5d9bcSMike Barcroft 
29ebf5d9bcSMike Barcroft #include <sys/param.h>
30ebf5d9bcSMike Barcroft #include <sys/jail.h>
311f406de7SMichael Reifenberger #include <sys/sysctl.h>
321f406de7SMichael Reifenberger 
331f406de7SMichael Reifenberger #include <arpa/inet.h>
34ebf5d9bcSMike Barcroft 
35ebf5d9bcSMike Barcroft #include <err.h>
3670b75adfSXin LI #include <errno.h>
371f406de7SMichael Reifenberger #include <limits.h>
3870b75adfSXin LI #include <login_cap.h>
39ebf5d9bcSMike Barcroft #include <stdio.h>
40ebf5d9bcSMike Barcroft #include <stdlib.h>
4170b75adfSXin LI #include <pwd.h>
42ebf5d9bcSMike Barcroft #include <unistd.h>
431f406de7SMichael Reifenberger #include <string.h>
44ebf5d9bcSMike Barcroft 
45ebf5d9bcSMike Barcroft static void	usage(void);
461f406de7SMichael Reifenberger int	addr2jid(const char *addr);
47ebf5d9bcSMike Barcroft 
4870b75adfSXin LI #define GET_USER_INFO do {						\
4970b75adfSXin LI 	pwd = getpwnam(username);					\
5070b75adfSXin LI 	if (pwd == NULL) {						\
5170b75adfSXin LI 		if (errno)						\
5270b75adfSXin LI 			err(1, "getpwnam: %s", username);		\
5370b75adfSXin LI 		else							\
5470b75adfSXin LI 			errx(1, "%s: no such user", username);		\
5570b75adfSXin LI 	}								\
5670b75adfSXin LI 	lcap = login_getpwclass(pwd);					\
5770b75adfSXin LI 	if (lcap == NULL)						\
5870b75adfSXin LI 		err(1, "getpwclass: %s", username);			\
5970b75adfSXin LI 	ngroups = NGROUPS;						\
6070b75adfSXin LI 	if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0)	\
6170b75adfSXin LI 		err(1, "getgrouplist: %s", username);			\
6270b75adfSXin LI } while (0)
6370b75adfSXin LI 
64ebf5d9bcSMike Barcroft int
65ebf5d9bcSMike Barcroft main(int argc, char *argv[])
66ebf5d9bcSMike Barcroft {
67ebf5d9bcSMike Barcroft 	int jid;
6870b75adfSXin LI 	login_cap_t *lcap = NULL;
6970b75adfSXin LI 	struct passwd *pwd = NULL;
7070b75adfSXin LI 	gid_t groups[NGROUPS];
7170b75adfSXin LI 	int ch, ngroups, uflag, Uflag;
7270b75adfSXin LI 	char *username;
7370b75adfSXin LI 	ch = uflag = Uflag = 0;
7470b75adfSXin LI 	username = NULL;
75ebf5d9bcSMike Barcroft 
7670b75adfSXin LI 	while ((ch = getopt(argc, argv, "u:U:")) != -1) {
7770b75adfSXin LI 		switch (ch) {
7870b75adfSXin LI 		case 'u':
7970b75adfSXin LI 			username = optarg;
8070b75adfSXin LI 			uflag = 1;
8170b75adfSXin LI 			break;
8270b75adfSXin LI 		case 'U':
8370b75adfSXin LI 			username = optarg;
8470b75adfSXin LI 			Uflag = 1;
8570b75adfSXin LI 			break;
8670b75adfSXin LI 		default:
87ebf5d9bcSMike Barcroft 			usage();
8870b75adfSXin LI 		}
8970b75adfSXin LI 	}
9070b75adfSXin LI 	argc -= optind;
9170b75adfSXin LI 	argv += optind;
9270b75adfSXin LI 	if (argc < 2)
9370b75adfSXin LI 		usage();
9470b75adfSXin LI 	if (uflag && Uflag)
9570b75adfSXin LI 		usage();
9670b75adfSXin LI 	if (uflag)
9770b75adfSXin LI 		GET_USER_INFO;
9870b75adfSXin LI 	jid = (int)strtol(argv[0], NULL, 10);
99ebf5d9bcSMike Barcroft 	if (jail_attach(jid) == -1)
1001f406de7SMichael Reifenberger 		if (jail_attach(addr2jid(argv[0])) == -1)
1011f406de7SMichael Reifenberger 			errx(1, "jail_attach(): Cant convert %s to jid", argv[0]);
102ebf5d9bcSMike Barcroft 	if (chdir("/") == -1)
103ebf5d9bcSMike Barcroft 		err(1, "chdir(): /");
10470b75adfSXin LI 	if (username != NULL) {
10570b75adfSXin LI 		if (Uflag)
10670b75adfSXin LI 			GET_USER_INFO;
10770b75adfSXin LI 		if (setgroups(ngroups, groups) != 0)
10870b75adfSXin LI 			err(1, "setgroups");
10970b75adfSXin LI 		if (setgid(pwd->pw_gid) != 0)
11070b75adfSXin LI 			err(1, "setgid");
11170b75adfSXin LI 		if (setusercontext(lcap, pwd, pwd->pw_uid,
11270b75adfSXin LI 		    LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0)
11370b75adfSXin LI 			err(1, "setusercontext");
11470b75adfSXin LI 		login_close(lcap);
11570b75adfSXin LI 	}
11670b75adfSXin LI 	if (execvp(argv[1], argv + 1) == -1)
11770b75adfSXin LI 		err(1, "execvp(): %s", argv[1]);
118ebf5d9bcSMike Barcroft 	exit(0);
119ebf5d9bcSMike Barcroft }
120ebf5d9bcSMike Barcroft 
121ebf5d9bcSMike Barcroft static void
122ebf5d9bcSMike Barcroft usage(void)
123ebf5d9bcSMike Barcroft {
124ebf5d9bcSMike Barcroft 
12570b75adfSXin LI 	fprintf(stderr, "%s%s\n",
12670b75adfSXin LI 		"usage: jexec [-u username | -U username]",
1271f406de7SMichael Reifenberger 		" [jid | hostname | ip-number] command ...");
128ebf5d9bcSMike Barcroft 	exit(1);
129ebf5d9bcSMike Barcroft }
1301f406de7SMichael Reifenberger 
1311f406de7SMichael Reifenberger int
1321f406de7SMichael Reifenberger addr2jid(const char *addr)
1331f406de7SMichael Reifenberger {
1341f406de7SMichael Reifenberger 	struct xprison *sxp, *xp;
1351f406de7SMichael Reifenberger 	struct in_addr in;
1361f406de7SMichael Reifenberger 	size_t i, len, slen;
1371f406de7SMichael Reifenberger 
1381f406de7SMichael Reifenberger 	if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
1391f406de7SMichael Reifenberger 		err(1, "sysctlbyname(): security.jail.list");
1401f406de7SMichael Reifenberger 	for (i = 0; i < 4; i++) {
1411f406de7SMichael Reifenberger 		if (len <= 0)
1421f406de7SMichael Reifenberger 			err(1, "sysctlbyname(): len <=0");
1431f406de7SMichael Reifenberger 		sxp = xp = malloc(len);
1441f406de7SMichael Reifenberger 		if (sxp == NULL)
1451f406de7SMichael Reifenberger 			err(1, "malloc()");
1461f406de7SMichael Reifenberger 		if (sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) {
1471f406de7SMichael Reifenberger 			if (errno == ENOMEM) {
1481f406de7SMichael Reifenberger 				free(sxp);
1491f406de7SMichael Reifenberger 				sxp = NULL;
1501f406de7SMichael Reifenberger 				continue;
1511f406de7SMichael Reifenberger 			}
1521f406de7SMichael Reifenberger 			err(1, "sysctlbyname(): security.jail.list");
1531f406de7SMichael Reifenberger 		}
1541f406de7SMichael Reifenberger 		break;
1551f406de7SMichael Reifenberger 	}
1561f406de7SMichael Reifenberger 	if (sxp == NULL)
1571f406de7SMichael Reifenberger 		err(1, "sysctlbyname(): security.jail.list");
1581f406de7SMichael Reifenberger 	if (len < sizeof(*xp) || len % sizeof(*xp) ||
1591f406de7SMichael Reifenberger 	    xp->pr_version != XPRISON_VERSION)
1601f406de7SMichael Reifenberger 		errx(1, "Kernel and userland out of sync");
1611f406de7SMichael Reifenberger 	slen = strlen(addr);
1621f406de7SMichael Reifenberger 	for (i = 0; i < len / sizeof(*xp); i++) {
1631f406de7SMichael Reifenberger 		in.s_addr = ntohl(xp->pr_ip);
1641f406de7SMichael Reifenberger 		if ((strncmp(inet_ntoa(in), addr, slen) == 0) ||
1651f406de7SMichael Reifenberger 		    (strncmp(xp->pr_host, addr, slen) == 0)) {
1661f406de7SMichael Reifenberger 			free(sxp);
1671f406de7SMichael Reifenberger 			return (xp->pr_id);
1681f406de7SMichael Reifenberger 		}
1691f406de7SMichael Reifenberger 		xp++;
1701f406de7SMichael Reifenberger 	}
1711f406de7SMichael Reifenberger 	free(sxp);
1721f406de7SMichael Reifenberger 	return 0;
1731f406de7SMichael Reifenberger }
174