diff options
Diffstat (limited to 'lib/supple/capi.c')
-rw-r--r-- | lib/supple/capi.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/lib/supple/capi.c b/lib/supple/capi.c index c413c20..c0f8f48 100644 --- a/lib/supple/capi.c +++ b/lib/supple/capi.c @@ -13,7 +13,12 @@ #include <lua.h> #include <lauxlib.h> +#include <sys/types.h> #include <string.h> +#include <stdbool.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> /* The API exposed, increment on backward-compatible changes */ #define CAPI_API 1 @@ -157,12 +162,95 @@ supple_capi_rawtype(lua_State *L) return 1; } +/* Lockdown function, takes nothing, returns a string token and errno which + * explains the result. We're using SUPPLE_MKDTEMP as a template for + * mkdtemp(). The wrapper ensures it is unset unless testing. + */ +#define TEMPDIR_NAME ((getenv("SUPPLE_MKDTEMP") != NULL) ? \ + (getenv("SUPPLE_MKDTEMP")) : ("/var/tmp/suppleXXXXXX")) +static int +supple_capi_lockdown(lua_State *L) +{ + bool rootly = (geteuid() == 0); + char *tempdir; + lua_settop(L, 0); /* Discard any arguments */ + + /* Prepare a copy of the tempdir template ready */ + tempdir = lua_newuserdata(L, strlen(TEMPDIR_NAME)); + strcpy(tempdir, TEMPDIR_NAME); + /* And make a temp directory to use */ + if (mkdtemp(tempdir) != tempdir) { + /* Failed to make the temp dir, give up */ + int saved_errno = errno; + lua_pushliteral(L, "mkdir"); + lua_pushnumber(L, saved_errno); + return 2; + } + + /* Temporary directory made, if we're rootly, chown it */ + if (rootly) { + if (chown(tempdir, 0, 0) != 0) { + int saved_errno = errno; + rmdir(tempdir); + lua_pushliteral(L, "chown"); + lua_pushnumber(L, saved_errno); + return 2; + } + } + + /* Change into that directory */ + if (chdir(tempdir) != 0) { + int saved_errno = errno; + rmdir(tempdir); + lua_pushliteral(L, "chdir"); + lua_pushnumber(L, saved_errno); + return 2; + } + + /* Remove the directory */ + if (rmdir(tempdir) != 0) { + int saved_errno = errno; + lua_pushliteral(L, "rmdir"); + lua_pushnumber(L, saved_errno); + return 2; + } + + /* chroot() to the ephemeral dir */ + if (rootly && (chroot(".") != 0)) { + int saved_errno = errno; + lua_pushliteral(L, "chroot"); + lua_pushnumber(L, saved_errno); + return 2; + } + + /* Ensure our PWD is "/" */ + if (rootly && chdir("/") != 0) { + int saved_errno = errno; + lua_pushliteral(L, "chdir"); + lua_pushnumber(L, saved_errno); + return 2; + } + + /* Drop privs */ + if (rootly && setuid(getuid()) != 0) { + int saved_errno = errno; + lua_pushliteral(L, "setuid"); + lua_pushnumber(L, saved_errno); + return 2; + } + + lua_pushstring(L, (rootly ? "ok" : "oknonroot")); + lua_pushnumber(L, 0); + return 2; +} + static const struct luaL_Reg supple_capi_functions[] = { { "explain", supple_capi_explain }, { "new_proxy", supple_capi_new_proxy }, { "type", supple_capi_type }, { "rawtype", supple_capi_rawtype }, + { "lockdown", supple_capi_lockdown }, { NULL, NULL } }; |