Index: sbin/bectl/bectl_jail.c =================================================================== --- sbin/bectl/bectl_jail.c +++ sbin/bectl/bectl_jail.c @@ -40,95 +40,36 @@ #include #include - #include "bectl.h" -static void jailparam_grow(void); static void jailparam_add(const char *name, const char *val); static int jailparam_del(const char *name); static bool jailparam_addarg(char *arg); static int jailparam_delarg(char *arg); +static int bectl_cmd_jail_background(void); +static int bectl_cmd_jail_exec(void); static int bectl_search_jail_paths(const char *mnt); static int bectl_locate_jail(const char *ident); -/* We'll start with 8 parameters initially and grow as needed. */ -#define INIT_PARAMCOUNT 8 +static int nvlist_to_jailparam(struct jailparam **jp); -static struct jailparam *jp; -static int jpcnt; static int jpused; static char mnt_loc[BE_MAXPATHLEN]; +static nvlist_t *jailparams; -static void -jailparam_grow(void) -{ - - jpcnt *= 2; - jp = realloc(jp, jpcnt * sizeof(*jp)); - if (jp == NULL) - err(2, "realloc"); -} static void jailparam_add(const char *name, const char *val) { - int i; - - for (i = 0; i < jpused; ++i) { - if (strcmp(name, jp[i].jp_name) == 0) - break; - } - - if (i < jpused) - jailparam_free(&jp[i], 1); - else if (jpused == jpcnt) - /* The next slot isn't allocated yet */ - jailparam_grow(); - - if (jailparam_init(&jp[i], name) != 0) - return; - if (jailparam_import(&jp[i], val) != 0) - return; - ++jpused; + jpused++; + nvlist_add_string(jailparams, name, val); } static int jailparam_del(const char *name) { - int i; - char *val; - - for (i = 0; i < jpused; ++i) { - if (strcmp(name, jp[i].jp_name) == 0) - break; - } - - if (i == jpused) - return (ENOENT); - - for (; i < jpused - 1; ++i) { - val = jailparam_export(&jp[i + 1]); - - jailparam_free(&jp[i], 1); - /* - * Given the context, the following will really only fail if - * they can't allocate the copy of the name or value. - */ - if (jailparam_init(&jp[i], jp[i + 1].jp_name) != 0) { - free(val); - return (ENOMEM); - } - if (jailparam_import(&jp[i], val) != 0) { - jailparam_free(&jp[i], 1); - free(val); - return (ENOMEM); - } - free(val); - } - - jailparam_free(&jp[i], 1); - --jpused; + nvlist_remove_all(jailparams, name); return (0); } @@ -145,7 +86,7 @@ arg); return (false); } - + *val++ = '\0'; if (strcmp(name, "path") == 0) { if (strlen(val) >= BE_MAXPATHLEN) { @@ -176,21 +117,61 @@ return (jailparam_del(name)); } +/* Convert our nvlist to a jailparam struct*/ +static int +nvlist_to_jailparam(struct jailparam **jpp) +{ + int rc, i, jpidx; + char *name, *value; + struct jailparam *jp; + nvpair_t *cur; + + jp = malloc(jpused * sizeof(*jp)); + if (jp == NULL) + err(2, "malloc"); + + cur = nvlist_next_nvpair(jailparams, NULL); + for(i = jpidx = 0; i < jpused; i++){ + name = nvpair_name(cur); + nvpair_value_string(cur, &value); + + fprintf(stderr, "bectl jail: import jailparam: '%s'='%s'\n", name, value); + if ((rc = jailparam_init(&jp[jpidx], name)) != 0) { + continue; + } + + if ((rc = jailparam_import(&jp[jpidx], value)) != 0 ){ + continue; + } + jpidx++; + cur = nvlist_next_nvpair(jailparams, cur); + } + + if (jpidx != jpused) { + //resize jp with the new size. + fprintf(stderr, "one of our params wasnt added. should resize here"); + } + + *jpp = jp; + return (0); +} + int bectl_cmd_jail(int argc, char *argv[]) { char *bootenv, *mountpoint; - int jid, mntflags, opt, ret; + int mntflags, opt, ret; bool default_hostname, interactive, unjail; - pid_t pid; /* XXX TODO: Allow shallow */ mntflags = BE_MNT_DEEP; default_hostname = interactive = unjail = true; - jpcnt = INIT_PARAMCOUNT; - jp = malloc(jpcnt * sizeof(*jp)); - if (jp == NULL) - err(2, "malloc"); + + ret = nvlist_alloc(&jailparams, NV_UNIQUE_NAME, 0); + if (ret) { + fprintf(stderr, "nvlist_alloc() failed\n"); + return (ret); + } jailparam_add("persist", "true"); jailparam_add("allow.mount", "true"); @@ -242,6 +223,16 @@ return (usage(false)); } + if (argc > 1) { + if ( nvlist_exists(jailparams, "command") || + nvlist_exists(jailparams, "exec.start") ){ + fprintf(stderr, "command is defined more than once"); + return (1); + } + jailparam_add("command", argv[1]); + } + + bootenv = argv[0]; /* @@ -266,7 +257,37 @@ */ if (mountpoint == NULL) jailparam_add("path", mnt_loc); - /* Create the jail for now, attach later as-needed */ + + if (!interactive){ + ret = bectl_cmd_jail_background(); + } else { + ret = bectl_cmd_jail_exec(); + } + + if (ret || unjail) + be_unmount(be, bootenv, 0); + + return (ret); +} + +/* + * Convert our nvlist to a jailparam pointer and create the jail + * using jailparam_set. This limits us to only using jailparams and + * not any pseudo ones, such as 'mount.devfs'. + * + * This function frees the jailparams nvlist. + */ +static int +bectl_cmd_jail_background() +{ + struct jailparam *jp; + int jid; + + if( nvlist_to_jailparam(&jp) != 0 ){ + nvlist_free(jailparams); + return (1); + } + jid = jailparam_set(jp, jpused, JAIL_CREATE); if (jid == -1) { fprintf(stderr, "unable to create jail. error: %d\n", errno); @@ -274,11 +295,71 @@ } jailparam_free(jp, jpused); + nvlist_free(jailparams); free(jp); - /* We're not interactive, nothing more to do here. */ - if (!interactive) - return (0); + return (0); +} + +/* + * Fork into the system's jail command so that it can handle the + * pesudo jailparams. + */ +static int +bectl_cmd_jail_exec(){ + char **args, *name, *value, buf[4096]; + char **argpos; // do we need this if we have args? + int total; + pid_t pid; + nvpair_t *cur; + + // Basically we shove everything into our buffer, while + // incrementing our pointer. + total = 0; + + args = malloc( (jpused + 3) * sizeof(char *)); + if (args == NULL) { + err(2, "malloc"); + } + + // bufarg keeps track of our position on the buffer, + argpos = args; + + // our first argument starts at the adress of the + // buffer + *argpos++ = buf; + + // write our jail command and, flags to the buffer + // we add a +1 so the null terminator exists in our buffer + total += sprintf(buf + total, "/usr/sbin/jail") + 1; + *argpos++ = buf + total; + + total += sprintf(buf + total, "-c") + 1; + *argpos++ = buf + total; + + cur = nvlist_next_nvpair(jailparams, NULL); + while(cur != NULL){ + name = nvpair_name(cur); + nvpair_value_string(cur, &value); + // TODO: add range checking here to exit when we go over the + // buffer? or if the number returned == 1 (meaning we + // didnt write anything ) + total += snprintf(buf + total, 4096 + total, "%s=%s", name, value) + 1; + *argpos++ = buf + total; + + cur = nvlist_next_nvpair(jailparams, cur); + } + + //*argpos = NULL; + args[jpused+2] = NULL; + nvlist_free(jailparams); + + for (int i = 0; i < (jpused + 3); i++){ + if (args[i] == NULL) + fprintf(stderr, "arg[%d]: NULL\n", i); + else + fprintf(stderr, "arg[%d]: %s\n", i, args[i]); + } pid = fork(); switch(pid) { @@ -286,29 +367,16 @@ perror("fork"); return (1); case 0: - jail_attach(jid); - /* We're attached within the jail... good bye! */ - chdir("/"); - if (argc > 1) - execve(argv[1], &argv[1], NULL); - else - execl("/bin/sh", "/bin/sh", NULL); - fprintf(stderr, "bectl jail: failed to execute %s\n", - (argc > 1 ? argv[1] : "/bin/sh")); - _exit(1); + execvp(args[0], args); default: - /* Wait for the child to get back, see if we need to unjail */ waitpid(pid, NULL, 0); } - if (unjail) { - jail_remove(jid); - be_unmount(be, bootenv, 0); - } - + free(args); return (0); } + static int bectl_search_jail_paths(const char *mnt) {