summaryrefslogtreecommitdiffstats
path: root/lib/privsep.lua
blob: d2edcb7d5c091654572cc24e1ca52bc2b9ace28d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

module(..., package.seeall)

require("json")
require("posix")

local rpc = {}

-- private privileged rpc server ------------------------------------
local function rpcserver(r, w)
	for line in r:lines() do
		local handle = json.decode(line)
		if type(rpc[handle.func]) == "function" then
			response = rpc[handle.func](unpack(handle.data))
		else
			response = nil
		end
		w:write(json.encode(response).."\n")
		w:flush()
	end
end


-- public func ---------------------------------------------------- 
function drop_privs(user, group, privileged_funcs)
	local k, v
	local wrapper = {}

	-- communication pipes
	local cr, pw = posix.pipe()
	local pr, cw = posix.pipe()

	-- create wrapper table
	for k,v in pairs(privileged_funcs or {}) do
		if type(v) == "function" then
			rpc[k] = v
			wrapper[k] = function(...)
				local handle = {}
				handle.func = k
				handle.data = {...}
				cw:write(json.encode(handle).."\n")
				cw:flush()
				return (json.decode(cr:read("*line")))
			end
		end
	end
			
	pid = posix.fork()
	if pid == nil then
		cr:close()
		cw:close()
		pr:close()
		cw:close()
		return nil
	end

	if pid == 0 then
		-- child runs with privs
		cr:close()
		cw:close()
		rpcserver(pr, pw)
		pw:close()
		pr:close()
		os.exit()
	end

	-- lets drop privs
	if posix.setpid("g", group) and	posix.setpid("u", user) then
		return wrapper
	else
		posix.kill(pid)
		return nil
	end
end