xref: /freebsd/usr.sbin/jexec/jexec.c (revision aa0a1e58)
1 /*-
2  * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
3  * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #include <sys/param.h>
31 #include <sys/jail.h>
32 #include <sys/socket.h>
33 #include <sys/sysctl.h>
34 
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37 
38 #include <err.h>
39 #include <errno.h>
40 #include <jail.h>
41 #include <limits.h>
42 #include <login_cap.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <pwd.h>
47 #include <unistd.h>
48 
49 static void	usage(void);
50 
51 #define GET_USER_INFO do {						\
52 	pwd = getpwnam(username);					\
53 	if (pwd == NULL) {						\
54 		if (errno)						\
55 			err(1, "getpwnam: %s", username);		\
56 		else							\
57 			errx(1, "%s: no such user", username);		\
58 	}								\
59 	lcap = login_getpwclass(pwd);					\
60 	if (lcap == NULL)						\
61 		err(1, "getpwclass: %s", username);			\
62 	ngroups = ngroups_max;						\
63 	if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0)	\
64 		err(1, "getgrouplist: %s", username);			\
65 } while (0)
66 
67 int
68 main(int argc, char *argv[])
69 {
70 	int jid;
71 	login_cap_t *lcap = NULL;
72 	struct passwd *pwd = NULL;
73 	gid_t *groups = NULL;
74 	int ch, ngroups, uflag, Uflag;
75 	long ngroups_max;
76 	char *username;
77 
78 	ch = uflag = Uflag = 0;
79 	username = NULL;
80 	ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
81 	if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL)
82 		err(1, "malloc");
83 
84 	while ((ch = getopt(argc, argv, "nu:U:")) != -1) {
85 		switch (ch) {
86 		case 'n':
87 			/* Specified name, now unused */
88 			break;
89 		case 'u':
90 			username = optarg;
91 			uflag = 1;
92 			break;
93 		case 'U':
94 			username = optarg;
95 			Uflag = 1;
96 			break;
97 		default:
98 			usage();
99 		}
100 	}
101 	argc -= optind;
102 	argv += optind;
103 	if (argc < 2)
104 		usage();
105 	if (uflag && Uflag)
106 		usage();
107 	if (uflag)
108 		GET_USER_INFO;
109 	jid = jail_getid(argv[0]);
110 	if (jid < 0)
111 		errx(1, "%s", jail_errmsg);
112 	if (jail_attach(jid) == -1)
113 		err(1, "jail_attach(%d)", jid);
114 	if (chdir("/") == -1)
115 		err(1, "chdir(): /");
116 	if (username != NULL) {
117 		if (Uflag)
118 			GET_USER_INFO;
119 		if (setgroups(ngroups, groups) != 0)
120 			err(1, "setgroups");
121 		if (setgid(pwd->pw_gid) != 0)
122 			err(1, "setgid");
123 		if (setusercontext(lcap, pwd, pwd->pw_uid,
124 		    LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0)
125 			err(1, "setusercontext");
126 		login_close(lcap);
127 	}
128 	if (execvp(argv[1], argv + 1) == -1)
129 		err(1, "execvp(): %s", argv[1]);
130 	exit(0);
131 }
132 
133 static void
134 usage(void)
135 {
136 
137 	fprintf(stderr, "%s\n",
138 		"usage: jexec [-u username | -U username] jail command ...");
139 	exit(1);
140 }
141