summaryrefslogtreecommitdiff
path: root/lib/supple/capi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/supple/capi.c')
-rw-r--r--lib/supple/capi.c88
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 }
};