xref: /freebsd/lib/flua/libjail/lua_jail.c (revision 19261079)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/jail.h>
35 #include <errno.h>
36 #include <jail.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <lua.h>
41 #include <lauxlib.h>
42 #include <lualib.h>
43 
44 int luaopen_jail(lua_State *);
45 
46 static int
47 l_getid(lua_State *L)
48 {
49 	const char *name;
50 	int jid;
51 
52 	name = luaL_checkstring(L, 1);
53 	jid = jail_getid(name);
54 	if (jid == -1) {
55 		lua_pushnil(L);
56 		lua_pushstring(L, jail_errmsg);
57 		return (2);
58 	}
59 	lua_pushinteger(L, jid);
60 	return (1);
61 }
62 
63 static int
64 l_getname(lua_State *L)
65 {
66 	char *name;
67 	int jid;
68 
69 	jid = luaL_checkinteger(L, 1);
70 	name = jail_getname(jid);
71 	if (name == NULL) {
72 		lua_pushnil(L);
73 		lua_pushstring(L, jail_errmsg);
74 		return (2);
75 	}
76 	lua_pushstring(L, name);
77 	free(name);
78 	return (1);
79 }
80 
81 static int
82 l_allparams(lua_State *L)
83 {
84 	struct jailparam *params;
85 	int params_count;
86 
87 	params_count = jailparam_all(&params);
88 	if (params_count == -1) {
89 		lua_pushnil(L);
90 		lua_pushstring(L, jail_errmsg);
91 		return (2);
92 	}
93 	lua_newtable(L);
94 	for (int i = 0; i < params_count; ++i) {
95 		lua_pushstring(L, params[i].jp_name);
96 		lua_rawseti(L, -2, i + 1);
97 	}
98 	jailparam_free(params, params_count);
99 	free(params);
100 	return (1);
101 }
102 
103 static int
104 l_getparams(lua_State *L)
105 {
106 	const char *name;
107 	struct jailparam *params;
108 	size_t params_count, skipped;
109 	int flags, jid, type;
110 
111 	type = lua_type(L, 1);
112 	luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
113 	    "expected a jail name (string) or id (integer)");
114 	luaL_checktype(L, 2, LUA_TTABLE);
115 	params_count = 1 + lua_rawlen(L, 2);
116 	flags = luaL_optinteger(L, 3, 0);
117 
118 	params = malloc(params_count * sizeof(struct jailparam));
119 	if (params == NULL)
120 		return (luaL_error(L, "malloc: %s", strerror(errno)));
121 
122 	/*
123 	 * Set the jail name or id param as determined by the first arg.
124 	 */
125 
126 	if (type == LUA_TSTRING) {
127 		if (jailparam_init(&params[0], "name") == -1) {
128 			free(params);
129 			return (luaL_error(L, "jailparam_init: %s",
130 			    jail_errmsg));
131 		}
132 		name = lua_tostring(L, 1);
133 		if (jailparam_import(&params[0], name) == -1) {
134 			jailparam_free(params, 1);
135 			free(params);
136 			return (luaL_error(L, "jailparam_import: %s",
137 			    jail_errmsg));
138 		}
139 	} else /* type == LUA_TNUMBER */ {
140 		if (jailparam_init(&params[0], "jid") == -1) {
141 			free(params);
142 			return (luaL_error(L, "jailparam_init: %s",
143 			    jail_errmsg));
144 		}
145 		jid = lua_tointeger(L, 1);
146 		if (jailparam_import_raw(&params[0], &jid, sizeof(jid)) == -1) {
147 			jailparam_free(params, 1);
148 			free(params);
149 			return (luaL_error(L, "jailparam_import_raw: %s",
150 			    jail_errmsg));
151 		}
152 	}
153 
154 	/*
155 	 * Set the remaining param names being requested.
156 	 */
157 
158 	skipped = 0;
159 	for (size_t i = 1; i < params_count; ++i) {
160 		const char *param_name;
161 
162 		lua_rawgeti(L, -1, i);
163 		param_name = lua_tostring(L, -1);
164 		if (param_name == NULL) {
165 			jailparam_free(params, i - skipped);
166 			free(params);
167 			return (luaL_argerror(L, 2,
168 			    "param names must be strings"));
169 		}
170 		lua_pop(L, 1);
171 		/* Skip name or jid, whichever was given. */
172 		if (type == LUA_TSTRING) {
173 			if (strcmp(param_name, "name") == 0) {
174 				++skipped;
175 				continue;
176 			}
177 		} else /* type == LUA_TNUMBER */ {
178 			if (strcmp(param_name, "jid") == 0) {
179 				++skipped;
180 				continue;
181 			}
182 		}
183 		if (jailparam_init(&params[i - skipped], param_name) == -1) {
184 			jailparam_free(params, i - skipped);
185 			free(params);
186 			return (luaL_error(L, "jailparam_init: %s",
187 			    jail_errmsg));
188 		}
189 	}
190 	params_count -= skipped;
191 
192 	/*
193 	 * Get the values and convert to a table.
194 	 */
195 
196 	jid = jailparam_get(params, params_count, flags);
197 	if (jid == -1) {
198 		jailparam_free(params, params_count);
199 		free(params);
200 		lua_pushnil(L);
201 		lua_pushstring(L, jail_errmsg);
202 		return (2);
203 	}
204 	lua_pushinteger(L, jid);
205 
206 	lua_newtable(L);
207 	for (size_t i = 0; i < params_count; ++i) {
208 		char *value;
209 
210 		value = jailparam_export(&params[i]);
211 		lua_pushstring(L, value);
212 		free(value);
213 		lua_setfield(L, -2, params[i].jp_name);
214 	}
215 
216 	jailparam_free(params, params_count);
217 	free(params);
218 
219 	return (2);
220 }
221 
222 static int
223 l_setparams(lua_State *L)
224 {
225 	const char *name;
226 	struct jailparam *params;
227 	size_t params_count;
228 	int flags, jid, type;
229 
230 	type = lua_type(L, 1);
231 	luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
232 	    "expected a jail name (string) or id (integer)");
233 	luaL_checktype(L, 2, LUA_TTABLE);
234 
235 	lua_pushnil(L);
236 	for (params_count = 1; lua_next(L, 2) != 0; ++params_count)
237 		lua_pop(L, 1);
238 
239 	flags = luaL_optinteger(L, 3, 0);
240 
241 	params = malloc(params_count * sizeof(struct jailparam));
242 	if (params == NULL)
243 		return (luaL_error(L, "malloc: %s", strerror(errno)));
244 
245 	/*
246 	 * Set the jail name or id param as determined by the first arg.
247 	 */
248 
249 	if (type == LUA_TSTRING) {
250 		if (jailparam_init(&params[0], "name") == -1) {
251 			free(params);
252 			return (luaL_error(L, "jailparam_init: %s",
253 			    jail_errmsg));
254 		}
255 		name = lua_tostring(L, 1);
256 		if (jailparam_import(&params[0], name) == -1) {
257 			jailparam_free(params, 1);
258 			free(params);
259 			return (luaL_error(L, "jailparam_import: %s",
260 			    jail_errmsg));
261 		}
262 	} else /* type == LUA_TNUMBER */ {
263 		if (jailparam_init(&params[0], "jid") == -1) {
264 			free(params);
265 			return (luaL_error(L, "jailparam_init: %s",
266 			    jail_errmsg));
267 		}
268 		jid = lua_tointeger(L, 1);
269 		if (jailparam_import_raw(&params[0], &jid, sizeof(jid)) == -1) {
270 			jailparam_free(params, 1);
271 			free(params);
272 			return (luaL_error(L, "jailparam_import_raw: %s",
273 			    jail_errmsg));
274 		}
275 	}
276 
277 	/*
278 	 * Set the rest of the provided params.
279 	 */
280 
281 	lua_pushnil(L);
282 	for (size_t i = 1; i < params_count && lua_next(L, 2) != 0; ++i) {
283 		const char *value;
284 
285 		name = lua_tostring(L, -2);
286 		if (name == NULL) {
287 			jailparam_free(params, i);
288 			free(params);
289 			return (luaL_argerror(L, 2,
290 			    "param names must be strings"));
291 		}
292 		if (jailparam_init(&params[i], name) == -1) {
293 			jailparam_free(params, i);
294 			free(params);
295 			return (luaL_error(L, "jailparam_init: %s",
296 			    jail_errmsg));
297 		}
298 
299 		value = lua_tostring(L, -1);
300 		if (value == NULL) {
301 			jailparam_free(params, i + 1);
302 			free(params);
303 			return (luaL_argerror(L, 2,
304 			    "param values must be strings"));
305 		}
306 		if (jailparam_import(&params[i], value) == -1) {
307 			jailparam_free(params, i + 1);
308 			free(params);
309 			return (luaL_error(L, "jailparam_import: %s",
310 			    jail_errmsg));
311 		}
312 
313 		lua_pop(L, 1);
314 	}
315 
316 	/*
317 	 * Attempt to set the params.
318 	 */
319 
320 	jid = jailparam_set(params, params_count, flags);
321 	if (jid == -1) {
322 		jailparam_free(params, params_count);
323 		free(params);
324 		lua_pushnil(L);
325 		lua_pushstring(L, jail_errmsg);
326 		return (2);
327 	}
328 	lua_pushinteger(L, jid);
329 
330 	jailparam_free(params, params_count);
331 	free(params);
332 	return (1);
333 }
334 
335 static const struct luaL_Reg l_jail[] = {
336 	/** Get id of a jail by name.
337 	 * @param name	jail name (string)
338 	 * @return	jail id (integer)
339 	 *		or nil, error (string) on error
340 	 */
341 	{"getid", l_getid},
342 	/** Get name of a jail by id.
343 	 * @param jid	jail id (integer)
344 	 * @return	jail name (string)
345 	 *		or nil, error (string) on error
346 	 */
347 	{"getname", l_getname},
348 	/** Get a list of all known jail parameters.
349 	 * @return	list of jail parameter names (table of strings)
350 	 *		or nil, error (string) on error
351 	 */
352 	{"allparams", l_allparams},
353 	/** Get the listed params for a given jail.
354 	 * @param jail	jail name (string) or id (integer)
355 	 * @param params	list of parameter names (table of strings)
356 	 * @param flags	optional flags (integer)
357 	 * @return	jid (integer), params (table of [string] = string)
358 	 *		or nil, error (string) on error
359 	 */
360 	{"getparams", l_getparams},
361 	/** Set params for a given jail.
362 	 * @param jail	jail name (string) or id (integer)
363 	 * @param params	params and values (table of [string] = string)
364 	 * @param flags	optional flags (integer)
365 	 * @return	jid (integer)
366 	 *		or nil, error (string) on error
367 	 */
368 	{"setparams", l_setparams},
369 	{NULL, NULL}
370 };
371 
372 int
373 luaopen_jail(lua_State *L)
374 {
375 	lua_newtable(L);
376 
377 	luaL_setfuncs(L, l_jail, 0);
378 
379 	lua_pushinteger(L, JAIL_CREATE);
380 	lua_setfield(L, -2, "CREATE");
381 	lua_pushinteger(L, JAIL_UPDATE);
382 	lua_setfield(L, -2, "UPDATE");
383 	lua_pushinteger(L, JAIL_ATTACH);
384 	lua_setfield(L, -2, "ATTACH");
385 	lua_pushinteger(L, JAIL_DYING);
386 	lua_setfield(L, -2, "DYING");
387 
388 	return (1);
389 }
390