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 int running_jid(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
dep_setup(int docf)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_jid(s->s, 0) < 0) {
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
dep_check(struct cfjail * j)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
dep_done(struct cfjail * j,unsigned flags)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
dep_reset(struct cfjail * j)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 *
next_jail(void)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
start_state(const char * target,int docf,unsigned state,int running)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 if ((jid = running_jid(target, JAIL_DYING)) > 0) {
373 j = add_jail();
374 j->name = estrdup(target);
375 j->jid = jid;
376 }
377 }
378 if (j == NULL) {
379 warnx("\"%s\" not found", target);
380 return -1;
381 }
382 j->flags = (j->flags & JF_FAILED) | state;
383 dep_reset(j);
384 requeue(j, &ready);
385 }
386 return 0;
387 }
388
389 /*
390 * Move a jail to a new list.
391 */
392 void
requeue(struct cfjail * j,struct cfjails * queue)393 requeue(struct cfjail *j, struct cfjails *queue)
394 {
395 if (j->queue != queue) {
396 TAILQ_REMOVE(j->queue, j, tq);
397 TAILQ_INSERT_TAIL(queue, j, tq);
398 j->queue = queue;
399 }
400 }
401
402 void
requeue_head(struct cfjail * j,struct cfjails * queue)403 requeue_head(struct cfjail *j, struct cfjails *queue)
404 {
405 TAILQ_REMOVE(j->queue, j, tq);
406 TAILQ_INSERT_HEAD(queue, j, tq);
407 j->queue = queue;
408 }
409
410 /*
411 * Add a dependency edge between two jails.
412 */
413 static void
dep_add(struct cfjail * from,struct cfjail * to,unsigned flags)414 dep_add(struct cfjail *from, struct cfjail *to, unsigned flags)
415 {
416 struct cfdepend *d;
417
418 d = emalloc(sizeof(struct cfdepend));
419 d->flags = flags;
420 d->j[DEP_FROM] = from;
421 d->j[DEP_TO] = to;
422 STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]);
423 STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]);
424 }
425
426 /*
427 * Compare jail pointers for qsort/bsearch.
428 */
429 static int
cmp_jailptr(const void * a,const void * b)430 cmp_jailptr(const void *a, const void *b)
431 {
432 return strcmp((*((struct cfjail * const *)a))->name,
433 ((*(struct cfjail * const *)b))->name);
434 }
435
436 static int
cmp_jailptr_name(const void * a,const void * b)437 cmp_jailptr_name(const void *a, const void *b)
438 {
439 return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name);
440 }
441
442 /*
443 * Find a jail object by name.
444 */
445 static struct cfjail *
find_jail(const char * name)446 find_jail(const char *name)
447 {
448 struct cfjail **jp;
449
450 jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *),
451 cmp_jailptr_name);
452 return jp ? *jp : NULL;
453 }
454
455 /*
456 * Return the named jail's jid if it is running, and -1 if it isn't.
457 */
458 static int
running_jid(const char * name,int flags)459 running_jid(const char *name, int flags)
460 {
461 struct iovec jiov[2];
462 char *ep;
463 int jid;
464
465 if ((jid = strtol(name, &ep, 10)) && !*ep) {
466 jiov[0].iov_base = __DECONST(char *, "jid");
467 jiov[0].iov_len = sizeof("jid");
468 jiov[1].iov_base = &jid;
469 jiov[1].iov_len = sizeof(jid);
470 } else {
471 jiov[0].iov_base = __DECONST(char *, "name");
472 jiov[0].iov_len = sizeof("name");
473 jiov[1].iov_len = strlen(name) + 1;
474 jiov[1].iov_base = alloca(jiov[1].iov_len);
475 strcpy(jiov[1].iov_base, name);
476 }
477 return jail_get(jiov, 2, flags);
478 }
479