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