summaryrefslogtreecommitdiff
path: root/srcx/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'srcx/util.c')
-rw-r--r--srcx/util.c211
1 files changed, 127 insertions, 84 deletions
diff --git a/srcx/util.c b/srcx/util.c
index 8894c61..ffea8ff 100644
--- a/srcx/util.c
+++ b/srcx/util.c
@@ -57,112 +57,155 @@
#include <string.h>
#include <unistd.h>
+#include <netinet/in.h>
+
#include "util.h"
extern char** environ;
-size_t get_jail_sysctl(struct xprison** ret)
+void
+jails_load (jails *jls)
{
- struct xprison* xp;
- size_t len;
- *ret = NULL;
-
- if(sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
- err(1, "couldn't list jails");
-
-retry:
+ struct xprison *xp;
- if(len <= 0)
- return 0;
-
- xp = calloc(len, 1);
- if(xp == NULL)
- err(1, "out of memory");
-
- if(sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1)
- {
- if(errno == ENOMEM)
- {
- free(xp);
- goto retry;
- }
+ memset (jls, 0, sizeof (jails));
- err(1, "couldn't list jails");
- }
+ if(sysctlbyname("security.jail.list", NULL, &jls->length, NULL, 0) == -1)
+ err(1, "couldn't list jails");
- if(len < sizeof(*xp) || len % sizeof(*xp) || xp->pr_version != XPRISON_VERSION)
- errx(1, "kernel and userland out of sync");
+retry:
- *ret = xp;
- return len / sizeof(*xp);
+ if(jls->length <= 0)
+ {
+ jls->data = NULL;
+ jls->last = NULL;
+ }
+
+ jls->data = calloc(jls->length, 1);
+ if(jls->data == NULL)
+ err(1, "out of memory");
+
+ if(sysctlbyname("security.jail.list", jls->data, &jls->length, NULL, 0) == -1)
+ {
+ if(errno == ENOMEM)
+ {
+ free(jls->data);
+ jls->data = NULL;
+ goto retry;
+ }
+
+ err(1, "couldn't list jails");
+ }
+
+ xp = jls->data;
+ if(jls->length < sizeof(*xp) || xp->pr_version != XPRISON_VERSION)
+ errx(1, "kernel and userland out of sync");
}
-void free_jail_sysctl(size_t len, struct xprison* xp)
+struct xprison*
+jails_next (jails *jls)
{
- if(len == 0 || xp == NULL)
- return;
-
- /*
- * An extra precaution to prevent leakage of information
- * into the jail.
- */
-
- memset(xp, 0, sizeof(struct xprison) * len);
- free(xp);
+ struct xprison *xp = jls->last;
+ unsigned char *data, *next, *end;
+
+ if(xp == NULL)
+ {
+ xp = jls->data;
+ }
+ else
+ {
+ switch(xp->pr_version)
+ {
+ case 1:
+ case 2:
+ xp = xp + 1;
+ break;
+ case 3:
+ data = (unsigned char*)(xp + 1);
+ data += (xp->pr_ip4s * sizeof(struct in_addr));
+ data += (xp->pr_ip6s * sizeof(struct in6_addr));
+ xp = (struct xprison*)data;
+ break;
+ default:
+ errx(1, "unknown jail structure");
+ break;
+ }
+ }
+
+ if(xp == NULL)
+ return NULL;
+
+ next = (unsigned char*)(xp + 1);
+ end = ((unsigned char*)jls->data) + jls->length;
+ if (next > end)
+ return NULL;
+
+ if(xp->pr_version != XPRISON_VERSION)
+ errx(1, "kernel and userland out of sync");
+
+ jls->last = xp;
+ return xp;
}
-struct xprison* find_jail(const char* str, size_t len, struct xprison* xp)
+void
+jails_done(jails *jls)
{
- int jid;
- size_t i;
- char* e;
-
- if(len == 0 || xp == NULL)
- return NULL;
-
- jid = strtol(str, &e, 10);
-
- /* If it was all a number ... */
- if(!*e)
- {
- if(jid <= 0)
- errx(1, "invalid jail id: %s", str);
-
- /* Validate the number */
- for(i = 0; i < len; i++)
- {
- if(jid == xp[i].pr_id)
- return &(xp[i]);
- }
- }
-
- for(i = 0; i < len; i++)
- {
- if(strcmp(xp[i].pr_host, str) == 0)
- return &(xp[i]);
- }
+ memset(jls->data, 0, jls->length);
+ free(jls->data);
+ jls->data = NULL;
+ jls->length = 0;
+ jls->last = NULL;
+}
- return NULL;
+struct xprison*
+jails_find(jails *jls, const char* str)
+{
+ struct xprison *xp;
+ char *e;
+ int jid;
+
+ jid = strtol(str, &e, 10);
+ jls->last = NULL;
+
+ for(;;)
+ {
+ xp = jails_next(jls);
+ if(xp == NULL)
+ return NULL;
+
+ /* If it was all a number ... */
+ if(!*e)
+ {
+ if(jid <= 0)
+ errx(1, "invalid jail id: %s", str);
+ if(jid == xp->pr_id)
+ return xp;
+ }
+
+ /* A host name? */
+ else
+ {
+ if(strcmp(xp->pr_host, str) == 0)
+ return xp;
+ }
+ }
+
+ /* Not reached */
}
int translate_jail_name(const char* str)
{
- struct xprison* sxp = NULL;
- struct xprison* xp = NULL;
- size_t len;
- int jid = -1;
-
- len = get_jail_sysctl(&sxp);
- if(sxp)
- {
- xp = find_jail(str, len, sxp);
- if(xp != NULL)
- jid = xp->pr_id;
+ struct xprison* xp;
+ int jid = -1;
+ jails jls;
- free(sxp);
- }
+ jails_load(&jls);
+ xp = jails_find(&jls, str);
+ if(xp != NULL)
+ jid = xp->pr_id;
+ jails_done(&jls);
- return jid;
+ return jid;
}
int kvm_prepare_jail(struct xprison* xp)