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