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(¶ms); 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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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(¶ms[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