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