Deleted Added
sdiff udiff text old ( 185435 ) new ( 191668 )
full compact
1/*-
2 * Copyright (c) 1999 Poul-Henning Kamp.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/usr.sbin/jail/jail.c 191668 2009-04-29 16:02:52Z jamie $");
29
30#include <sys/param.h>
31#include <sys/jail.h>
32#include <sys/queue.h>
33#include <sys/socket.h>
34#include <sys/sysctl.h>
35#include <sys/types.h>
36
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <netdb.h>
40
41#include <err.h>
42#include <errno.h>
43#include <grp.h>
44#include <login_cap.h>
45#include <paths.h>
46#include <pwd.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <strings.h>
50#include <string.h>
51#include <unistd.h>
52
53static void usage(void);
54static int add_addresses(struct addrinfo *);
55static struct in_addr *copy_addr4(void);
56#ifdef INET6
57static struct in6_addr *copy_addr6(void);
58#endif
59
60extern char **environ;
61
62struct addr4entry {
63 STAILQ_ENTRY(addr4entry) addr4entries;
64 struct in_addr ip4;
65 int count;
66};
67struct addr6entry {
68 STAILQ_ENTRY(addr6entry) addr6entries;
69#ifdef INET6
70 struct in6_addr ip6;
71#endif
72 int count;
73};
74STAILQ_HEAD(addr4head, addr4entry) addr4 = STAILQ_HEAD_INITIALIZER(addr4);
75STAILQ_HEAD(addr6head, addr6entry) addr6 = STAILQ_HEAD_INITIALIZER(addr6);
76
77#define GET_USER_INFO do { \
78 pwd = getpwnam(username); \
79 if (pwd == NULL) { \
80 if (errno) \
81 err(1, "getpwnam: %s", username); \
82 else \
83 errx(1, "%s: no such user", username); \
84 } \
85 lcap = login_getpwclass(pwd); \
86 if (lcap == NULL) \
87 err(1, "getpwclass: %s", username); \
88 ngroups = NGROUPS; \
89 if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0) \
90 err(1, "getgrouplist: %s", username); \
91} while (0)
92
93int
94main(int argc, char **argv)
95{
96 login_cap_t *lcap = NULL;
97 struct jail j;
98 struct passwd *pwd = NULL;
99 gid_t groups[NGROUPS];
100 int ch, error, i, ngroups, securelevel;
101 int hflag, iflag, Jflag, lflag, uflag, Uflag;
102 char path[PATH_MAX], *jailname, *ep, *username, *JidFile, *ip;
103 static char *cleanenv;
104 const char *shell, *p = NULL;
105 long ltmp;
106 FILE *fp;
107 struct addrinfo hints, *res0;
108
109 hflag = iflag = Jflag = lflag = uflag = Uflag = 0;
110 securelevel = -1;
111 jailname = username = JidFile = cleanenv = NULL;
112 fp = NULL;
113
114 while ((ch = getopt(argc, argv, "hiln:s:u:U:J:")) != -1) {
115 switch (ch) {
116 case 'h':
117 hflag = 1;
118 break;
119 case 'i':
120 iflag = 1;
121 break;
122 case 'J':
123 JidFile = optarg;
124 Jflag = 1;
125 break;
126 case 'n':
127 jailname = optarg;
128 break;
129 case 's':
130 ltmp = strtol(optarg, &ep, 0);
131 if (*ep || ep == optarg || ltmp > INT_MAX || !ltmp)
132 errx(1, "invalid securelevel: `%s'", optarg);
133 securelevel = ltmp;
134 break;
135 case 'u':
136 username = optarg;
137 uflag = 1;
138 break;
139 case 'U':
140 username = optarg;
141 Uflag = 1;
142 break;
143 case 'l':
144 lflag = 1;
145 break;
146 default:
147 usage();
148 }
149 }
150 argc -= optind;
151 argv += optind;
152 if (argc < 4)
153 usage();
154 if (uflag && Uflag)
155 usage();
156 if (lflag && username == NULL)
157 usage();
158 if (uflag)
159 GET_USER_INFO;
160 if (realpath(argv[0], path) == NULL)
161 err(1, "realpath: %s", argv[0]);
162 if (chdir(path) != 0)
163 err(1, "chdir: %s", path);
164 /* Initialize struct jail. */
165 memset(&j, 0, sizeof(j));
166 j.version = JAIL_API_VERSION;
167 j.path = path;
168 j.hostname = argv[1];
169 if (jailname != NULL)
170 j.jailname = jailname;
171
172 /* Handle IP addresses. If requested resolve hostname too. */
173 bzero(&hints, sizeof(struct addrinfo));
174 hints.ai_protocol = IPPROTO_TCP;
175 hints.ai_socktype = SOCK_STREAM;
176 if (JAIL_API_VERSION < 2)
177 hints.ai_family = PF_INET;
178 else
179 hints.ai_family = PF_UNSPEC;
180 /* Handle hostname. */
181 if (hflag != 0) {
182 error = getaddrinfo(j.hostname, NULL, &hints, &res0);
183 if (error != 0)
184 errx(1, "failed to handle hostname: %s",
185 gai_strerror(error));
186 error = add_addresses(res0);
187 freeaddrinfo(res0);
188 if (error != 0)
189 errx(1, "failed to add addresses.");
190 }
191 /* Handle IP addresses. */
192 hints.ai_flags = AI_NUMERICHOST;
193 ip = strtok(argv[2], ",");
194 while (ip != NULL) {
195 error = getaddrinfo(ip, NULL, &hints, &res0);
196 if (error != 0)
197 errx(1, "failed to handle ip: %s", gai_strerror(error));
198 error = add_addresses(res0);
199 freeaddrinfo(res0);
200 if (error != 0)
201 errx(1, "failed to add addresses.");
202 ip = strtok(NULL, ",");
203 }
204 /* Count IP addresses and add them to struct jail. */
205 if (!STAILQ_EMPTY(&addr4)) {
206 j.ip4s = STAILQ_FIRST(&addr4)->count;
207 j.ip4 = copy_addr4();
208 if (j.ip4s > 0 && j.ip4 == NULL)
209 errx(1, "copy_addr4()");
210 }
211#ifdef INET6
212 if (!STAILQ_EMPTY(&addr6)) {
213 j.ip6s = STAILQ_FIRST(&addr6)->count;
214 j.ip6 = copy_addr6();
215 if (j.ip6s > 0 && j.ip6 == NULL)
216 errx(1, "copy_addr6()");
217 }
218#endif
219
220 if (Jflag) {
221 fp = fopen(JidFile, "w");
222 if (fp == NULL)
223 errx(1, "Could not create JidFile: %s", JidFile);
224 }
225 i = jail(&j);
226 if (i == -1)
227 err(1, "syscall failed with");
228 if (iflag) {
229 printf("%d\n", i);
230 fflush(stdout);
231 }
232 if (Jflag) {
233 if (fp != NULL) {
234 fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
235 i, j.path, j.hostname, argv[2], argv[3]);
236 (void)fclose(fp);
237 } else {
238 errx(1, "Could not write JidFile: %s", JidFile);
239 }
240 }
241 if (securelevel > 0) {
242 if (sysctlbyname("kern.securelevel", NULL, 0, &securelevel,
243 sizeof(securelevel)))
244 err(1, "Can not set securelevel to %d", securelevel);
245 }
246 if (username != NULL) {
247 if (Uflag)
248 GET_USER_INFO;
249 if (lflag) {
250 p = getenv("TERM");
251 environ = &cleanenv;
252 }
253 if (setgroups(ngroups, groups) != 0)
254 err(1, "setgroups");
255 if (setgid(pwd->pw_gid) != 0)
256 err(1, "setgid");
257 if (setusercontext(lcap, pwd, pwd->pw_uid,
258 LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0)
259 err(1, "setusercontext");
260 login_close(lcap);
261 }
262 if (lflag) {
263 if (*pwd->pw_shell)
264 shell = pwd->pw_shell;
265 else
266 shell = _PATH_BSHELL;
267 if (chdir(pwd->pw_dir) < 0)
268 errx(1, "no home directory");
269 setenv("HOME", pwd->pw_dir, 1);
270 setenv("SHELL", shell, 1);
271 setenv("USER", pwd->pw_name, 1);
272 if (p)
273 setenv("TERM", p, 1);
274 }
275 if (execv(argv[3], argv + 3) != 0)
276 err(1, "execv: %s", argv[3]);
277 exit(0);
278}
279
280static void
281usage(void)
282{
283
284 (void)fprintf(stderr, "%s%s%s\n",
285 "usage: jail [-hi] [-n jailname] [-J jid_file] ",
286 "[-s securelevel] [-l -u username | -U username] ",
287 "path hostname [ip[,..]] command ...");
288 exit(1);
289}
290
291static int
292add_addresses(struct addrinfo *res0)
293{
294 int error;
295 struct addrinfo *res;
296 struct addr4entry *a4p;
297 struct sockaddr_in *sai;
298#ifdef INET6
299 struct addr6entry *a6p;
300 struct sockaddr_in6 *sai6;
301#endif
302 int count;
303
304 error = 0;
305 for (res = res0; res && error == 0; res = res->ai_next) {
306 switch (res->ai_family) {
307 case AF_INET:
308 sai = (struct sockaddr_in *)(void *)res->ai_addr;
309 STAILQ_FOREACH(a4p, &addr4, addr4entries) {
310 if (bcmp(&sai->sin_addr, &a4p->ip4,
311 sizeof(struct in_addr)) == 0) {
312 err(1, "Ignoring duplicate IPv4 address.");
313 break;
314 }
315 }
316 a4p = (struct addr4entry *) malloc(
317 sizeof(struct addr4entry));
318 if (a4p == NULL) {
319 error = 1;
320 break;
321 }
322 bzero(a4p, sizeof(struct addr4entry));
323 bcopy(&sai->sin_addr, &a4p->ip4,
324 sizeof(struct in_addr));
325 if (!STAILQ_EMPTY(&addr4))
326 count = STAILQ_FIRST(&addr4)->count;
327 else
328 count = 0;
329 STAILQ_INSERT_TAIL(&addr4, a4p, addr4entries);
330 STAILQ_FIRST(&addr4)->count = count + 1;
331 break;
332#ifdef INET6
333 case AF_INET6:
334 sai6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
335 STAILQ_FOREACH(a6p, &addr6, addr6entries) {
336 if (bcmp(&sai6->sin6_addr, &a6p->ip6,
337 sizeof(struct in6_addr)) == 0) {
338 err(1, "Ignoring duplicate IPv6 address.");
339 break;
340 }
341 }
342 a6p = (struct addr6entry *) malloc(
343 sizeof(struct addr6entry));
344 if (a6p == NULL) {
345 error = 1;
346 break;
347 }
348 bzero(a6p, sizeof(struct addr6entry));
349 bcopy(&sai6->sin6_addr, &a6p->ip6,
350 sizeof(struct in6_addr));
351 if (!STAILQ_EMPTY(&addr6))
352 count = STAILQ_FIRST(&addr6)->count;
353 else
354 count = 0;
355 STAILQ_INSERT_TAIL(&addr6, a6p, addr6entries);
356 STAILQ_FIRST(&addr6)->count = count + 1;
357 break;
358#endif
359 default:
360 err(1, "Address family %d not supported. Ignoring.\n",
361 res->ai_family);
362 break;
363 }
364 }
365
366 return (error);
367}
368
369static struct in_addr *
370copy_addr4(void)
371{
372 size_t len;
373 struct in_addr *ip4s, *p, ia;
374 struct addr4entry *a4p;
375
376 if (STAILQ_EMPTY(&addr4))
377 return NULL;
378
379 len = STAILQ_FIRST(&addr4)->count * sizeof(struct in_addr);
380
381 ip4s = p = (struct in_addr *)malloc(len);
382 if (ip4s == NULL)
383 return (NULL);
384
385 bzero(p, len);
386
387 while (!STAILQ_EMPTY(&addr4)) {
388 a4p = STAILQ_FIRST(&addr4);
389 STAILQ_REMOVE_HEAD(&addr4, addr4entries);
390 ia.s_addr = a4p->ip4.s_addr;
391 bcopy(&ia, p, sizeof(struct in_addr));
392 p++;
393 free(a4p);
394 }
395
396 return (ip4s);
397}
398
399#ifdef INET6
400static struct in6_addr *
401copy_addr6(void)
402{
403 size_t len;
404 struct in6_addr *ip6s, *p;
405 struct addr6entry *a6p;
406
407 if (STAILQ_EMPTY(&addr6))
408 return NULL;
409
410 len = STAILQ_FIRST(&addr6)->count * sizeof(struct in6_addr);
411
412 ip6s = p = (struct in6_addr *)malloc(len);
413 if (ip6s == NULL)
414 return (NULL);
415
416 bzero(p, len);
417
418 while (!STAILQ_EMPTY(&addr6)) {
419 a6p = STAILQ_FIRST(&addr6);
420 STAILQ_REMOVE_HEAD(&addr6, addr6entries);
421 bcopy(&a6p->ip6, p, sizeof(struct in6_addr));
422 p++;
423 free(a6p);
424 }
425
426 return (ip6s);
427}
428#endif
429