xref: /src/libexec/flua/libjail/lua_jail.c (revision 151bd3516b541823b16793460d73916e63d2b9c1)
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(&params);
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(&params[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(&params[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(&params[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(&params[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(&params[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, &params_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(&params[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(&params[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(&params[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(&params[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(&params[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(&params[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(&params[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