diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2012-12-12 11:04:07 +0100 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2012-12-12 11:04:07 +0100 |
commit | 5fef443b54a26a69be9ccdd22b44c62ecb133abc (patch) | |
tree | bcb3118c37451f41a87339990a076eb89ea33133 | |
download | privsep-5fef443b54a26a69be9ccdd22b44c62ecb133abc.tar.bz2 privsep-5fef443b54a26a69be9ccdd22b44c62ecb133abc.tar.xz |
initial prototype
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | example.lua | 9 | ||||
-rw-r--r-- | lua-privsep.c | 58 | ||||
-rw-r--r-- | modules/mymod.lua | 7 | ||||
-rw-r--r-- | privsep-main.lua | 50 | ||||
-rw-r--r-- | privsep.lua | 42 |
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 |