xref: /freebsd/usr.sbin/jls/jls.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
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/types.h>
32 #include <sys/jail.h>
33 #include <sys/sysctl.h>
34 
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #define	FLAG_A		0x00001
47 #define	FLAG_V		0x00002
48 
49 #ifdef SUPPORT_OLD_XPRISON
50 static
51 char *print_xprison_v1(void *p, char *end, unsigned flags)
52 {
53 	struct xprison_v1 *xp;
54 	struct in_addr in;
55 
56 	if ((char *)p + sizeof(struct xprison_v1) > end)
57 		errx(1, "Invalid length for jail");
58 
59 	xp = (struct xprison_v1 *)p;
60 	if (flags & FLAG_V) {
61 		printf("%6d  %-29.29s %.74s\n",
62 			xp->pr_id, xp->pr_host, xp->pr_path);
63 		/* We are not printing an empty line here for state and name. */
64 		/* We are not printing an empty line here for cpusetid. */
65 		/* IPv4 address. */
66 		in.s_addr = htonl(xp->pr_ip);
67 		printf("%6s  %-15.15s\n", "", inet_ntoa(in));
68 	} else {
69 		printf("%6d  %-15.15s %-29.29s %.74s\n",
70 		    xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
71 	}
72 
73 	return ((char *)(xp + 1));
74 }
75 #endif
76 
77 static
78 char *print_xprison_v3(void *p, char *end, unsigned flags)
79 {
80 	struct xprison *xp;
81 	struct in_addr *iap, in;
82 	struct in6_addr *ia6p;
83 	char buf[INET6_ADDRSTRLEN];
84 	const char *state;
85 	char *q;
86 	uint32_t i;
87 
88 	if ((char *)p + sizeof(struct xprison) > end)
89 		errx(1, "Invalid length for jail");
90 	xp = (struct xprison *)p;
91 
92 	if (xp->pr_state < 0 || xp->pr_state >= (int)
93 	    ((sizeof(prison_states) / sizeof(struct prison_state))))
94 		state = "(bogus)";
95 	else
96 		state = prison_states[xp->pr_state].state_name;
97 
98 	/* See if we should print non-ACTIVE jails. No? */
99 	if ((flags & FLAG_A) == 0 && strcmp(state, "ALIVE")) {
100 		q = (char *)(xp + 1);
101 		q += (xp->pr_ip4s * sizeof(struct in_addr));
102 		if (q > end)
103 			errx(1, "Invalid length for jail");
104 		q += (xp->pr_ip6s * sizeof(struct in6_addr));
105 		if (q > end)
106 			errx(1, "Invalid length for jail");
107 		return (q);
108 	}
109 
110 	if (flags & FLAG_V)
111 		printf("%6d  %-29.29s %.74s\n",
112 			xp->pr_id, xp->pr_host, xp->pr_path);
113 
114 	/* Jail state and name. */
115 	if (flags & FLAG_V)
116 		printf("%6s  %-29.29s %.74s\n",
117 		    "", (xp->pr_name[0] != '\0') ? xp->pr_name : "", state);
118 
119 	/* cpusetid. */
120 	if (flags & FLAG_V)
121 		printf("%6s  %-6d\n",
122 		    "", xp->pr_cpusetid);
123 
124 	q = (char *)(xp + 1);
125 	/* IPv4 addresses. */
126 	iap = (struct in_addr *)(void *)q;
127 	q += (xp->pr_ip4s * sizeof(struct in_addr));
128 	if (q > end)
129 		errx(1, "Invalid length for jail");
130 	in.s_addr = 0;
131 	for (i = 0; i < xp->pr_ip4s; i++) {
132 		if (i == 0 || flags & FLAG_V)
133 			in.s_addr = iap[i].s_addr;
134 		if (flags & FLAG_V)
135 			printf("%6s  %-15.15s\n", "", inet_ntoa(in));
136 	}
137 	/* IPv6 addresses. */
138 	ia6p = (struct in6_addr *)(void *)q;
139 	q += (xp->pr_ip6s * sizeof(struct in6_addr));
140 	if (q > end)
141 		errx(1, "Invalid length for jail");
142 	for (i = 0; i < xp->pr_ip6s; i++) {
143 		if (flags & FLAG_V) {
144 			inet_ntop(AF_INET6, &ia6p[i], buf, sizeof(buf));
145 			printf("%6s  %s\n", "", buf);
146 		}
147 	}
148 
149 	/* If requested print the old style single line version. */
150 	if (!(flags & FLAG_V))
151 		printf("%6d  %-15.15s %-29.29s %.74s\n",
152 		    xp->pr_id, (in.s_addr) ? inet_ntoa(in) : "",
153 		    xp->pr_host, xp->pr_path);
154 
155 	return (q);
156 }
157 
158 static void
159 usage(void)
160 {
161 
162 	(void)fprintf(stderr, "usage: jls [-av]\n");
163 	exit(1);
164 }
165 
166 int
167 main(int argc, char *argv[])
168 {
169 	int ch, version;
170 	unsigned flags;
171 	size_t i, j, len;
172 	void *p, *q;
173 
174 	flags = 0;
175 	while ((ch = getopt(argc, argv, "av")) != -1) {
176 		switch (ch) {
177 		case 'a':
178 			flags |= FLAG_A;
179 			break;
180 		case 'v':
181 			flags |= FLAG_V;
182 			break;
183 		default:
184 			usage();
185 		}
186 	}
187 	argc -= optind;
188 	argv += optind;
189 
190 	if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
191 		err(1, "sysctlbyname(): security.jail.list");
192 
193 	j = len;
194 	for (i = 0; i < 4; i++) {
195 		if (len <= 0)
196 			exit(0);
197 		p = q = malloc(len);
198 		if (p == NULL)
199 			err(1, "malloc()");
200 
201 		if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) {
202 			if (errno == ENOMEM) {
203 				free(p);
204 				p = NULL;
205 				len += j;
206 				continue;
207 			}
208 			err(1, "sysctlbyname(): security.jail.list");
209 		}
210 		break;
211 	}
212 	if (p == NULL)
213 		err(1, "sysctlbyname(): security.jail.list");
214 	if (len < sizeof(int))
215 		errx(1, "This is no prison. Kernel and userland out of sync?");
216 	version = *(int *)p;
217 	if (version > XPRISON_VERSION)
218 		errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
219 
220 	if (flags & FLAG_V) {
221 		printf("   JID  Hostname                      Path\n");
222 		printf("        Name                          State\n");
223 		printf("        CPUSetID\n");
224 		printf("        IP Address(es)\n");
225 	} else {
226 		printf("   JID  IP Address      Hostname"
227 		    "                      Path\n");
228 	}
229 	for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) {
230 		version = *(int *)q;
231 		if (version > XPRISON_VERSION)
232 			errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
233 		switch (version) {
234 #ifdef SUPPORT_OLD_XPRISON
235 		case 1:
236 			q = print_xprison_v1(q, (char *)p + len, flags);
237 			break;
238 		case 2:
239 			errx(1, "Version 2 was used by multi-IPv4 jail "
240 			    "implementations that never made it into the "
241 			    "official kernel.");
242 			/* NOTREACHED */
243 			break;
244 #endif
245 		case 3:
246 			q = print_xprison_v3(q, (char *)p + len, flags);
247 			break;
248 		default:
249 			errx(1, "Prison unknown. Kernel/userland out of sync?");
250 			/* NOTREACHED */
251 			break;
252 		}
253 	}
254 
255 	free(p);
256 	exit(0);
257 }
258