xref: /freebsd-13.1/lib/flua/libjail/lua_jail.c (revision 5bdce6ff)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020, Ryan Moeller <[email protected]>
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 	luaL_argcheck(L, params_count > 1, 2, "expected #params > 0");
117 	flags = luaL_optinteger(L, 3, 0);
118 
119 	params = malloc(params_count * sizeof(struct jailparam));
120 	if (params == NULL)
121 		return (luaL_error(L, "malloc: %s", strerror(errno)));
122 
123 	/*
124 	 * Set the jail name or id param as determined by the first arg.
125 	 */
126 
127 	if (type == LUA_TSTRING) {
128 		if (jailparam_init(&params[0], "name") == -1) {
129 			free(params);
130 			return (luaL_error(L, "jailparam_init: %s",
131 			    jail_errmsg));
132 		}
133 		name = lua_tostring(L, 1);
134 		if (jailparam_import(&params[0], name) == -1) {
135 			jailparam_free(params, 1);
136 			free(params);
137 			return (luaL_error(L, "jailparam_import: %s",
138 			    jail_errmsg));
139 		}
140 	} else /* type == LUA_TNUMBER */ {
141 		if (jailparam_init(&params[0], "jid") == -1) {
142 			free(params);
143 			return (luaL_error(L, "jailparam_init: %s",
144 			    jail_errmsg));
145 		}
146 		jid = lua_tointeger(L, 1);
147 		if (jailparam_import_raw(&params[0], &jid, sizeof(jid)) == -1) {
148 			jailparam_free(params, 1);
149 			free(params);
150 			return (luaL_error(L, "jailparam_import_raw: %s",
151 			    jail_errmsg));
152 		}
153 	}
154 
155 	/*
156 	 * Set the remaining param names being requested.
157 	 */
158 
159 	skipped = 0;
160 	for (size_t i = 1; i < params_count; ++i) {
161 		const char *param_name;
162 
163 		lua_rawgeti(L, -1, i);
164 		param_name = lua_tostring(L, -1);
165 		if (param_name == NULL) {
166 			jailparam_free(params, i - skipped);
167 			free(params);
168 			return (luaL_argerror(L, 2,
169 			    "param names must be strings"));
170 		}
171 		lua_pop(L, 1);
172 		/* Skip name or jid, whichever was given. */
173 		if (type == LUA_TSTRING) {
174 			if (strcmp(param_name, "name") == 0) {
175 				++skipped;
176 				continue;
177 			}
178 		} else /* type == LUA_TNUMBER */ {
179 			if (strcmp(param_name, "jid") == 0) {
180 				++skipped;
181 				continue;
182 			}
183 		}
184 		if (jailparam_init(&params[i - skipped], param_name) == -1) {
185 			jailparam_free(params, i - skipped);
186 			free(params);
187 			return (luaL_error(L, "jailparam_init: %s",
188 			    jail_errmsg));
189 		}
190 	}
191 	params_count -= skipped;
192 
193 	/*
194 	 * Get the values and convert to a table.
195 	 */
196 
197 	jid = jailparam_get(params, params_count, flags);
198 	if (jid == -1) {
199 		jailparam_free(params, params_count);
200 		free(params);
201 		lua_pushnil(L);
202 		lua_pushstring(L, jail_errmsg);
203 		return (2);
204 	}
205 	lua_pushinteger(L, jid);
206 
207 	lua_newtable(L);
208 	for (size_t i = 0; i < params_count; ++i) {
209 		char *value;
210 
211 		value = jailparam_export(&params[i]);
212 		lua_pushstring(L, value);
213 		free(value);
214 		lua_setfield(L, -2, params[i].jp_name);
215 	}
216 
217 	jailparam_free(params, params_count);
218 	free(params);
219 
220 	return (2);
221 }
222 
223 static int
224 l_setparams(lua_State *L)
225 {
226 	const char *name;
227 	struct jailparam *params;
228 	size_t params_count;
229 	int flags, jid, type;
230 
231 	type = lua_type(L, 1);
232 	luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
233 	    "expected a jail name (string) or id (integer)");
234 	luaL_checktype(L, 2, LUA_TTABLE);
235 
236 	lua_pushnil(L);
237 	for (params_count = 1; lua_next(L, 2) != 0; ++params_count)
238 		lua_pop(L, 1);
239 	luaL_argcheck(L, params_count > 1, 2, "expected #params > 0");
240 
241 	flags = luaL_optinteger(L, 3, 0);
242 
243 	params = malloc(params_count * sizeof(struct jailparam));
244 	if (params == NULL)
245 		return (luaL_error(L, "malloc: %s", strerror(errno)));
246 
247 	/*
248 	 * Set the jail name or id param as determined by the first arg.
249 	 */
250 
251 	if (type == LUA_TSTRING) {
252 		if (jailparam_init(&params[0], "name") == -1) {
253 			free(params);
254 			return (luaL_error(L, "jailparam_init: %s",
255 			    jail_errmsg));
256 		}
257 		name = lua_tostring(L, 1);
258 		if (jailparam_import(&params[0], name) == -1) {
259 			jailparam_free(params, 1);
260 			free(params);
261 			return (luaL_error(L, "jailparam_import: %s",
262 			    jail_errmsg));
263 		}
264 	} else /* type == LUA_TNUMBER */ {
265 		if (jailparam_init(&params[0], "jid") == -1) {
266 			free(params);
267 			return (luaL_error(L, "jailparam_init: %s",
268 			    jail_errmsg));
269 		}
270 		jid = lua_tointeger(L, 1);
271 		if (jailparam_import_raw(&params[0], &jid, sizeof(jid)) == -1) {
272 			jailparam_free(params, 1);
273 			free(params);
274 			return (luaL_error(L, "jailparam_import_raw: %s",
275 			    jail_errmsg));
276 		}
277 	}
278 
279 	/*
280 	 * Set the rest of the provided params.
281 	 */
282 
283 	lua_pushnil(L);
284 	for (size_t i = 1; i < params_count && lua_next(L, 2) != 0; ++i) {
285 		const char *value;
286 
287 		name = lua_tostring(L, -2);
288 		if (name == NULL) {
289 			jailparam_free(params, i);
290 			free(params);
291 			return (luaL_argerror(L, 2,
292 			    "param names must be strings"));
293 		}
294 		if (jailparam_init(&params[i], name) == -1) {
295 			jailparam_free(params, i);
296 			free(params);
297 			return (luaL_error(L, "jailparam_init: %s",
298 			    jail_errmsg));
299 		}
300 
301 		value = lua_tostring(L, -1);
302 		if (value == NULL) {
303 			jailparam_free(params, i + 1);
304 			free(params);
305 			return (luaL_argerror(L, 2,
306 			    "param values must be strings"));
307 		}
308 		if (jailparam_import(&params[i], value) == -1) {
309 			jailparam_free(params, i + 1);
310 			free(params);
311 			return (luaL_error(L, "jailparam_import: %s",
312 			    jail_errmsg));
313 		}
314 
315 		lua_pop(L, 1);
316 	}
317 
318 	/*
319 	 * Attempt to set the params.
320 	 */
321 
322 	jid = jailparam_set(params, params_count, flags);
323 	if (jid == -1) {
324 		jailparam_free(params, params_count);
325 		free(params);
326 		lua_pushnil(L);
327 		lua_pushstring(L, jail_errmsg);
328 		return (2);
329 	}
330 	lua_pushinteger(L, jid);
331 
332 	jailparam_free(params, params_count);
333 	free(params);
334 	return (1);
335 }
336 
337 static const struct luaL_Reg l_jail[] = {
338 	/** Get id of a jail by name.
339 	 * @param name	jail name (string)
340 	 * @return	jail id (integer)
341 	 *		or nil, error (string) on error
342 	 */
343 	{"getid", l_getid},
344 	/** Get name of a jail by id.
345 	 * @param jid	jail id (integer)
346 	 * @return	jail name (string)
347 	 *		or nil, error (string) on error
348 	 */
349 	{"getname", l_getname},
350 	/** Get a list of all known jail parameters.
351 	 * @return	list of jail parameter names (table of strings)
352 	 *		or nil, error (string) on error
353 	 */
354 	{"allparams", l_allparams},
355 	/** Get the listed params for a given jail.
356 	 * @param jail	jail name (string) or id (integer)
357 	 * @param params	list of parameter names (table of strings)
358 	 * @param flags	optional flags (integer)
359 	 * @return	jid (integer), params (table of [string] = string)
360 	 *		or nil, error (string) on error
361 	 */
362 	{"getparams", l_getparams},
363 	/** Set params for a given jail.
364 	 * @param jail	jail name (string) or id (integer)
365 	 * @param params	params and values (table of [string] = string)
366 	 * @param flags	optional flags (integer)
367 	 * @return	jid (integer)
368 	 *		or nil, error (string) on error
369 	 */
370 	{"setparams", l_setparams},
371 	{NULL, NULL}
372 };
373 
374 int
375 luaopen_jail(lua_State *L)
376 {
377 	lua_newtable(L);
378 
379 	luaL_setfuncs(L, l_jail, 0);
380 
381 	lua_pushinteger(L, JAIL_CREATE);
382 	lua_setfield(L, -2, "CREATE");
383 	lua_pushinteger(L, JAIL_UPDATE);
384 	lua_setfield(L, -2, "UPDATE");
385 	lua_pushinteger(L, JAIL_ATTACH);
386 	lua_setfield(L, -2, "ATTACH");
387 	lua_pushinteger(L, JAIL_DYING);
388 	lua_setfield(L, -2, "DYING");
389 
390 	return (1);
391 }
392