summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2012-12-12 11:04:07 +0100
committerNatanael Copa <ncopa@alpinelinux.org>2012-12-12 11:04:07 +0100
commit5fef443b54a26a69be9ccdd22b44c62ecb133abc (patch)
treebcb3118c37451f41a87339990a076eb89ea33133
downloadprivsep-5fef443b54a26a69be9ccdd22b44c62ecb133abc.tar.bz2
privsep-5fef443b54a26a69be9ccdd22b44c62ecb133abc.tar.xz
initial prototype
-rw-r--r--Makefile16
-rw-r--r--example.lua9
-rw-r--r--lua-privsep.c58
-rw-r--r--modules/mymod.lua7
-rw-r--r--privsep-main.lua50
-rw-r--r--privsep.lua42
6 files changed, 182 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e0e03cb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+
+COMPILE_PROG = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $($@_objs) $($@_libs)
+
+
+PKGCONF ?= pkg-config
+
+LUA_PKG ?= lua
+LUA_CFLAGS := $(shell $(PKGCONF) --cflags $(LUA_PKG))
+LUA_LIBS := $(shell $(PKGCONF) --libs $(LUA_PKG))
+
+lua-privsep_objs = lua-privsep.o
+lua-privsep_libs = $(LUA_LIBS)
+
+lua-privsep: $(lua-privsep_objs)
+ $(COMPILE_PROG)
+
diff --git a/example.lua b/example.lua
new file mode 100644
index 0000000..324df49
--- /dev/null
+++ b/example.lua
@@ -0,0 +1,9 @@
+
+privsep = require("privsep")
+
+mymod = privsep.wrap("mymod", "mysessionid")
+
+print(mymod.myfunc("foo", false))
+
+
+
diff --git a/lua-privsep.c b/lua-privsep.c
new file mode 100644
index 0000000..2325b65
--- /dev/null
+++ b/lua-privsep.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#ifndef PRIVSEP_PATH
+#define PRIVSEP_PATH "./"
+#endif
+
+static int traceback (lua_State *L) {
+ if (!lua_isstring(L, 1)) /* 'message' not a string? */
+ return 1; /* keep it intact */
+ fprintf(stderr, "traceback\n");
+ lua_getfield(L, LUA_GLOBALSINDEX, "debug");
+ if (!lua_istable(L, -1)) {
+ fprintf(stderr, "traceback: debug\n");
+ lua_pop(L, 1);
+ return 1;
+ }
+
+ lua_getfield(L, -1, "traceback");
+ if (!lua_isfunction(L, -1)) {
+ fprintf(stderr, "traceback: traceback\n");
+ lua_pop(L, 2);
+ return 1;
+ }
+
+ lua_pushvalue(L, 1); /* pass error message */
+ lua_pushinteger(L, 2); /* skip this function and traceback */
+ lua_call(L, 2, 1); /* call debug.traceback */
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *luamain = PRIVSEP_PATH "privsep-main.lua";
+ int i, traceback_index;
+
+ lua_State *L = luaL_newstate();
+ luaL_openlibs(L);
+
+ lua_pushcfunction(L, traceback);
+ traceback_index = lua_gettop(L);
+
+ if (luaL_loadfile(L, luamain))
+ return luaL_error(L, "%s", luamain);
+
+ for (i = 1; i < argc; i++)
+ lua_pushstring(L, argv[i]);
+
+ if (lua_pcall(L, argc-1, 0, traceback_index))
+ return luaL_error(L, "error");
+
+
+ return 0;
+}
+
diff --git a/modules/mymod.lua b/modules/mymod.lua
new file mode 100644
index 0000000..1f5de06
--- /dev/null
+++ b/modules/mymod.lua
@@ -0,0 +1,7 @@
+local mymod = {}
+
+function mymod.myfunc(arg1, arg2)
+ return "hello from mymod.myfunc. arg1 is '"..tostring(arg1).."' and arg2 is '"..tostring(arg2).."'"
+end
+
+return mymod
diff --git a/privsep-main.lua b/privsep-main.lua
new file mode 100644
index 0000000..8fe447c
--- /dev/null
+++ b/privsep-main.lua
@@ -0,0 +1,50 @@
+modname = ...
+
+if not modname then
+ modname = "session"
+end
+
+json = require("json")
+
+
+function ret_error(errmsg)
+ io.write(json.encode({false, errmsg, nil}).."\n")
+ os.exit(0)
+end
+
+function ret_success(result)
+ io.write(json.encode({true, "success", result}).."\n")
+end
+
+-- path must be absolute for production so users cannot load scripts from
+-- non secured dirs
+modules_path = "./modules/"
+
+if not modname then
+ return 1
+end
+
+-- make sure we dont have any path elements in modname so we cannot pass
+-- modnames like '../myevilmod'
+mfile = modules_path..string.gsub(modname, ".*/", "")..".lua"
+
+-- load the module
+m = dofile(mfile)
+
+-- read args from stdin
+request = json.decode(io.read("*a"))
+funcname, sessionid, args = unpack(request)
+
+--ret_error(funcname)
+-- check that the func we want exists
+if type(m[funcname]) ~= "function" then
+ ret_error(funcname..": not a function")
+end
+
+-- TODO: check permissions here
+
+-- execute the func and pack the return values into a table
+result = { m[funcname](unpack(args)) }
+
+ret_success(result)
+
diff --git a/privsep.lua b/privsep.lua
new file mode 100644
index 0000000..de4087a
--- /dev/null
+++ b/privsep.lua
@@ -0,0 +1,42 @@
+
+lpc = require("lpc")
+json = require("json")
+
+local privsep_exec = "./lua-privsep"
+local modules_path = "./modules"
+
+local privsep = {}
+function privsep.call_privileged(modname, funcname, sessionid, args)
+ local pid, w, r = lpc.run(privsep_exec, modname)
+ w:write(json.encode{ funcname, sessionid, args }.."\n")
+ w:close()
+
+ local resp = r:read("*all")
+ local retcode = lpc.wait(pid)
+
+ if resp == nil or resp == "" then
+ io.stderr:write("remote '"..modname.."' failed: "..tostring(retcode).."\n")
+ return nil
+ end
+
+ local data = json.decode(resp)
+ local status, errmsg, result = unpack(data)
+ if not status then
+ io.stderr:write("modname: "..tostring(errmsg).."\n")
+ return nil
+ end
+ return unpack(result)
+end
+
+function privsep.wrap(modname, sessionid)
+ local mod = dofile(modules_path.."/"..modname..".lua")
+ local f = {}
+ for k,v in pairs(mod) do
+ f[k] = function(...)
+ return privsep.call_privileged(modname, k, sessionid, {...})
+ end
+ end
+ return f
+end
+
+return privsep