1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2011 James Gritton 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/uio.h> 33 34 #include <err.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #include "jailp.h" 39 40 struct cfjails ready = TAILQ_HEAD_INITIALIZER(ready); 41 struct cfjails depend = TAILQ_HEAD_INITIALIZER(depend); 42 43 static void dep_add(struct cfjail *from, struct cfjail *to, unsigned flags); 44 static int cmp_jailptr(const void *a, const void *b); 45 static int cmp_jailptr_name(const void *a, const void *b); 46 static struct cfjail *find_jail(const char *name); 47 static struct cfjail *running_jail(const char *name, int flags); 48 49 static struct cfjail **jails_byname; 50 static size_t njails; 51 52 /* 53 * Set up jail dependency lists. 54 */ 55 void 56 dep_setup(int docf) 57 { 58 struct cfjail *j, *dj; 59 struct cfparam *p; 60 struct cfstring *s; 61 struct cfdepend *d; 62 const char *cs; 63 char *pname; 64 size_t plen; 65 int deps, ldeps; 66 67 if (!docf) { 68 /* 69 * With no config file, let "depend" for a single jail 70 * look at currently running jails. 71 */ 72 if ((j = TAILQ_FIRST(&cfjails)) && 73 (p = j->intparams[IP_DEPEND])) { 74 TAILQ_FOREACH(s, &p->val, tq) { 75 if (running_jail(s->s, 0) == NULL) { 76 warnx("depends on nonexistent jail " 77 "\"%s\"", s->s); 78 j->flags |= JF_FAILED; 79 } 80 } 81 } 82 return; 83 } 84 85 njails = 0; 86 TAILQ_FOREACH(j, &cfjails, tq) 87 njails++; 88 jails_byname = emalloc(njails * sizeof(struct cfjail *)); 89 njails = 0; 90 TAILQ_FOREACH(j, &cfjails, tq) 91 jails_byname[njails++] = j; 92 qsort(jails_byname, njails, sizeof(struct cfjail *), cmp_jailptr); 93 deps = 0; 94 ldeps = 0; 95 plen = 0; 96 pname = NULL; 97 TAILQ_FOREACH(j, &cfjails, tq) { 98 if (j->flags & JF_FAILED) 99 continue; 100 if ((p = j->intparams[IP_DEPEND])) { 101 TAILQ_FOREACH(s, &p->val, tq) { 102 dj = find_jail(s->s); 103 if (dj != NULL) { 104 deps++; 105 dep_add(j, dj, 0); 106 } else { 107 jail_warnx(j, 108 "depends on undefined jail \"%s\"", 109 s->s); 110 j->flags |= JF_FAILED; 111 } 112 } 113 } 114 /* A jail has an implied dependency on its parent. */ 115 if ((cs = strrchr(j->name, '.'))) 116 { 117 if (plen < (size_t)(cs - j->name + 1)) { 118 plen = (cs - j->name) + 1; 119 pname = erealloc(pname, plen); 120 } 121 strlcpy(pname, j->name, plen); 122 dj = find_jail(pname); 123 if (dj != NULL) { 124 ldeps++; 125 dep_add(j, dj, DF_LIGHT); 126 } 127 } 128 } 129 130 /* Look for dependency loops. */ 131 if (deps && (deps > 1 || ldeps)) { 132 (void)start_state(NULL, 0, 0, 0); 133 while ((j = TAILQ_FIRST(&ready))) { 134 requeue(j, &cfjails); 135 dep_done(j, DF_NOFAIL); 136 } 137 while ((j = TAILQ_FIRST(&depend)) != NULL) { 138 jail_warnx(j, "dependency loop"); 139 j->flags |= JF_FAILED; 140 do { 141 requeue(j, &cfjails); 142 dep_done(j, DF_NOFAIL); 143 } while ((j = TAILQ_FIRST(&ready))); 144 } 145 TAILQ_FOREACH(j, &cfjails, tq) 146 STAILQ_FOREACH(d, &j->dep[DEP_FROM], tq[DEP_FROM]) 147 d->flags &= ~DF_SEEN; 148 } 149 if (pname != NULL) 150 free(pname); 151 } 152 153 /* 154 * Return if a jail has dependencies. 155 */ 156 int 157 dep_check(struct cfjail *j) 158 { 159 int reset, depfrom, depto, ndeps, rev; 160 struct cfjail *dj; 161 struct cfdepend *d; 162 163 static int bits[] = { 0, 1, 1, 2, 1, 2, 2, 3 }; 164 165 if (j->ndeps == 0) 166 return 0; 167 ndeps = 0; 168 if ((rev = JF_DO_STOP(j->flags))) { 169 depfrom = DEP_TO; 170 depto = DEP_FROM; 171 } else { 172 depfrom = DEP_FROM; 173 depto = DEP_TO; 174 } 175 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) { 176 if (d->flags & DF_SEEN) 177 continue; 178 dj = d->j[depto]; 179 if (dj->flags & JF_FAILED) { 180 if (!(j->flags & (JF_DEPEND | JF_FAILED)) && 181 verbose >= 0) 182 jail_warnx(j, "skipped"); 183 j->flags |= JF_FAILED; 184 continue; 185 } 186 /* 187 * The dependee's state may be set (or changed) as a result of 188 * being in a dependency it wasn't in earlier. 189 */ 190 reset = 0; 191 if (bits[dj->flags & JF_OP_MASK] <= 1) { 192 if (!(dj->flags & JF_OP_MASK)) { 193 reset = 1; 194 dj->flags |= JF_DEPEND; 195 requeue(dj, &ready); 196 } 197 /* Set or change the dependee's state. */ 198 switch (j->flags & JF_OP_MASK) { 199 case JF_START: 200 dj->flags |= JF_START; 201 break; 202 case JF_SET: 203 if (!(dj->flags & JF_OP_MASK)) 204 dj->flags |= JF_SET; 205 else if (dj->flags & JF_STOP) 206 dj->flags |= JF_START; 207 break; 208 case JF_STOP: 209 case JF_RESTART: 210 if (!(dj->flags & JF_STOP)) 211 reset = 1; 212 dj->flags |= JF_STOP; 213 if (dj->flags & JF_SET) 214 dj->flags ^= (JF_START | JF_SET); 215 break; 216 } 217 } 218 if (reset) 219 dep_reset(dj); 220 if (!((d->flags & DF_LIGHT) && 221 (rev ? dj->jid < 0 : dj->jid > 0))) 222 ndeps++; 223 } 224 if (ndeps == 0) 225 return 0; 226 requeue(j, &depend); 227 return 1; 228 } 229 230 /* 231 * Resolve any dependencies from a finished jail. 232 */ 233 void 234 dep_done(struct cfjail *j, unsigned flags) 235 { 236 struct cfjail *dj; 237 struct cfdepend *d; 238 int depfrom, depto; 239 240 if (JF_DO_STOP(j->flags)) { 241 depfrom = DEP_TO; 242 depto = DEP_FROM; 243 } else { 244 depfrom = DEP_FROM; 245 depto = DEP_TO; 246 } 247 STAILQ_FOREACH(d, &j->dep[depto], tq[depto]) { 248 if ((d->flags & DF_SEEN) | (flags & ~d->flags & DF_LIGHT)) 249 continue; 250 d->flags |= DF_SEEN; 251 dj = d->j[depfrom]; 252 if (!(flags & DF_NOFAIL) && (j->flags & JF_FAILED) && 253 (j->flags & (JF_OP_MASK | JF_DEPEND)) != 254 (JF_SET | JF_DEPEND)) { 255 if (!(dj->flags & (JF_DEPEND | JF_FAILED)) && 256 verbose >= 0) 257 jail_warnx(dj, "skipped"); 258 dj->flags |= JF_FAILED; 259 } 260 if (!--dj->ndeps && dj->queue == &depend) 261 requeue(dj, &ready); 262 } 263 } 264 265 /* 266 * Count a jail's dependencies and mark them as unseen. 267 */ 268 void 269 dep_reset(struct cfjail *j) 270 { 271 int depfrom; 272 struct cfdepend *d; 273 274 depfrom = JF_DO_STOP(j->flags) ? DEP_TO : DEP_FROM; 275 j->ndeps = 0; 276 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) 277 j->ndeps++; 278 } 279 280 /* 281 * Find the next jail ready to do something. 282 */ 283 struct cfjail * 284 next_jail(void) 285 { 286 struct cfjail *j; 287 288 if (!(j = next_proc(!TAILQ_EMPTY(&ready))) && 289 (j = TAILQ_FIRST(&ready)) && JF_DO_STOP(j->flags) && 290 (j = TAILQ_LAST(&ready, cfjails)) && !JF_DO_STOP(j->flags)) { 291 TAILQ_FOREACH_REVERSE(j, &ready, cfjails, tq) 292 if (JF_DO_STOP(j->flags)) 293 break; 294 } 295 if (j != NULL) 296 requeue(j, &cfjails); 297 return j; 298 } 299 300 /* 301 * Set jails to the proper start state. 302 */ 303 int 304 start_state(const char *target, int docf, unsigned state, int running) 305 { 306 struct iovec jiov[6]; 307 struct cfjail *j, *tj; 308 int jid; 309 char namebuf[MAXHOSTNAMELEN]; 310 311 if (!target || (!docf && state != JF_STOP) || 312 (!running && !strcmp(target, "*"))) { 313 /* 314 * For a global wildcard (including no target specified), 315 * set the state on all jails and start with those that 316 * have no dependencies. 317 */ 318 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 319 j->flags = (j->flags & JF_FAILED) | state | 320 (docf ? JF_WILD : 0); 321 dep_reset(j); 322 requeue(j, j->ndeps ? &depend : &ready); 323 } 324 } else if (wild_jail_name(target)) { 325 /* 326 * For targets specified singly, or with a non-global wildcard, 327 * set their state and call them ready (even if there are 328 * dependencies). Leave everything else unqueued for now. 329 */ 330 if (running) { 331 /* 332 * -R matches its wildcards against currently running 333 * jails, not against the config file. 334 */ 335 jiov[0].iov_base = __DECONST(char *, "lastjid"); 336 jiov[0].iov_len = sizeof("lastjid"); 337 jiov[1].iov_base = &jid; 338 jiov[1].iov_len = sizeof(jid); 339 jiov[2].iov_base = __DECONST(char *, "jid"); 340 jiov[2].iov_len = sizeof("jid"); 341 jiov[3].iov_base = &jid; 342 jiov[3].iov_len = sizeof(jid); 343 jiov[4].iov_base = __DECONST(char *, "name"); 344 jiov[4].iov_len = sizeof("name"); 345 jiov[5].iov_base = &namebuf; 346 jiov[5].iov_len = sizeof(namebuf); 347 for (jid = 0; jail_get(jiov, 6, 0) > 0; ) { 348 if (wild_jail_match(namebuf, target)) { 349 j = add_jail(); 350 j->name = estrdup(namebuf); 351 j->jid = jid; 352 j->flags = (j->flags & JF_FAILED) | 353 state | JF_WILD; 354 dep_reset(j); 355 requeue(j, &ready); 356 } 357 } 358 } else { 359 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 360 if (wild_jail_match(j->name, target)) { 361 j->flags = (j->flags & JF_FAILED) | 362 state | JF_WILD; 363 dep_reset(j); 364 requeue(j, &ready); 365 } 366 } 367 } 368 } else { 369 j = find_jail(target); 370 if (j == NULL && state == JF_STOP) { 371 /* Allow -[rR] to specify a currently running jail. */ 372 j = running_jail(target, JAIL_DYING); 373 } 374 if (j == NULL) { 375 warnx("\"%s\" not found", target); 376 return -1; 377 } 378 j->flags = (j->flags & JF_FAILED) | state; 379 dep_reset(j); 380 requeue(j, &ready); 381 } 382 return 0; 383 } 384 385 /* 386 * Move a jail to a new list. 387 */ 388 void 389 requeue(struct cfjail *j, struct cfjails *queue) 390 { 391 if (j->queue != queue) { 392 TAILQ_REMOVE(j->queue, j, tq); 393 TAILQ_INSERT_TAIL(queue, j, tq); 394 j->queue = queue; 395 } 396 } 397 398 void 399 requeue_head(struct cfjail *j, struct cfjails *queue) 400 { 401 TAILQ_REMOVE(j->queue, j, tq); 402 TAILQ_INSERT_HEAD(queue, j, tq); 403 j->queue = queue; 404 } 405 406 /* 407 * Add a dependency edge between two jails. 408 */ 409 static void 410 dep_add(struct cfjail *from, struct cfjail *to, unsigned flags) 411 { 412 struct cfdepend *d; 413 414 d = emalloc(sizeof(struct cfdepend)); 415 d->flags = flags; 416 d->j[DEP_FROM] = from; 417 d->j[DEP_TO] = to; 418 STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]); 419 STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]); 420 } 421 422 /* 423 * Compare jail pointers for qsort/bsearch. 424 */ 425 static int 426 cmp_jailptr(const void *a, const void *b) 427 { 428 return strcmp((*((struct cfjail * const *)a))->name, 429 ((*(struct cfjail * const *)b))->name); 430 } 431 432 static int 433 cmp_jailptr_name(const void *a, const void *b) 434 { 435 return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name); 436 } 437 438 /* 439 * Find a jail object by name. 440 */ 441 static struct cfjail * 442 find_jail(const char *name) 443 { 444 struct cfjail **jp; 445 446 if (jails_byname == NULL) 447 return NULL; 448 449 jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *), 450 cmp_jailptr_name); 451 return jp ? *jp : NULL; 452 } 453 454 /* 455 * Return jail if it is running, and NULL if it isn't. 456 */ 457 static struct cfjail * 458 running_jail(const char *name, int flags) 459 { 460 struct iovec jiov[4]; 461 struct cfjail *jail; 462 char *ep; 463 char jailname[MAXHOSTNAMELEN]; 464 int jid, ret, len; 465 466 if ((jid = strtol(name, &ep, 10)) && !*ep) { 467 memset(jailname,0,sizeof(jailname)); 468 len = sizeof(jailname); 469 } else { 470 strncpy(jailname, name,sizeof(jailname)); 471 len = strlen(name) + 1; 472 jid = 0; 473 } 474 475 jiov[0].iov_base = __DECONST(char *, "jid"); 476 jiov[0].iov_len = sizeof("jid"); 477 jiov[1].iov_base = &jid; 478 jiov[1].iov_len = sizeof(jid); 479 jiov[2].iov_base = __DECONST(char *, "name"); 480 jiov[2].iov_len = sizeof("name"); 481 jiov[3].iov_base = &jailname; 482 jiov[3].iov_len = len; 483 484 if ((ret = jail_get(jiov, 4, flags)) < 0) 485 return (NULL); 486 487 if ((jail = find_jail(jailname)) == NULL) { 488 jail = add_jail(); 489 jail->name = estrdup(jailname); 490 jail->jid = ret; 491 } 492 493 return (jail); 494 } 495