173577bf0SRyan Moeller /*-
273577bf0SRyan Moeller * SPDX-License-Identifier: BSD-2-Clause
373577bf0SRyan Moeller *
473577bf0SRyan Moeller * Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org>
56a7647ecSKyle Evans * Copyright (c) 2020, Kyle Evans <kevans@FreeBSD.org>
673577bf0SRyan Moeller *
773577bf0SRyan Moeller * Redistribution and use in source and binary forms, with or without
873577bf0SRyan Moeller * modification, are permitted provided that the following conditions
973577bf0SRyan Moeller * are met:
1073577bf0SRyan Moeller * 1. Redistributions of source code must retain the above copyright
1173577bf0SRyan Moeller * notice, this list of conditions and the following disclaimer.
1273577bf0SRyan Moeller * 2. Redistributions in binary form must reproduce the above copyright
1373577bf0SRyan Moeller * notice, this list of conditions and the following disclaimer in the
1473577bf0SRyan Moeller * documentation and/or other materials provided with the distribution.
1573577bf0SRyan Moeller *
1673577bf0SRyan Moeller * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1773577bf0SRyan Moeller * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1873577bf0SRyan Moeller * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1973577bf0SRyan Moeller * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2073577bf0SRyan Moeller * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2173577bf0SRyan Moeller * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2273577bf0SRyan Moeller * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2373577bf0SRyan Moeller * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2473577bf0SRyan Moeller * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2573577bf0SRyan Moeller * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2673577bf0SRyan Moeller * SUCH DAMAGE.
2773577bf0SRyan Moeller */
2873577bf0SRyan Moeller
2973577bf0SRyan Moeller #include <sys/param.h>
3073577bf0SRyan Moeller #include <sys/jail.h>
3173577bf0SRyan Moeller #include <errno.h>
3273577bf0SRyan Moeller #include <jail.h>
336a7647ecSKyle Evans #include <stdbool.h>
3473577bf0SRyan Moeller #include <stdlib.h>
3573577bf0SRyan Moeller #include <string.h>
3673577bf0SRyan Moeller
3773577bf0SRyan Moeller #include <lua.h>
3873577bf0SRyan Moeller #include <lauxlib.h>
3973577bf0SRyan Moeller #include <lualib.h>
4073577bf0SRyan Moeller
41*151bd351SKyle Evans #include "bootstrap.h"
42*151bd351SKyle Evans
436a7647ecSKyle Evans #define JAIL_METATABLE "jail iterator metatable"
446a7647ecSKyle Evans
456a7647ecSKyle Evans /*
466a7647ecSKyle Evans * Taken from RhodiumToad's lspawn implementation, let static analyzers make
476a7647ecSKyle Evans * better decisions about the behavior after we raise an error.
486a7647ecSKyle Evans */
496a7647ecSKyle Evans #if defined(LUA_VERSION_NUM) && defined(LUA_API)
506a7647ecSKyle Evans LUA_API int (lua_error) (lua_State *L) __dead2;
516a7647ecSKyle Evans #endif
526a7647ecSKyle Evans #if defined(LUA_ERRFILE) && defined(LUALIB_API)
536a7647ecSKyle Evans LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg) __dead2;
546a7647ecSKyle Evans LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname) __dead2;
556a7647ecSKyle Evans LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...) __dead2;
566a7647ecSKyle Evans #endif
576a7647ecSKyle Evans
5873577bf0SRyan Moeller int luaopen_jail(lua_State *);
5973577bf0SRyan Moeller
606a7647ecSKyle Evans typedef bool (*getparam_filter)(const char *, void *);
616a7647ecSKyle Evans
626a7647ecSKyle Evans static void getparam_table(lua_State *L, int paramindex,
636a7647ecSKyle Evans struct jailparam *params, size_t paramoff, size_t *params_countp,
646a7647ecSKyle Evans getparam_filter keyfilt, void *udata);
656a7647ecSKyle Evans
666a7647ecSKyle Evans struct l_jail_iter {
676a7647ecSKyle Evans struct jailparam *params;
686a7647ecSKyle Evans size_t params_count;
696a7647ecSKyle Evans int jid;
706a7647ecSKyle Evans };
716a7647ecSKyle Evans
726a7647ecSKyle Evans static bool
l_jail_filter(const char * param_name,void * data __unused)736a7647ecSKyle Evans l_jail_filter(const char *param_name, void *data __unused)
746a7647ecSKyle Evans {
756a7647ecSKyle Evans
766a7647ecSKyle Evans /*
776a7647ecSKyle Evans * Allowing lastjid will mess up our iteration over all jails on the
78f2411b92SGordon Bergling * system, as this is a special parameter that indicates where the search
796a7647ecSKyle Evans * starts from. We'll always add jid and name, so just silently remove
806a7647ecSKyle Evans * these.
816a7647ecSKyle Evans */
826a7647ecSKyle Evans return (strcmp(param_name, "lastjid") != 0 &&
836a7647ecSKyle Evans strcmp(param_name, "jid") != 0 &&
846a7647ecSKyle Evans strcmp(param_name, "name") != 0);
856a7647ecSKyle Evans }
866a7647ecSKyle Evans
876a7647ecSKyle Evans static int
l_jail_iter_next(lua_State * L)886a7647ecSKyle Evans l_jail_iter_next(lua_State *L)
896a7647ecSKyle Evans {
906a7647ecSKyle Evans struct l_jail_iter *iter, **iterp;
916a7647ecSKyle Evans struct jailparam *jp;
926a7647ecSKyle Evans int serrno;
936a7647ecSKyle Evans
946a7647ecSKyle Evans iterp = (struct l_jail_iter **)luaL_checkudata(L, 1, JAIL_METATABLE);
956a7647ecSKyle Evans iter = *iterp;
966a7647ecSKyle Evans luaL_argcheck(L, iter != NULL, 1, "closed jail iterator");
976a7647ecSKyle Evans
986a7647ecSKyle Evans jp = iter->params;
996a7647ecSKyle Evans /* Populate lastjid; we must keep it in params[0] for our sake. */
1006a7647ecSKyle Evans if (jailparam_import_raw(&jp[0], &iter->jid, sizeof(iter->jid))) {
1016a7647ecSKyle Evans jailparam_free(jp, iter->params_count);
1026a7647ecSKyle Evans free(jp);
1036a7647ecSKyle Evans free(iter);
1046a7647ecSKyle Evans *iterp = NULL;
1056a7647ecSKyle Evans return (luaL_error(L, "jailparam_import_raw: %s", jail_errmsg));
1066a7647ecSKyle Evans }
1076a7647ecSKyle Evans
1086a7647ecSKyle Evans /* The list of requested params was populated back in l_list(). */
1096a7647ecSKyle Evans iter->jid = jailparam_get(jp, iter->params_count, 0);
1106a7647ecSKyle Evans if (iter->jid == -1) {
1116a7647ecSKyle Evans /*
1126a7647ecSKyle Evans * We probably got an ENOENT to signify the end of the jail
1136a7647ecSKyle Evans * listing, but just in case we didn't; stash it off and start
1146a7647ecSKyle Evans * cleaning up. We'll handle non-ENOENT errors later.
1156a7647ecSKyle Evans */
1166a7647ecSKyle Evans serrno = errno;
1176a7647ecSKyle Evans jailparam_free(jp, iter->params_count);
1186a7647ecSKyle Evans free(iter->params);
1196a7647ecSKyle Evans free(iter);
1206a7647ecSKyle Evans *iterp = NULL;
1216a7647ecSKyle Evans if (serrno != ENOENT)
1226a7647ecSKyle Evans return (luaL_error(L, "jailparam_get: %s",
1236a7647ecSKyle Evans strerror(serrno)));
1246a7647ecSKyle Evans return (0);
1256a7647ecSKyle Evans }
1266a7647ecSKyle Evans
1276a7647ecSKyle Evans /*
1286a7647ecSKyle Evans * Finally, we'll fill in the return table with whatever parameters the
1296a7647ecSKyle Evans * user requested, in addition to the ones we forced with exception to
1306a7647ecSKyle Evans * lastjid.
1316a7647ecSKyle Evans */
1326a7647ecSKyle Evans lua_newtable(L);
1336a7647ecSKyle Evans for (size_t i = 0; i < iter->params_count; ++i) {
1346a7647ecSKyle Evans char *value;
1356a7647ecSKyle Evans
1366a7647ecSKyle Evans jp = &iter->params[i];
1376a7647ecSKyle Evans if (strcmp(jp->jp_name, "lastjid") == 0)
1386a7647ecSKyle Evans continue;
1396a7647ecSKyle Evans value = jailparam_export(jp);
1406a7647ecSKyle Evans lua_pushstring(L, value);
1416a7647ecSKyle Evans lua_setfield(L, -2, jp->jp_name);
1426a7647ecSKyle Evans free(value);
1436a7647ecSKyle Evans }
1446a7647ecSKyle Evans
1456a7647ecSKyle Evans return (1);
1466a7647ecSKyle Evans }
1476a7647ecSKyle Evans
1486a7647ecSKyle Evans static int
l_jail_iter_close(lua_State * L)1496a7647ecSKyle Evans l_jail_iter_close(lua_State *L)
1506a7647ecSKyle Evans {
1516a7647ecSKyle Evans struct l_jail_iter *iter, **iterp;
1526a7647ecSKyle Evans
1536a7647ecSKyle Evans /*
1546a7647ecSKyle Evans * Since we're using this as the __gc method as well, there's a good
1556a7647ecSKyle Evans * chance that it's already been cleaned up by iterating to the end of
1566a7647ecSKyle Evans * the list.
1576a7647ecSKyle Evans */
1586a7647ecSKyle Evans iterp = (struct l_jail_iter **)lua_touserdata(L, 1);
1596a7647ecSKyle Evans iter = *iterp;
1606a7647ecSKyle Evans if (iter == NULL)
1616a7647ecSKyle Evans return (0);
1626a7647ecSKyle Evans
1636a7647ecSKyle Evans jailparam_free(iter->params, iter->params_count);
1646a7647ecSKyle Evans free(iter->params);
1656a7647ecSKyle Evans free(iter);
1666a7647ecSKyle Evans *iterp = NULL;
1676a7647ecSKyle Evans return (0);
1686a7647ecSKyle Evans }
1696a7647ecSKyle Evans
1706a7647ecSKyle Evans static int
l_list(lua_State * L)1716a7647ecSKyle Evans l_list(lua_State *L)
1726a7647ecSKyle Evans {
1736a7647ecSKyle Evans struct l_jail_iter *iter;
1746a7647ecSKyle Evans int nargs;
1756a7647ecSKyle Evans
1766a7647ecSKyle Evans nargs = lua_gettop(L);
1776a7647ecSKyle Evans if (nargs >= 1)
1786a7647ecSKyle Evans luaL_checktype(L, 1, LUA_TTABLE);
1796a7647ecSKyle Evans
1806a7647ecSKyle Evans iter = malloc(sizeof(*iter));
1816a7647ecSKyle Evans if (iter == NULL)
1826a7647ecSKyle Evans return (luaL_error(L, "malloc: %s", strerror(errno)));
1836a7647ecSKyle Evans
1846a7647ecSKyle Evans /*
1856a7647ecSKyle Evans * lastjid, jid, name + length of the table. This may be too much if
1866a7647ecSKyle Evans * we have duplicated one of those fixed parameters.
1876a7647ecSKyle Evans */
1886a7647ecSKyle Evans iter->params_count = 3 + (nargs != 0 ? lua_rawlen(L, 1) : 0);
1896a7647ecSKyle Evans iter->params = malloc(iter->params_count * sizeof(*iter->params));
1906a7647ecSKyle Evans if (iter->params == NULL) {
1916a7647ecSKyle Evans free(iter);
1926a7647ecSKyle Evans return (luaL_error(L, "malloc params: %s", strerror(errno)));
1936a7647ecSKyle Evans }
1946a7647ecSKyle Evans
1956a7647ecSKyle Evans /* The :next() method will populate lastjid before jail_getparam(). */
1966a7647ecSKyle Evans if (jailparam_init(&iter->params[0], "lastjid") == -1) {
1976a7647ecSKyle Evans free(iter->params);
1986a7647ecSKyle Evans free(iter);
1996a7647ecSKyle Evans return (luaL_error(L, "jailparam_init: %s", jail_errmsg));
2006a7647ecSKyle Evans }
2016a7647ecSKyle Evans /* These two will get populated by jail_getparam(). */
2026a7647ecSKyle Evans if (jailparam_init(&iter->params[1], "jid") == -1) {
2036a7647ecSKyle Evans jailparam_free(iter->params, 1);
2046a7647ecSKyle Evans free(iter->params);
2056a7647ecSKyle Evans free(iter);
2066a7647ecSKyle Evans return (luaL_error(L, "jailparam_init: %s",
2076a7647ecSKyle Evans jail_errmsg));
2086a7647ecSKyle Evans }
2096a7647ecSKyle Evans if (jailparam_init(&iter->params[2], "name") == -1) {
2106a7647ecSKyle Evans jailparam_free(iter->params, 2);
2116a7647ecSKyle Evans free(iter->params);
2126a7647ecSKyle Evans free(iter);
2136a7647ecSKyle Evans return (luaL_error(L, "jailparam_init: %s",
2146a7647ecSKyle Evans jail_errmsg));
2156a7647ecSKyle Evans }
2166a7647ecSKyle Evans
2176a7647ecSKyle Evans /*
2186a7647ecSKyle Evans * We only need to process additional arguments if we were given any.
2196a7647ecSKyle Evans * That is, we don't descend into getparam_table if we're passed nothing
2206a7647ecSKyle Evans * or an empty table.
2216a7647ecSKyle Evans */
2226a7647ecSKyle Evans iter->jid = 0;
2236a7647ecSKyle Evans if (iter->params_count != 3)
2246a7647ecSKyle Evans getparam_table(L, 1, iter->params, 2, &iter->params_count,
2256a7647ecSKyle Evans l_jail_filter, NULL);
2266a7647ecSKyle Evans
2276a7647ecSKyle Evans /*
2286a7647ecSKyle Evans * Part of the iterator magic. We give it an iterator function with a
2296a7647ecSKyle Evans * metatable defining next() and close() that can be used for manual
2306a7647ecSKyle Evans * iteration. iter->jid is how we track which jail we last iterated, to
2316a7647ecSKyle Evans * be supplied as "lastjid".
2326a7647ecSKyle Evans */
2336a7647ecSKyle Evans lua_pushcfunction(L, l_jail_iter_next);
2346a7647ecSKyle Evans *(struct l_jail_iter **)lua_newuserdata(L,
2356a7647ecSKyle Evans sizeof(struct l_jail_iter **)) = iter;
2366a7647ecSKyle Evans luaL_getmetatable(L, JAIL_METATABLE);
2376a7647ecSKyle Evans lua_setmetatable(L, -2);
2386a7647ecSKyle Evans return (2);
2396a7647ecSKyle Evans }
2406a7647ecSKyle Evans
2416a7647ecSKyle Evans static void
register_jail_metatable(lua_State * L)2426a7647ecSKyle Evans register_jail_metatable(lua_State *L)
2436a7647ecSKyle Evans {
2446a7647ecSKyle Evans luaL_newmetatable(L, JAIL_METATABLE);
2456a7647ecSKyle Evans lua_newtable(L);
2466a7647ecSKyle Evans lua_pushcfunction(L, l_jail_iter_next);
2476a7647ecSKyle Evans lua_setfield(L, -2, "next");
2486a7647ecSKyle Evans lua_pushcfunction(L, l_jail_iter_close);
2496a7647ecSKyle Evans lua_setfield(L, -2, "close");
2506a7647ecSKyle Evans
2516a7647ecSKyle Evans lua_setfield(L, -2, "__index");
2526a7647ecSKyle Evans
2536a7647ecSKyle Evans lua_pushcfunction(L, l_jail_iter_close);
2546a7647ecSKyle Evans lua_setfield(L, -2, "__gc");
2556a7647ecSKyle Evans
2566a7647ecSKyle Evans lua_pop(L, 1);
2576a7647ecSKyle Evans }
2586a7647ecSKyle Evans
25973577bf0SRyan Moeller static int
l_getid(lua_State * L)26073577bf0SRyan Moeller l_getid(lua_State *L)
26173577bf0SRyan Moeller {
26273577bf0SRyan Moeller const char *name;
26373577bf0SRyan Moeller int jid;
26473577bf0SRyan Moeller
26573577bf0SRyan Moeller name = luaL_checkstring(L, 1);
26673577bf0SRyan Moeller jid = jail_getid(name);
26773577bf0SRyan Moeller if (jid == -1) {
26873577bf0SRyan Moeller lua_pushnil(L);
26973577bf0SRyan Moeller lua_pushstring(L, jail_errmsg);
27073577bf0SRyan Moeller return (2);
27173577bf0SRyan Moeller }
27273577bf0SRyan Moeller lua_pushinteger(L, jid);
27373577bf0SRyan Moeller return (1);
27473577bf0SRyan Moeller }
27573577bf0SRyan Moeller
27673577bf0SRyan Moeller static int
l_getname(lua_State * L)27773577bf0SRyan Moeller l_getname(lua_State *L)
27873577bf0SRyan Moeller {
27973577bf0SRyan Moeller char *name;
28073577bf0SRyan Moeller int jid;
28173577bf0SRyan Moeller
28273577bf0SRyan Moeller jid = luaL_checkinteger(L, 1);
28373577bf0SRyan Moeller name = jail_getname(jid);
28473577bf0SRyan Moeller if (name == NULL) {
28573577bf0SRyan Moeller lua_pushnil(L);
28673577bf0SRyan Moeller lua_pushstring(L, jail_errmsg);
28773577bf0SRyan Moeller return (2);
28873577bf0SRyan Moeller }
28973577bf0SRyan Moeller lua_pushstring(L, name);
29073577bf0SRyan Moeller free(name);
29173577bf0SRyan Moeller return (1);
29273577bf0SRyan Moeller }
29373577bf0SRyan Moeller
29473577bf0SRyan Moeller static int
l_allparams(lua_State * L)29573577bf0SRyan Moeller l_allparams(lua_State *L)
29673577bf0SRyan Moeller {
29773577bf0SRyan Moeller struct jailparam *params;
29873577bf0SRyan Moeller int params_count;
29973577bf0SRyan Moeller
30073577bf0SRyan Moeller params_count = jailparam_all(¶ms);
30173577bf0SRyan Moeller if (params_count == -1) {
30273577bf0SRyan Moeller lua_pushnil(L);
30373577bf0SRyan Moeller lua_pushstring(L, jail_errmsg);
30473577bf0SRyan Moeller return (2);
30573577bf0SRyan Moeller }
30673577bf0SRyan Moeller lua_newtable(L);
30773577bf0SRyan Moeller for (int i = 0; i < params_count; ++i) {
30873577bf0SRyan Moeller lua_pushstring(L, params[i].jp_name);
30973577bf0SRyan Moeller lua_rawseti(L, -2, i + 1);
31073577bf0SRyan Moeller }
31173577bf0SRyan Moeller jailparam_free(params, params_count);
31273577bf0SRyan Moeller free(params);
31373577bf0SRyan Moeller return (1);
31473577bf0SRyan Moeller }
31573577bf0SRyan Moeller
3166a7647ecSKyle Evans static void
getparam_table(lua_State * L,int paramindex,struct jailparam * params,size_t params_off,size_t * params_countp,getparam_filter keyfilt,void * udata)3176a7647ecSKyle Evans getparam_table(lua_State *L, int paramindex, struct jailparam *params,
3186a7647ecSKyle Evans size_t params_off, size_t *params_countp, getparam_filter keyfilt,
3196a7647ecSKyle Evans void *udata)
3206a7647ecSKyle Evans {
3216a7647ecSKyle Evans size_t params_count;
3226a7647ecSKyle Evans int skipped;
3236a7647ecSKyle Evans
3246a7647ecSKyle Evans params_count = *params_countp;
3256a7647ecSKyle Evans skipped = 0;
3266a7647ecSKyle Evans for (size_t i = 1 + params_off; i < params_count; ++i) {
3276a7647ecSKyle Evans const char *param_name;
3286a7647ecSKyle Evans
3296a7647ecSKyle Evans lua_rawgeti(L, -1, i - params_off);
3306a7647ecSKyle Evans param_name = lua_tostring(L, -1);
3316a7647ecSKyle Evans if (param_name == NULL) {
3326a7647ecSKyle Evans jailparam_free(params, i - skipped);
3336a7647ecSKyle Evans free(params);
3346a7647ecSKyle Evans luaL_argerror(L, paramindex,
3356a7647ecSKyle Evans "param names must be strings");
3366a7647ecSKyle Evans }
3376a7647ecSKyle Evans lua_pop(L, 1);
3386a7647ecSKyle Evans if (keyfilt != NULL && !keyfilt(param_name, udata)) {
3396a7647ecSKyle Evans ++skipped;
3406a7647ecSKyle Evans continue;
3416a7647ecSKyle Evans }
3426a7647ecSKyle Evans if (jailparam_init(¶ms[i - skipped], param_name) == -1) {
3436a7647ecSKyle Evans jailparam_free(params, i - skipped);
3446a7647ecSKyle Evans free(params);
3456a7647ecSKyle Evans luaL_error(L, "jailparam_init: %s", jail_errmsg);
3466a7647ecSKyle Evans }
3476a7647ecSKyle Evans }
3486a7647ecSKyle Evans *params_countp -= skipped;
3496a7647ecSKyle Evans }
3506a7647ecSKyle Evans
3516a7647ecSKyle Evans struct getparams_filter_args {
3526a7647ecSKyle Evans int filter_type;
3536a7647ecSKyle Evans };
3546a7647ecSKyle Evans
3556a7647ecSKyle Evans static bool
l_getparams_filter(const char * param_name,void * udata)3566a7647ecSKyle Evans l_getparams_filter(const char *param_name, void *udata)
3576a7647ecSKyle Evans {
3586a7647ecSKyle Evans struct getparams_filter_args *gpa;
3596a7647ecSKyle Evans
3606a7647ecSKyle Evans gpa = udata;
3616a7647ecSKyle Evans
3626a7647ecSKyle Evans /* Skip name or jid, whichever was given. */
3636a7647ecSKyle Evans if (gpa->filter_type == LUA_TSTRING) {
3646a7647ecSKyle Evans if (strcmp(param_name, "name") == 0)
3656a7647ecSKyle Evans return (false);
3666a7647ecSKyle Evans } else /* type == LUA_TNUMBER */ {
3676a7647ecSKyle Evans if (strcmp(param_name, "jid") == 0)
3686a7647ecSKyle Evans return (false);
3696a7647ecSKyle Evans }
3706a7647ecSKyle Evans
3716a7647ecSKyle Evans return (true);
3726a7647ecSKyle Evans }
3736a7647ecSKyle Evans
37473577bf0SRyan Moeller static int
l_getparams(lua_State * L)37573577bf0SRyan Moeller l_getparams(lua_State *L)
37673577bf0SRyan Moeller {
37773577bf0SRyan Moeller const char *name;
37873577bf0SRyan Moeller struct jailparam *params;
3796a7647ecSKyle Evans size_t params_count;
3806a7647ecSKyle Evans struct getparams_filter_args gpa;
38173577bf0SRyan Moeller int flags, jid, type;
38273577bf0SRyan Moeller
38373577bf0SRyan Moeller type = lua_type(L, 1);
38473577bf0SRyan Moeller luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
38573577bf0SRyan Moeller "expected a jail name (string) or id (integer)");
38673577bf0SRyan Moeller luaL_checktype(L, 2, LUA_TTABLE);
38773577bf0SRyan Moeller params_count = 1 + lua_rawlen(L, 2);
38873577bf0SRyan Moeller flags = luaL_optinteger(L, 3, 0);
38973577bf0SRyan Moeller
39073577bf0SRyan Moeller params = malloc(params_count * sizeof(struct jailparam));
39173577bf0SRyan Moeller if (params == NULL)
39273577bf0SRyan Moeller return (luaL_error(L, "malloc: %s", strerror(errno)));
39373577bf0SRyan Moeller
39473577bf0SRyan Moeller /*
39573577bf0SRyan Moeller * Set the jail name or id param as determined by the first arg.
39673577bf0SRyan Moeller */
39773577bf0SRyan Moeller
39873577bf0SRyan Moeller if (type == LUA_TSTRING) {
39973577bf0SRyan Moeller if (jailparam_init(¶ms[0], "name") == -1) {
40073577bf0SRyan Moeller free(params);
40173577bf0SRyan Moeller return (luaL_error(L, "jailparam_init: %s",
40273577bf0SRyan Moeller jail_errmsg));
40373577bf0SRyan Moeller }
40473577bf0SRyan Moeller name = lua_tostring(L, 1);
40573577bf0SRyan Moeller if (jailparam_import(¶ms[0], name) == -1) {
40673577bf0SRyan Moeller jailparam_free(params, 1);
40773577bf0SRyan Moeller free(params);
40873577bf0SRyan Moeller return (luaL_error(L, "jailparam_import: %s",
40973577bf0SRyan Moeller jail_errmsg));
41073577bf0SRyan Moeller }
41173577bf0SRyan Moeller } else /* type == LUA_TNUMBER */ {
41273577bf0SRyan Moeller if (jailparam_init(¶ms[0], "jid") == -1) {
41373577bf0SRyan Moeller free(params);
41473577bf0SRyan Moeller return (luaL_error(L, "jailparam_init: %s",
41573577bf0SRyan Moeller jail_errmsg));
41673577bf0SRyan Moeller }
41773577bf0SRyan Moeller jid = lua_tointeger(L, 1);
41873577bf0SRyan Moeller if (jailparam_import_raw(¶ms[0], &jid, sizeof(jid)) == -1) {
41973577bf0SRyan Moeller jailparam_free(params, 1);
42073577bf0SRyan Moeller free(params);
42173577bf0SRyan Moeller return (luaL_error(L, "jailparam_import_raw: %s",
42273577bf0SRyan Moeller jail_errmsg));
42373577bf0SRyan Moeller }
42473577bf0SRyan Moeller }
42573577bf0SRyan Moeller
42673577bf0SRyan Moeller /*
42773577bf0SRyan Moeller * Set the remaining param names being requested.
42873577bf0SRyan Moeller */
4296a7647ecSKyle Evans gpa.filter_type = type;
4306a7647ecSKyle Evans getparam_table(L, 2, params, 0, ¶ms_count, l_getparams_filter, &gpa);
43173577bf0SRyan Moeller
43273577bf0SRyan Moeller /*
43373577bf0SRyan Moeller * Get the values and convert to a table.
43473577bf0SRyan Moeller */
43573577bf0SRyan Moeller
43673577bf0SRyan Moeller jid = jailparam_get(params, params_count, flags);
43773577bf0SRyan Moeller if (jid == -1) {
43873577bf0SRyan Moeller jailparam_free(params, params_count);
43973577bf0SRyan Moeller free(params);
44073577bf0SRyan Moeller lua_pushnil(L);
44173577bf0SRyan Moeller lua_pushstring(L, jail_errmsg);
44273577bf0SRyan Moeller return (2);
44373577bf0SRyan Moeller }
44473577bf0SRyan Moeller lua_pushinteger(L, jid);
44573577bf0SRyan Moeller
44673577bf0SRyan Moeller lua_newtable(L);
44773577bf0SRyan Moeller for (size_t i = 0; i < params_count; ++i) {
44873577bf0SRyan Moeller char *value;
44973577bf0SRyan Moeller
45030e6e008SIgor Ostapenko if (params[i].jp_flags & JP_KEYVALUE &&
45130e6e008SIgor Ostapenko params[i].jp_valuelen == 0) {
45230e6e008SIgor Ostapenko /* Communicate back a missing key. */
45330e6e008SIgor Ostapenko lua_pushnil(L);
45430e6e008SIgor Ostapenko } else {
45573577bf0SRyan Moeller value = jailparam_export(¶ms[i]);
45673577bf0SRyan Moeller lua_pushstring(L, value);
45773577bf0SRyan Moeller free(value);
45830e6e008SIgor Ostapenko }
45930e6e008SIgor Ostapenko
46073577bf0SRyan Moeller lua_setfield(L, -2, params[i].jp_name);
46173577bf0SRyan Moeller }
46273577bf0SRyan Moeller
46373577bf0SRyan Moeller jailparam_free(params, params_count);
46473577bf0SRyan Moeller free(params);
46573577bf0SRyan Moeller
46673577bf0SRyan Moeller return (2);
46773577bf0SRyan Moeller }
46873577bf0SRyan Moeller
46973577bf0SRyan Moeller static int
l_setparams(lua_State * L)47073577bf0SRyan Moeller l_setparams(lua_State *L)
47173577bf0SRyan Moeller {
47273577bf0SRyan Moeller const char *name;
47373577bf0SRyan Moeller struct jailparam *params;
47473577bf0SRyan Moeller size_t params_count;
47573577bf0SRyan Moeller int flags, jid, type;
47673577bf0SRyan Moeller
47773577bf0SRyan Moeller type = lua_type(L, 1);
47873577bf0SRyan Moeller luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
47973577bf0SRyan Moeller "expected a jail name (string) or id (integer)");
48073577bf0SRyan Moeller luaL_checktype(L, 2, LUA_TTABLE);
48173577bf0SRyan Moeller
48273577bf0SRyan Moeller lua_pushnil(L);
48373577bf0SRyan Moeller for (params_count = 1; lua_next(L, 2) != 0; ++params_count)
48473577bf0SRyan Moeller lua_pop(L, 1);
48573577bf0SRyan Moeller
48673577bf0SRyan Moeller flags = luaL_optinteger(L, 3, 0);
48773577bf0SRyan Moeller
48873577bf0SRyan Moeller params = malloc(params_count * sizeof(struct jailparam));
48973577bf0SRyan Moeller if (params == NULL)
49073577bf0SRyan Moeller return (luaL_error(L, "malloc: %s", strerror(errno)));
49173577bf0SRyan Moeller
49273577bf0SRyan Moeller /*
49373577bf0SRyan Moeller * Set the jail name or id param as determined by the first arg.
49473577bf0SRyan Moeller */
49573577bf0SRyan Moeller
49673577bf0SRyan Moeller if (type == LUA_TSTRING) {
49773577bf0SRyan Moeller if (jailparam_init(¶ms[0], "name") == -1) {
49873577bf0SRyan Moeller free(params);
49973577bf0SRyan Moeller return (luaL_error(L, "jailparam_init: %s",
50073577bf0SRyan Moeller jail_errmsg));
50173577bf0SRyan Moeller }
50273577bf0SRyan Moeller name = lua_tostring(L, 1);
50373577bf0SRyan Moeller if (jailparam_import(¶ms[0], name) == -1) {
50473577bf0SRyan Moeller jailparam_free(params, 1);
50573577bf0SRyan Moeller free(params);
50673577bf0SRyan Moeller return (luaL_error(L, "jailparam_import: %s",
50773577bf0SRyan Moeller jail_errmsg));
50873577bf0SRyan Moeller }
50973577bf0SRyan Moeller } else /* type == LUA_TNUMBER */ {
51073577bf0SRyan Moeller if (jailparam_init(¶ms[0], "jid") == -1) {
51173577bf0SRyan Moeller free(params);
51273577bf0SRyan Moeller return (luaL_error(L, "jailparam_init: %s",
51373577bf0SRyan Moeller jail_errmsg));
51473577bf0SRyan Moeller }
51573577bf0SRyan Moeller jid = lua_tointeger(L, 1);
51673577bf0SRyan Moeller if (jailparam_import_raw(¶ms[0], &jid, sizeof(jid)) == -1) {
51773577bf0SRyan Moeller jailparam_free(params, 1);
51873577bf0SRyan Moeller free(params);
51973577bf0SRyan Moeller return (luaL_error(L, "jailparam_import_raw: %s",
52073577bf0SRyan Moeller jail_errmsg));
52173577bf0SRyan Moeller }
52273577bf0SRyan Moeller }
52373577bf0SRyan Moeller
52473577bf0SRyan Moeller /*
52573577bf0SRyan Moeller * Set the rest of the provided params.
52673577bf0SRyan Moeller */
52773577bf0SRyan Moeller
52873577bf0SRyan Moeller lua_pushnil(L);
52973577bf0SRyan Moeller for (size_t i = 1; i < params_count && lua_next(L, 2) != 0; ++i) {
53073577bf0SRyan Moeller const char *value;
53173577bf0SRyan Moeller
53273577bf0SRyan Moeller name = lua_tostring(L, -2);
53373577bf0SRyan Moeller if (name == NULL) {
53473577bf0SRyan Moeller jailparam_free(params, i);
53573577bf0SRyan Moeller free(params);
53673577bf0SRyan Moeller return (luaL_argerror(L, 2,
53773577bf0SRyan Moeller "param names must be strings"));
53873577bf0SRyan Moeller }
53973577bf0SRyan Moeller if (jailparam_init(¶ms[i], name) == -1) {
54073577bf0SRyan Moeller jailparam_free(params, i);
54173577bf0SRyan Moeller free(params);
54273577bf0SRyan Moeller return (luaL_error(L, "jailparam_init: %s",
54373577bf0SRyan Moeller jail_errmsg));
54473577bf0SRyan Moeller }
54573577bf0SRyan Moeller
54673577bf0SRyan Moeller value = lua_tostring(L, -1);
54730e6e008SIgor Ostapenko /* Allow passing NULL for key removal. */
54830e6e008SIgor Ostapenko if (value == NULL && !(params[i].jp_flags & JP_KEYVALUE)) {
54973577bf0SRyan Moeller jailparam_free(params, i + 1);
55073577bf0SRyan Moeller free(params);
55173577bf0SRyan Moeller return (luaL_argerror(L, 2,
55273577bf0SRyan Moeller "param values must be strings"));
55373577bf0SRyan Moeller }
55473577bf0SRyan Moeller if (jailparam_import(¶ms[i], value) == -1) {
55573577bf0SRyan Moeller jailparam_free(params, i + 1);
55673577bf0SRyan Moeller free(params);
55773577bf0SRyan Moeller return (luaL_error(L, "jailparam_import: %s",
55873577bf0SRyan Moeller jail_errmsg));
55973577bf0SRyan Moeller }
56073577bf0SRyan Moeller
56173577bf0SRyan Moeller lua_pop(L, 1);
56273577bf0SRyan Moeller }
56373577bf0SRyan Moeller
56473577bf0SRyan Moeller /*
56573577bf0SRyan Moeller * Attempt to set the params.
56673577bf0SRyan Moeller */
56773577bf0SRyan Moeller
56873577bf0SRyan Moeller jid = jailparam_set(params, params_count, flags);
56973577bf0SRyan Moeller if (jid == -1) {
57073577bf0SRyan Moeller jailparam_free(params, params_count);
57173577bf0SRyan Moeller free(params);
57273577bf0SRyan Moeller lua_pushnil(L);
57373577bf0SRyan Moeller lua_pushstring(L, jail_errmsg);
57473577bf0SRyan Moeller return (2);
57573577bf0SRyan Moeller }
57673577bf0SRyan Moeller lua_pushinteger(L, jid);
57773577bf0SRyan Moeller
57873577bf0SRyan Moeller jailparam_free(params, params_count);
57973577bf0SRyan Moeller free(params);
58073577bf0SRyan Moeller return (1);
58173577bf0SRyan Moeller }
58273577bf0SRyan Moeller
583a6499c56SKyle Evans static int
l_attach(lua_State * L)584a6499c56SKyle Evans l_attach(lua_State *L)
585a6499c56SKyle Evans {
586a6499c56SKyle Evans int jid, type;
587a6499c56SKyle Evans
588a6499c56SKyle Evans type = lua_type(L, 1);
589a6499c56SKyle Evans luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
590a6499c56SKyle Evans "expected a jail name (string) or id (integer)");
591a6499c56SKyle Evans
592a6499c56SKyle Evans if (lua_isstring(L, 1)) {
593a6499c56SKyle Evans /* Resolve it to a jid. */
594a6499c56SKyle Evans jid = jail_getid(lua_tostring(L, 1));
595a6499c56SKyle Evans if (jid == -1) {
596a6499c56SKyle Evans lua_pushnil(L);
597a6499c56SKyle Evans lua_pushstring(L, jail_errmsg);
598a6499c56SKyle Evans return (2);
599a6499c56SKyle Evans }
600a6499c56SKyle Evans } else {
601a6499c56SKyle Evans jid = lua_tointeger(L, 1);
602a6499c56SKyle Evans }
603a6499c56SKyle Evans
604a6499c56SKyle Evans if (jail_attach(jid) == -1) {
605a6499c56SKyle Evans lua_pushnil(L);
606a6499c56SKyle Evans lua_pushstring(L, strerror(errno));
607a6499c56SKyle Evans return (2);
608a6499c56SKyle Evans }
609a6499c56SKyle Evans
610a6499c56SKyle Evans lua_pushboolean(L, 1);
611a6499c56SKyle Evans return (1);
612a6499c56SKyle Evans }
613a6499c56SKyle Evans
614a6499c56SKyle Evans static int
l_remove(lua_State * L)615a6499c56SKyle Evans l_remove(lua_State *L)
616a6499c56SKyle Evans {
617a6499c56SKyle Evans int jid, type;
618a6499c56SKyle Evans
619a6499c56SKyle Evans type = lua_type(L, 1);
620a6499c56SKyle Evans luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
621a6499c56SKyle Evans "expected a jail name (string) or id (integer)");
622a6499c56SKyle Evans
623a6499c56SKyle Evans if (lua_isstring(L, 1)) {
624a6499c56SKyle Evans /* Resolve it to a jid. */
625a6499c56SKyle Evans jid = jail_getid(lua_tostring(L, 1));
626a6499c56SKyle Evans if (jid == -1) {
627a6499c56SKyle Evans lua_pushnil(L);
628a6499c56SKyle Evans lua_pushstring(L, jail_errmsg);
629a6499c56SKyle Evans return (2);
630a6499c56SKyle Evans }
631a6499c56SKyle Evans } else {
632a6499c56SKyle Evans jid = lua_tointeger(L, 1);
633a6499c56SKyle Evans }
634a6499c56SKyle Evans
635a6499c56SKyle Evans if (jail_remove(jid) == -1) {
636a6499c56SKyle Evans lua_pushnil(L);
637a6499c56SKyle Evans lua_pushstring(L, strerror(errno));
638a6499c56SKyle Evans return (2);
639a6499c56SKyle Evans }
640a6499c56SKyle Evans
641a6499c56SKyle Evans lua_pushboolean(L, 1);
642a6499c56SKyle Evans return (1);
643a6499c56SKyle Evans }
644a6499c56SKyle Evans
64573577bf0SRyan Moeller static const struct luaL_Reg l_jail[] = {
64673577bf0SRyan Moeller /** Get id of a jail by name.
64773577bf0SRyan Moeller * @param name jail name (string)
64873577bf0SRyan Moeller * @return jail id (integer)
64973577bf0SRyan Moeller * or nil, error (string) on error
65073577bf0SRyan Moeller */
65173577bf0SRyan Moeller {"getid", l_getid},
65273577bf0SRyan Moeller /** Get name of a jail by id.
65373577bf0SRyan Moeller * @param jid jail id (integer)
65473577bf0SRyan Moeller * @return jail name (string)
65573577bf0SRyan Moeller * or nil, error (string) on error
65673577bf0SRyan Moeller */
65773577bf0SRyan Moeller {"getname", l_getname},
65873577bf0SRyan Moeller /** Get a list of all known jail parameters.
65973577bf0SRyan Moeller * @return list of jail parameter names (table of strings)
66073577bf0SRyan Moeller * or nil, error (string) on error
66173577bf0SRyan Moeller */
66273577bf0SRyan Moeller {"allparams", l_allparams},
66373577bf0SRyan Moeller /** Get the listed params for a given jail.
66473577bf0SRyan Moeller * @param jail jail name (string) or id (integer)
66573577bf0SRyan Moeller * @param params list of parameter names (table of strings)
66673577bf0SRyan Moeller * @param flags optional flags (integer)
66773577bf0SRyan Moeller * @return jid (integer), params (table of [string] = string)
66873577bf0SRyan Moeller * or nil, error (string) on error
66973577bf0SRyan Moeller */
67073577bf0SRyan Moeller {"getparams", l_getparams},
67173577bf0SRyan Moeller /** Set params for a given jail.
67273577bf0SRyan Moeller * @param jail jail name (string) or id (integer)
67373577bf0SRyan Moeller * @param params params and values (table of [string] = string)
67473577bf0SRyan Moeller * @param flags optional flags (integer)
67573577bf0SRyan Moeller * @return jid (integer)
67673577bf0SRyan Moeller * or nil, error (string) on error
67773577bf0SRyan Moeller */
67873577bf0SRyan Moeller {"setparams", l_setparams},
6796a7647ecSKyle Evans /** Get a list of jail parameters for running jails on the system.
6806a7647ecSKyle Evans * @param params optional list of parameter names (table of
6816a7647ecSKyle Evans * strings)
6826a7647ecSKyle Evans * @return iterator (function), jail_obj (object) with next and
6836a7647ecSKyle Evans * close methods
6846a7647ecSKyle Evans */
6856a7647ecSKyle Evans {"list", l_list},
686a6499c56SKyle Evans /** Attach to a running jail.
687a6499c56SKyle Evans * @param jail jail name (string) or id (integer)
688a6499c56SKyle Evans * @return true (boolean)
689a6499c56SKyle Evans * or nil, error (string) on error
690a6499c56SKyle Evans */
691a6499c56SKyle Evans {"attach", l_attach},
692a6499c56SKyle Evans /** Remove a running jail.
693a6499c56SKyle Evans * @param jail jail name (string) or id (integer)
694a6499c56SKyle Evans * @return true (boolean)
695a6499c56SKyle Evans * or nil, error (string) on error
696a6499c56SKyle Evans */
697a6499c56SKyle Evans {"remove", l_remove},
69873577bf0SRyan Moeller {NULL, NULL}
69973577bf0SRyan Moeller };
70073577bf0SRyan Moeller
70173577bf0SRyan Moeller int
luaopen_jail(lua_State * L)70273577bf0SRyan Moeller luaopen_jail(lua_State *L)
70373577bf0SRyan Moeller {
70473577bf0SRyan Moeller lua_newtable(L);
70573577bf0SRyan Moeller
70673577bf0SRyan Moeller luaL_setfuncs(L, l_jail, 0);
70773577bf0SRyan Moeller
70873577bf0SRyan Moeller lua_pushinteger(L, JAIL_CREATE);
70973577bf0SRyan Moeller lua_setfield(L, -2, "CREATE");
71073577bf0SRyan Moeller lua_pushinteger(L, JAIL_UPDATE);
71173577bf0SRyan Moeller lua_setfield(L, -2, "UPDATE");
71273577bf0SRyan Moeller lua_pushinteger(L, JAIL_ATTACH);
71373577bf0SRyan Moeller lua_setfield(L, -2, "ATTACH");
71473577bf0SRyan Moeller lua_pushinteger(L, JAIL_DYING);
71573577bf0SRyan Moeller lua_setfield(L, -2, "DYING");
71673577bf0SRyan Moeller
7176a7647ecSKyle Evans register_jail_metatable(L);
7186a7647ecSKyle Evans
71973577bf0SRyan Moeller return (1);
72073577bf0SRyan Moeller }
721*151bd351SKyle Evans
722*151bd351SKyle Evans FLUA_MODULE(jail);
723