]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/jail/state.c
Add deprecation notice for bvmconsole and bvmdebug
[FreeBSD/FreeBSD.git] / usr.sbin / jail / state.c
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 }