]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libjail/jail.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libjail / jail.c
1 /*-
2  * Copyright (c) 2009 James Gritton.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/jail.h>
33 #include <sys/socket.h>
34 #include <sys/sysctl.h>
35
36 #include <arpa/inet.h>
37 #include <netinet/in.h>
38
39 #include <errno.h>
40 #include <inttypes.h>
41 #include <stdio.h>
42 #include <stdarg.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "jail.h"
47
48 #define SJPARAM         "security.jail.param"
49
50 #define JPS_IN_ADDR     1
51 #define JPS_IN6_ADDR    2
52
53 #define ARRAY_SANITY    5
54 #define ARRAY_SLOP      5
55
56
57 static int jailparam_import_enum(const char **values, int nvalues,
58     const char *valstr, size_t valsize, int *value);
59 static int jailparam_vlist(struct jailparam **jpp, va_list ap);
60 static int jailparam_type(struct jailparam *jp);
61 static char *noname(const char *name);
62 static char *nononame(const char *name);
63
64 char jail_errmsg[JAIL_ERRMSGLEN];
65
66 static const char *bool_values[] = { "false", "true" };
67 static const char *jailsys_values[] = { "disable", "new", "inherit" };
68
69
70 /*
71  * Import a null-terminated parameter list and set a jail with the flags
72  * and parameters.
73  */
74 int
75 jail_setv(int flags, ...)
76 {
77         va_list ap;
78         struct jailparam *jp;
79         int njp;
80
81         va_start(ap, flags);
82         njp = jailparam_vlist(&jp, ap);
83         va_end(ap);
84         if (njp < 0)
85                 return (njp);
86         return (jailparam_set(jp, njp, flags));
87 }
88
89 /*
90  * Read a null-terminated parameter list, get the referenced jail, and export
91  * the parameters to the list.
92  */
93 int
94 jail_getv(int flags, ...)
95 {
96         va_list ap, tap;
97         struct jailparam *jp;
98         char *valarg;
99         const char *value;
100         int njp, i, jid, namekey, zero;
101
102         va_start(ap, flags);
103         va_copy(tap, ap);
104         njp = jailparam_vlist(&jp, tap);
105         va_end(tap);
106         if (njp < 0)
107                 return (njp);
108         /*
109          * See if the name is the search key.  If so, we don't want to write
110          * it back in case it's a read-only string.
111          */
112         namekey = 1;
113         zero = 0;
114         for (i = 0; i < njp; i++) {
115                 if (!strcmp(jp->jp_name, "lastjid") ||
116                     (!strcmp(jp->jp_name, "jid") &&
117                      memcmp(jp->jp_value, &zero, sizeof(zero))))
118                         namekey = 0;
119         }
120         jid = jailparam_get(jp, njp, flags);
121         if (jid < 0) {
122                 va_end(ap);
123                 return (-1);
124         }
125         for (i = 0; i < njp; i++) {
126                 (void)va_arg(ap, char *);
127                 value = jailparam_export(jp + i);
128                 if (value == NULL) {
129                         va_end(ap);
130                         return (-1);
131                 }
132                 valarg = va_arg(ap, char *);
133                 if (!namekey || strcmp(jp[i].jp_name, "name"))
134                         /* It's up to the caller to ensure there's room. */
135                         strcpy(valarg, value);
136         }
137         va_end(ap);
138         return (jid);
139 }
140
141 /*
142  * Return a list of all known parameters.
143  */
144 int
145 jailparam_all(struct jailparam **jpp)
146 {
147         struct jailparam *jp;
148         size_t mlen1, mlen2, buflen;
149         int njp, nlist;
150         int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2];
151         char buf[MAXPATHLEN];
152
153         njp = 0;
154         nlist = 32;
155         jp = malloc(nlist * sizeof(*jp));
156         if (jp == NULL) {
157                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
158                 return (-1);
159         }
160         mib1[0] = 0;
161         mib1[1] = 2;
162         mlen1 = CTL_MAXNAME - 2;
163         if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) {
164                 snprintf(jail_errmsg, JAIL_ERRMSGLEN,
165                     "sysctlnametomib(" SJPARAM "): %s", strerror(errno));
166                 goto error;
167         }
168         for (;; njp++) {
169                 /* Get the next parameter. */
170                 mlen2 = sizeof(mib2);
171                 if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) {
172                         snprintf(jail_errmsg, JAIL_ERRMSGLEN,
173                             "sysctl(0.2): %s", strerror(errno));
174                         goto error;
175                 }
176                 if (mib2[0] != mib1[2] || mib2[1] != mib1[3] ||
177                     mib2[2] != mib1[4])
178                         break;
179                 /* Convert it to an ascii name. */
180                 memcpy(mib1 + 2, mib2, mlen2);
181                 mlen1 = mlen2 / sizeof(int);
182                 mib1[1] = 1;
183                 buflen = sizeof(buf);
184                 if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) {
185                         snprintf(jail_errmsg, JAIL_ERRMSGLEN,
186                             "sysctl(0.1): %s", strerror(errno));
187                         goto error;
188                 }
189                 if (buf[buflen - 2] == '.')
190                         buf[buflen - 2] = '\0';
191                 /* Add the parameter to the list */
192                 if (njp >= nlist) {
193                         nlist *= 2;
194                         jp = realloc(jp, nlist * sizeof(*jp));
195                         if (jp == NULL) {
196                                 jailparam_free(jp, njp);
197                                 return (-1);
198                         }
199                 }
200                 if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0)
201                         goto error;
202                 if (jailparam_type(jp + njp) < 0) {
203                         njp++;
204                         goto error;
205                 }
206                 mib1[1] = 2;
207         }
208         jp = realloc(jp, njp * sizeof(*jp));
209         *jpp = jp;
210         return (njp);
211
212  error:
213         jailparam_free(jp, njp);
214         free(jp);
215         return (-1);
216 }
217
218 /*
219  * Clear a jail parameter and copy in its name.
220  */
221 int
222 jailparam_init(struct jailparam *jp, const char *name)
223 {
224
225         memset(jp, 0, sizeof(*jp));
226         jp->jp_name = strdup(name);
227         if (jp->jp_name == NULL) {
228                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
229                 return (-1);
230         }
231         return (0);
232 }
233
234 /*
235  * Put a name and value into a jail parameter element, converting the value
236  * to internal form.
237  */
238 int
239 jailparam_import(struct jailparam *jp, const char *value)
240 {
241         char *p, *ep, *tvalue;
242         const char *avalue;
243         int i, nval, fw;
244
245         if (!jp->jp_ctltype && jailparam_type(jp) < 0)
246                 return (-1);
247         if (value == NULL)
248                 return (0);
249         if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) {
250                 jp->jp_value = strdup(value);
251                 if (jp->jp_value == NULL) {
252                         strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
253                         return (-1);
254                 }
255                 return (0);
256         }
257         nval = 1;
258         if (jp->jp_elemlen) {
259                 if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) {
260                         jp->jp_value = strdup("");
261                         if (jp->jp_value == NULL) {
262                                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
263                                 return (-1);
264                         }
265                         jp->jp_valuelen = 0;
266                         return (0);
267                 }
268                 for (p = strchr(value, ','); p; p = strchr(p + 1, ','))
269                         nval++;
270                 jp->jp_valuelen = jp->jp_elemlen * nval;
271         }
272         jp->jp_value = malloc(jp->jp_valuelen);
273         if (jp->jp_value == NULL) {
274                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
275                 return (-1);
276         }
277         avalue = value;
278         for (i = 0; i < nval; i++) {
279                 fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ",");
280                 switch (jp->jp_ctltype & CTLTYPE) {
281                 case CTLTYPE_INT:
282                         if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) {
283                                 if (!jailparam_import_enum(bool_values, 2,
284                                     avalue, fw, &((int *)jp->jp_value)[i])) {
285                                         snprintf(jail_errmsg,
286                                             JAIL_ERRMSGLEN, "%s: "
287                                             "unknown boolean value \"%.*s\"",
288                                             jp->jp_name, fw, avalue);
289                                         errno = EINVAL;
290                                         goto error;
291                                 }
292                                 break;
293                         }
294                         if (jp->jp_flags & JP_JAILSYS) {
295                                 /*
296                                  * Allow setting a jailsys parameter to "new"
297                                  * in a booleanesque fashion.
298                                  */
299                                 if (value[0] == '\0')
300                                         ((int *)jp->jp_value)[i] = JAIL_SYS_NEW;
301                                 else if (!jailparam_import_enum(jailsys_values,
302                                     sizeof(jailsys_values) /
303                                     sizeof(jailsys_values[0]), avalue, fw,
304                                     &((int *)jp->jp_value)[i])) {
305                                         snprintf(jail_errmsg,
306                                             JAIL_ERRMSGLEN, "%s: "
307                                             "unknown jailsys value \"%.*s\"",
308                                             jp->jp_name, fw, avalue);
309                                         errno = EINVAL;
310                                         goto error;
311                                 }
312                                 break;
313                         }
314                         ((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10);
315                 integer_test:
316                         if (ep != avalue + fw) {
317                                 snprintf(jail_errmsg, JAIL_ERRMSGLEN,
318                                     "%s: non-integer value \"%.*s\"",
319                                     jp->jp_name, fw, avalue);
320                                 errno = EINVAL;
321                                 goto error;
322                         }
323                         break;
324                 case CTLTYPE_UINT:
325                         ((unsigned *)jp->jp_value)[i] =
326                             strtoul(avalue, &ep, 10);
327                         goto integer_test;
328                 case CTLTYPE_LONG:
329                         ((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10);
330                         goto integer_test;
331                 case CTLTYPE_ULONG:
332                         ((unsigned long *)jp->jp_value)[i] =
333                             strtoul(avalue, &ep, 10);
334                         goto integer_test;
335                 case CTLTYPE_QUAD:
336                         ((int64_t *)jp->jp_value)[i] =
337                             strtoimax(avalue, &ep, 10);
338                         goto integer_test;
339                 case CTLTYPE_STRUCT:
340                         tvalue = alloca(fw + 1);
341                         strlcpy(tvalue, avalue, fw + 1);
342                         switch (jp->jp_structtype) {
343                         case JPS_IN_ADDR:
344                                 if (inet_pton(AF_INET, tvalue,
345                                     &((struct in_addr *)jp->jp_value)[i]) != 1)
346                                 {
347                                         snprintf(jail_errmsg,
348                                             JAIL_ERRMSGLEN,
349                                             "%s: not an IPv4 address: %s",
350                                             jp->jp_name, tvalue);
351                                         errno = EINVAL;
352                                         goto error;
353                                 }
354                                 break;
355                         case JPS_IN6_ADDR:
356                                 if (inet_pton(AF_INET6, tvalue,
357                                     &((struct in6_addr *)jp->jp_value)[i]) != 1)
358                                 {
359                                         snprintf(jail_errmsg,
360                                             JAIL_ERRMSGLEN,
361                                             "%s: not an IPv6 address: %s",
362                                             jp->jp_name, tvalue);
363                                         errno = EINVAL;
364                                         goto error;
365                                 }
366                                 break;
367                         default:
368                                 goto unknown_type;
369                         }
370                         break;
371                 default:
372                 unknown_type:
373                         snprintf(jail_errmsg, JAIL_ERRMSGLEN,
374                             "unknown type for %s", jp->jp_name);
375                         errno = ENOENT;
376                         goto error;
377                 }
378                 avalue += fw + 1;
379         }
380         return (0);
381
382  error:
383         free(jp->jp_value);
384         jp->jp_value = NULL;
385         return (-1);
386 }
387
388 static int
389 jailparam_import_enum(const char **values, int nvalues, const char *valstr,
390     size_t valsize, int *value)
391 {
392         char *ep;
393         int i;
394
395         for (i = 0; i < nvalues; i++)
396                 if (valsize == strlen(values[i]) &&
397                     !strncasecmp(valstr, values[i], valsize)) {
398                         *value = i;
399                         return 1;
400                 }
401         *value = strtol(valstr, &ep, 10);
402         return (ep == valstr + valsize);
403 }
404
405 /*
406  * Put a name and value into a jail parameter element, copying the value
407  * but not altering it.
408  */
409 int
410 jailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen)
411 {
412
413         jp->jp_value = value;
414         jp->jp_valuelen = valuelen;
415         jp->jp_flags |= JP_RAWVALUE;
416         return (0);
417 }
418
419 /*
420  * Run the jail_set and jail_get system calls on a parameter list.
421  */
422 int
423 jailparam_set(struct jailparam *jp, unsigned njp, int flags)
424 {
425         struct iovec *jiov;
426         char *nname;
427         int i, jid, bool0;
428         unsigned j;
429
430         jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1));
431         bool0 = 0;
432         for (i = j = 0; j < njp; j++) {
433                 jiov[i].iov_base = jp[j].jp_name;
434                 jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
435                 i++;
436                 if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) {
437                         /*
438                          * Set booleans without values.  If one has a value of
439                          * zero, change it to (or from) its "no" counterpart.
440                          */
441                         jiov[i].iov_base = NULL;
442                         jiov[i].iov_len = 0;
443                         if (jp[j].jp_value != NULL &&
444                             jp[j].jp_valuelen == sizeof(int) &&
445                             !*(int *)jp[j].jp_value) {
446                                 bool0 = 1;
447                                 nname = jp[j].jp_flags & JP_BOOL
448                                     ? noname(jp[j].jp_name)
449                                     : nononame(jp[j].jp_name);
450                                 if (nname == NULL) {
451                                         njp = j;
452                                         jid = -1;
453                                         goto done;
454                                 }
455                                 jiov[i - 1].iov_base = nname;
456                                 jiov[i - 1].iov_len = strlen(nname) + 1;
457                                 
458                         }
459                 } else {
460                         /*
461                          * Try to fill in missing values with an empty string.
462                          */
463                         if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 &&
464                             jailparam_import(jp + j, "") < 0) {
465                                 njp = j;
466                                 jid = -1;
467                                 goto done;
468                         }
469                         jiov[i].iov_base = jp[j].jp_value;
470                         jiov[i].iov_len =
471                             (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING
472                             ? strlen(jp[j].jp_value) + 1
473                             : jp[j].jp_valuelen;
474                 }
475                 i++;
476         }
477         *(const void **)&jiov[i].iov_base = "errmsg";
478         jiov[i].iov_len = sizeof("errmsg");
479         i++;
480         jiov[i].iov_base = jail_errmsg;
481         jiov[i].iov_len = JAIL_ERRMSGLEN;
482         i++;
483         jail_errmsg[0] = 0;
484         jid = jail_set(jiov, i, flags);
485         if (jid < 0 && !jail_errmsg[0])
486                 snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s",
487                     strerror(errno));
488  done:
489         if (bool0)
490                 for (j = 0; j < njp; j++)
491                         if ((jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) &&
492                             jp[j].jp_value != NULL &&
493                             jp[j].jp_valuelen == sizeof(int) &&
494                             !*(int *)jp[j].jp_value)
495                                 free(jiov[j * 2].iov_base);
496         return (jid);
497 }
498
499 int
500 jailparam_get(struct jailparam *jp, unsigned njp, int flags)
501 {
502         struct iovec *jiov;
503         struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key;
504         int i, ai, ki, jid, arrays, sanity;
505         unsigned j;
506
507         /*
508          * Get the types for all parameters.
509          * Find the key and any array parameters.
510          */
511         jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1));
512         jp_lastjid = jp_jid = jp_name = NULL;
513         arrays = 0;
514         for (ai = j = 0; j < njp; j++) {
515                 if (!jp[j].jp_ctltype && jailparam_type(jp + j) < 0)
516                         return (-1);
517                 if (!strcmp(jp[j].jp_name, "lastjid"))
518                         jp_lastjid = jp + j;
519                 else if (!strcmp(jp[j].jp_name, "jid"))
520                         jp_jid = jp + j;
521                 else if (!strcmp(jp[j].jp_name, "name"))
522                         jp_name = jp + j;
523                 else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
524                         arrays = 1;
525                         jiov[ai].iov_base = jp[j].jp_name;
526                         jiov[ai].iov_len = strlen(jp[j].jp_name) + 1;
527                         ai++;
528                         jiov[ai].iov_base = NULL;
529                         jiov[ai].iov_len = 0;
530                         ai++;
531                 }
532         }
533         jp_key = jp_lastjid ? jp_lastjid :
534             jp_jid && jp_jid->jp_valuelen == sizeof(int) &&
535             jp_jid->jp_value && *(int *)jp_jid->jp_value ? jp_jid : jp_name;
536         if (jp_key == NULL || jp_key->jp_value == NULL) {
537                 strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN);
538                 errno = ENOENT;
539                 return (-1);
540         }
541         ki = ai;
542         jiov[ki].iov_base = jp_key->jp_name;
543         jiov[ki].iov_len = strlen(jp_key->jp_name) + 1;
544         ki++;
545         jiov[ki].iov_base = jp_key->jp_value;
546         jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING
547             ? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen;
548         ki++;
549         *(const void **)&jiov[ki].iov_base = "errmsg";
550         jiov[ki].iov_len = sizeof("errmsg");
551         ki++;
552         jiov[ki].iov_base = jail_errmsg;
553         jiov[ki].iov_len = JAIL_ERRMSGLEN;
554         ki++;
555         jail_errmsg[0] = 0;
556         if (arrays && jail_get(jiov, ki, flags) < 0) {
557                 if (!jail_errmsg[0])
558                         snprintf(jail_errmsg, sizeof(jail_errmsg),
559                             "jail_get: %s", strerror(errno));
560                 return (-1);
561         }
562         /* Allocate storage for all parameters. */
563         for (ai = j = 0, i = ki; j < njp; j++) {
564                 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
565                         ai++;
566                         jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP;
567                         if (jp[j].jp_valuelen >= jiov[ai].iov_len)
568                                 jiov[ai].iov_len = jp[j].jp_valuelen;
569                         else {
570                                 jp[j].jp_valuelen = jiov[ai].iov_len;
571                                 if (jp[j].jp_value != NULL)
572                                         free(jp[j].jp_value);
573                                 jp[j].jp_value = malloc(jp[j].jp_valuelen);
574                                 if (jp[j].jp_value == NULL) {
575                                         strerror_r(errno, jail_errmsg,
576                                             JAIL_ERRMSGLEN);
577                                         return (-1);
578                                 }
579                         }
580                         jiov[ai].iov_base = jp[j].jp_value;
581                         memset(jiov[ai].iov_base, 0, jiov[ai].iov_len);
582                         ai++;
583                 } else if (jp + j != jp_key) {
584                         jiov[i].iov_base = jp[j].jp_name;
585                         jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
586                         i++;
587                         if (jp[j].jp_value == NULL &&
588                             !(jp[j].jp_flags & JP_RAWVALUE)) {
589                                 jp[j].jp_value = malloc(jp[j].jp_valuelen);
590                                 if (jp[j].jp_value == NULL) {
591                                         strerror_r(errno, jail_errmsg,
592                                             JAIL_ERRMSGLEN);
593                                         return (-1);
594                                 }
595                         }
596                         jiov[i].iov_base = jp[j].jp_value;
597                         jiov[i].iov_len = jp[j].jp_valuelen;
598                         memset(jiov[i].iov_base, 0, jiov[i].iov_len);
599                         i++;
600                 }
601         }
602         /*
603          * Get the prison.  If there are array elements, retry a few times
604          * in case their sizes changed from under us.
605          */
606         for (sanity = 0;; sanity++) {
607                 jid = jail_get(jiov, i, flags);
608                 if (jid >= 0 || !arrays || sanity == ARRAY_SANITY ||
609                     errno != EINVAL || jail_errmsg[0])
610                         break;
611                 for (ai = j = 0; j < njp; j++) {
612                         if (jp[j].jp_elemlen &&
613                             !(jp[j].jp_flags & JP_RAWVALUE)) {
614                                 ai++;
615                                 jiov[ai].iov_base = NULL;
616                                 jiov[ai].iov_len = 0;
617                                 ai++;
618                         }
619                 }
620                 if (jail_get(jiov, ki, flags) < 0)
621                         break;
622                 for (ai = j = 0; j < njp; j++) {
623                         if (jp[j].jp_elemlen &&
624                             !(jp[j].jp_flags & JP_RAWVALUE)) {
625                                 ai++;
626                                 jiov[ai].iov_len +=
627                                     jp[j].jp_elemlen * ARRAY_SLOP;
628                                 if (jp[j].jp_valuelen >= jiov[ai].iov_len)
629                                         jiov[ai].iov_len = jp[j].jp_valuelen;
630                                 else {
631                                         jp[j].jp_valuelen = jiov[ai].iov_len;
632                                         if (jp[j].jp_value != NULL)
633                                                 free(jp[j].jp_value);
634                                         jp[j].jp_value =
635                                             malloc(jiov[ai].iov_len);
636                                         if (jp[j].jp_value == NULL) {
637                                                 strerror_r(errno, jail_errmsg,
638                                                     JAIL_ERRMSGLEN);
639                                                 return (-1);
640                                         }
641                                 }
642                                 jiov[ai].iov_base = jp[j].jp_value;
643                                 memset(jiov[ai].iov_base, 0, jiov[ai].iov_len);
644                                 ai++;
645                         }
646                 }
647         }
648         if (jid < 0 && !jail_errmsg[0])
649                 snprintf(jail_errmsg, sizeof(jail_errmsg),
650                     "jail_get: %s", strerror(errno));
651         for (ai = j = 0, i = ki; j < njp; j++) {
652                 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
653                         ai++;
654                         jp[j].jp_valuelen = jiov[ai].iov_len;
655                         ai++;
656                 } else if (jp + j != jp_key) {
657                         i++;
658                         jp[j].jp_valuelen = jiov[i].iov_len;
659                         i++;
660                 }
661         }
662         return (jid);
663 }
664
665 /*
666  * Convert a jail parameter's value to external form.
667  */
668 char *
669 jailparam_export(struct jailparam *jp)
670 {
671         char *value, *tvalue, **values;
672         size_t valuelen;
673         int i, nval, ival;
674         char valbuf[INET6_ADDRSTRLEN];
675
676         if (!jp->jp_ctltype && jailparam_type(jp) < 0)
677                 return (NULL);
678         if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) {
679                 value = strdup(jp->jp_value);
680                 if (value == NULL)
681                         strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
682                 return (value);
683         }
684         nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1;
685         if (nval == 0) {
686                 value = strdup("");
687                 if (value == NULL)
688                         strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
689                 return (value);
690         }
691         values = alloca(nval * sizeof(char *));
692         valuelen = 0;
693         for (i = 0; i < nval; i++) {
694                 switch (jp->jp_ctltype & CTLTYPE) {
695                 case CTLTYPE_INT:
696                         ival = ((int *)jp->jp_value)[i];
697                         if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) &&
698                             (unsigned)ival < 2) {
699                                 strlcpy(valbuf, bool_values[ival],
700                                     sizeof(valbuf));
701                                 break;
702                         }
703                         if ((jp->jp_flags & JP_JAILSYS) &&
704                             (unsigned)ival < sizeof(jailsys_values) /
705                             sizeof(jailsys_values[0])) {
706                                 strlcpy(valbuf, jailsys_values[ival],
707                                     sizeof(valbuf));
708                                 break;
709                         }
710                         snprintf(valbuf, sizeof(valbuf), "%d", ival);
711                         break;
712                 case CTLTYPE_UINT:
713                         snprintf(valbuf, sizeof(valbuf), "%u",
714                             ((unsigned *)jp->jp_value)[i]);
715                         break;
716                 case CTLTYPE_LONG:
717                         snprintf(valbuf, sizeof(valbuf), "%ld",
718                             ((long *)jp->jp_value)[i]);
719                         break;
720                 case CTLTYPE_ULONG:
721                         snprintf(valbuf, sizeof(valbuf), "%lu",
722                             ((unsigned long *)jp->jp_value)[i]);
723                         break;
724                 case CTLTYPE_QUAD:
725                         snprintf(valbuf, sizeof(valbuf), "%jd",
726                             (intmax_t)((int64_t *)jp->jp_value)[i]);
727                         break;
728                 case CTLTYPE_STRUCT:
729                         switch (jp->jp_structtype) {
730                         case JPS_IN_ADDR:
731                                 if (inet_ntop(AF_INET,
732                                     &((struct in_addr *)jp->jp_value)[i],
733                                     valbuf, sizeof(valbuf)) == NULL) {
734                                         strerror_r(errno, jail_errmsg,
735                                             JAIL_ERRMSGLEN);
736
737                                         return (NULL);
738                                 }
739                                 break;
740                         case JPS_IN6_ADDR:
741                                 if (inet_ntop(AF_INET6,
742                                     &((struct in6_addr *)jp->jp_value)[i],
743                                     valbuf, sizeof(valbuf)) == NULL) {
744                                         strerror_r(errno, jail_errmsg,
745                                             JAIL_ERRMSGLEN);
746
747                                         return (NULL);
748                                 }
749                                 break;
750                         default:
751                                 goto unknown_type;
752                         }
753                         break;
754                 default:
755                 unknown_type:
756                         snprintf(jail_errmsg, JAIL_ERRMSGLEN,
757                             "unknown type for %s", jp->jp_name);
758                         errno = ENOENT;
759                         return (NULL);
760                 }
761                 valuelen += strlen(valbuf) + 1;
762                 values[i] = alloca(valuelen);
763                 strcpy(values[i], valbuf);
764         }
765         value = malloc(valuelen + 1);
766         if (value == NULL)
767                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
768         else {
769                 tvalue = value;
770                 for (i = 0; i < nval; i++) {
771                         strcpy(tvalue, values[i]);
772                         if (i < nval - 1) {
773                                 tvalue += strlen(values[i]);
774                                 *tvalue++ = ',';
775                         }
776                 }
777         }
778         return (value);
779 }
780
781 /*
782  * Free the contents of a jail parameter list (but not thst list itself).
783  */
784 void
785 jailparam_free(struct jailparam *jp, unsigned njp)
786 {
787         unsigned j;
788
789         for (j = 0; j < njp; j++) {
790                 free(jp[j].jp_name);
791                 if (!(jp[j].jp_flags & JP_RAWVALUE))
792                         free(jp[j].jp_value);
793         }
794 }
795
796 /*
797  * Create and import an array of jail parameters, given a list of name and
798  * value strings, terminated by a null name.
799  */
800 static int
801 jailparam_vlist(struct jailparam **jpp, va_list ap)
802 {
803         va_list tap;
804         struct jailparam *jp;
805         char *name, *value;
806         int njp;
807
808         va_copy(tap, ap);
809         for (njp = 0; va_arg(tap, char *) != NULL; njp++)
810                 (void)va_arg(tap, char *);
811         va_end(tap);
812         jp = calloc(njp, sizeof(struct jailparam));
813         if (jp == NULL) {
814                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
815                 return (-1);
816         }
817
818         for (njp = 0; (name = va_arg(ap, char *)) != NULL; njp++) {
819                 value = va_arg(ap, char *);
820                 if (jailparam_init(jp + njp, name) < 0 ||
821                     jailparam_import(jp + njp, value) < 0) {
822                         jailparam_free(jp, njp);
823                         free(jp);
824                         return (-1);
825                 }
826         }
827         *jpp = jp;
828         return (njp);
829 }
830
831 /*
832  * Find a parameter's type and size from its MIB.
833  */
834 static int
835 jailparam_type(struct jailparam *jp)
836 {
837         char *p, *nname;
838         size_t miblen, desclen;
839         int isarray;
840         struct {
841             int i;
842             char s[MAXPATHLEN];
843         } desc;
844         int mib[CTL_MAXNAME];
845
846         /* The "lastjid" parameter isn't real. */
847         if (!strcmp(jp->jp_name, "lastjid")) {
848                 jp->jp_valuelen = sizeof(int);
849                 jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR;
850                 return (0);
851         }
852
853         /* Find the sysctl that describes the parameter. */
854         mib[0] = 0;
855         mib[1] = 3;
856         snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", jp->jp_name);
857         miblen = sizeof(mib) - 2 * sizeof(int);
858         if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) {
859                 if (errno != ENOENT) {
860                         snprintf(jail_errmsg, JAIL_ERRMSGLEN,
861                             "sysctl(0.3.%s): %s", jp->jp_name, strerror(errno));
862                         return (-1);
863                 }
864                 /*
865                  * The parameter probably doesn't exist.  But it might be
866                  * the "no" counterpart to a boolean.
867                  */
868                 nname = nononame(jp->jp_name);
869                 if (nname != NULL) {
870                         snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname);
871                         free(nname);
872                         miblen = sizeof(mib) - 2 * sizeof(int);
873                         if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
874                             strlen(desc.s)) >= 0) {
875                                 mib[1] = 4;
876                                 desclen = sizeof(desc);
877                                 if (sysctl(mib, (miblen / sizeof(int)) + 2,
878                                            &desc, &desclen, NULL, 0) < 0) {
879                                         snprintf(jail_errmsg,
880                                             JAIL_ERRMSGLEN,
881                                             "sysctl(0.4.%s): %s", desc.s,
882                                             strerror(errno));
883                                         return (-1);
884                                 }
885                                 if ((desc.i & CTLTYPE) == CTLTYPE_INT &&
886                                     desc.s[0] == 'B') {
887                                         jp->jp_ctltype = desc.i;
888                                         jp->jp_flags |= JP_NOBOOL;
889                                         jp->jp_valuelen = sizeof(int);
890                                         return (0);
891                                 }
892                         }
893                 }
894         unknown_parameter:
895                 snprintf(jail_errmsg, JAIL_ERRMSGLEN,
896                     "unknown parameter: %s", jp->jp_name);
897                 errno = ENOENT;
898                 return (-1);
899         }
900  mib_desc:
901         mib[1] = 4;
902         desclen = sizeof(desc);
903         if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen,
904             NULL, 0) < 0) {
905                 snprintf(jail_errmsg, JAIL_ERRMSGLEN,
906                     "sysctl(0.4.%s): %s", jp->jp_name, strerror(errno));
907                 return (-1);
908         }
909         /* See if this is an array type. */
910         p = strchr(desc.s, '\0');
911         isarray  = 0;
912         if (p - 2 < desc.s || strcmp(p - 2, ",a"))
913                 isarray = 0;
914         else {
915                 isarray = 1;
916                 p[-2] = 0;
917         }
918         /* Look for types we understand */
919         jp->jp_ctltype = desc.i;
920         switch (desc.i & CTLTYPE) {
921         case CTLTYPE_INT:
922                 if (desc.s[0] == 'B')
923                         jp->jp_flags |= JP_BOOL;
924                 else if (!strcmp(desc.s, "E,jailsys"))
925                         jp->jp_flags |= JP_JAILSYS;
926         case CTLTYPE_UINT:
927                 jp->jp_valuelen = sizeof(int);
928                 break;
929         case CTLTYPE_LONG:
930         case CTLTYPE_ULONG:
931                 jp->jp_valuelen = sizeof(long);
932                 break;
933         case CTLTYPE_QUAD:
934                 jp->jp_valuelen = sizeof(int64_t);
935                 break;
936         case CTLTYPE_STRING:
937                 desc.s[0] = 0;
938                 desclen = sizeof(desc.s);
939                 if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen,
940                     NULL, 0) < 0) {
941                         snprintf(jail_errmsg, JAIL_ERRMSGLEN,
942                             "sysctl(" SJPARAM ".%s): %s", jp->jp_name,
943                             strerror(errno));
944                         return (-1);
945                 }
946                 jp->jp_valuelen = strtoul(desc.s, NULL, 10);
947                 break;
948         case CTLTYPE_STRUCT:
949                 if (!strcmp(desc.s, "S,in_addr")) {
950                         jp->jp_structtype = JPS_IN_ADDR;
951                         jp->jp_valuelen = sizeof(struct in_addr);
952                 } else if (!strcmp(desc.s, "S,in6_addr")) {
953                         jp->jp_structtype = JPS_IN6_ADDR;
954                         jp->jp_valuelen = sizeof(struct in6_addr);
955                 } else {
956                         desclen = 0;
957                         if (sysctl(mib + 2, miblen / sizeof(int),
958                             NULL, &jp->jp_valuelen, NULL, 0) < 0) {
959                                 snprintf(jail_errmsg, JAIL_ERRMSGLEN,
960                                     "sysctl(" SJPARAM ".%s): %s", jp->jp_name,
961                                     strerror(errno));
962                                 return (-1);
963                         }
964                 }
965                 break;
966         case CTLTYPE_NODE:
967                 /* A node might be described by an empty-named child. */
968                 mib[1] = 1;
969                 mib[(miblen / sizeof(int)) + 2] =
970                     mib[(miblen / sizeof(int)) + 1] - 1;
971                 miblen += sizeof(int);
972                 desclen = sizeof(desc.s);
973                 if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s, &desclen,
974                     NULL, 0) < 0) {
975                         snprintf(jail_errmsg, JAIL_ERRMSGLEN,
976                             "sysctl(0.1): %s", strerror(errno));
977                         return (-1);
978                 }
979                 if (desc.s[desclen - 2] != '.')
980                         goto unknown_parameter;
981                 goto mib_desc;
982         default:
983                 snprintf(jail_errmsg, JAIL_ERRMSGLEN,
984                     "unknown type for %s", jp->jp_name);
985                 errno = ENOENT;
986                 return (-1);
987         }
988         if (isarray) {
989                 jp->jp_elemlen = jp->jp_valuelen;
990                 jp->jp_valuelen = 0;
991         }
992         return (0);
993 }
994
995 /*
996  * Change a boolean parameter name into its "no" counterpart or vice versa.
997  */
998 static char *
999 noname(const char *name)
1000 {
1001         char *nname, *p;
1002
1003         nname = malloc(strlen(name) + 3);
1004         if (nname == NULL) {
1005                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
1006                 return (NULL);
1007         }
1008         p = strrchr(name, '.');
1009         if (p != NULL)
1010                 sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1);
1011         else
1012                 sprintf(nname, "no%s", name);
1013         return (nname);
1014 }
1015
1016 static char *
1017 nononame(const char *name)
1018 {
1019         char *p, *nname;
1020
1021         p = strrchr(name, '.');
1022         if (strncmp(p ? p + 1 : name, "no", 2)) {
1023                 snprintf(jail_errmsg, sizeof(jail_errmsg),
1024                     "mismatched boolean: %s", name);
1025                 errno = EINVAL;
1026                 return (NULL);
1027         }
1028         nname = malloc(strlen(name) - 1);
1029         if (nname == NULL) {
1030                 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
1031                 return (NULL);
1032         }
1033         if (p != NULL)
1034                 sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3);
1035         else
1036                 strcpy(nname, name + 2);
1037         return (nname);
1038 }