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
dep_setup(int docf)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
dep_check(struct cfjail * j)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
dep_done(struct cfjail * j,unsigned flags)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
dep_reset(struct cfjail * j)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 *
next_jail(void)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
start_state(const char * target,int docf,unsigned state,int running)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
requeue(struct cfjail * j,struct cfjails * queue)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
requeue_head(struct cfjail * j,struct cfjails * queue)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
dep_add(struct cfjail * from,struct cfjail * to,unsigned flags)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
cmp_jailptr(const void * a,const void * b)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
cmp_jailptr_name(const void * a,const void * b)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 *
find_jail(const char * name)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 *
running_jail(const char * name,int flags)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