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