summaryrefslogtreecommitdiffstats
path: root/awall-model.lua
blob: 7cec5b4e003c41283114805aa252f130b05d3391 (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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
module(..., package.seeall)

-- Load libraries
require("posix")
require("json")
require("modelfunctions")
fs = require("acf.fs")

-- Set variables
local packagename = "awall"

local etcpath = "/etc/awall/"
local etcoptionalpath = "/etc/awall/optional/"
local usrpath = "/usr/share/awall/mandatory/"
local usroptionalpath = "/usr/share/awall/optional/"

-- ################################################################################
-- LOCAL FUNCTIONS

local findfiles = function(where)
	local files = {}
	for d in posix.files(where) do
		if string.find(d, "%.json$") then
			if fs.is_file(where .. d) and string.find(d, "%.json$") then
				files[#files+1] = where..d
			elseif fs.is_link(where .. d) then
				-- awall will use links, but we want to drop the links from /etc/awall/ to one of the optional dirs
				-- because those are the ones handled by enable/disable
				local link = posix.dirname(posix.readlink(where..d) or "").."/"
logevent("link = "..link)
				if where == etcpath and (string.find(link, "^"..etcoptionalpath.."$") or string.find(link, "^"..usroptionalpath.."$")) then
					-- do nothing
				else
					files[#files+1] = where..d
				end

			end
		end
	end
	return files
end

local validatefiledetails = function(filedetails)
	local success = true
	local res, err = pcall(function()
        	local jsonoutput, count = json.decode(filedetails.value.filecontent.value)
        end)
	if not res and err then
		success = false
	end

	if not success then
		filedetails.value.filecontent.errtxt = "Invalid json code\n"..(err or "")
	end
	return success, filedetails
end

local validateeditablefile = function(filename)
	-- get/setfiledetails only work for files (not links), this prevents editing/deleting the enable links
	local dir = posix.dirname(filename or "").."/"
	if fs.is_file(filename) and string.find(filename, "%.json$") and (dir==etcpath or dir==etcoptionalpath) then
		return true
	else
		return false
	end
end

-- ################################################################################
-- PUBLIC FUNCTIONS

function getstatus()
	return modelfunctions.getstatus(nil, packagename, "AWall Status")
end

function get_startstop(self, clientdata)
        local actions = {"Verify", "Translate", "Activate"}
	return cfe({ type="group", label="Management", value={}, option=actions })
end

function startstop_service(self, startstop, action)        
	if not action then
		startstop.errtxt = "Invalid Action"
	else
		local cmd = {"awall"}
		if action == "Verify" then
			cmd[#cmd+1] = "translate"
			cmd[#cmd+1] = "-V"
		elseif action == "Translate" then
			cmd[#cmd+1] = "translate"
		else
			cmd[#cmd+1] = "activate"
			cmd[#cmd+1] = "-f"
		end
		startstop.descr, startstop.errtxt = modelfunctions.run_executable(cmd, true)
		if not startstop.errtxt and startstop.descr == "" then
			startstop.descr = "Success"
		end
	end
	return startstop
end

function list_policies()
	-- core-router     disabled  BSN core router
	local policies = {}
	local reversepolicies = {}
	local errtxt
	local f = modelfunctions.run_executable({"awall", "list"}, true)
	for l in string.gmatch(f, "[^\n]+") do
		local a,b,c = string.match(l, "(%S+)%s+(%S+)%s*(.*)")
		if a and a == "/usr/bin/lua:" then
			errtxt = b.." "..c
			break
		end
		if a then
			policies[#policies+1] = {name=a, status=b, description=c}
			reversepolicies[a] = #policies
		end
	end
	-- Since awall seems to crash (and not give results) when there is any error
	-- Let's show the actual files too
	local addfiles = function(files, editable, mandatory)
		for i,d in ipairs(files) do
			local name = string.match(d, "([^/]*)%.json$")
			if reversepolicies[name] then
				policies[reversepolicies[name]].filename = d
				policies[reversepolicies[name]].editable = editable
				if mandatory then policies[reversepolicies[name]].status = "mandatory" end
			else
				policies[#policies+1] = {name=name, filename=d, editable=editable}
				if mandatory then policies[#policies].status = "mandatory" end
				reversepolicies[name] = #policies
			end
		end
	end

	local files = findfiles(usroptionalpath)
	addfiles(files, false, false)
	files = findfiles(etcoptionalpath)
	addfiles(files, true, false)
	files = findfiles(usrpath)
	addfiles(files, false, true)
	files = findfiles(etcpath)
	addfiles(files, true, true)

	table.sort(policies, function(a,b) return a.name < b.name end)

	return cfe({ type="list", value=policies, label="Policies", errtxt=errtxt })
end

function get_newpolicy()
	local newpolicy = {}
	newpolicy.name = cfe({ label="Name", seq=1 })
	newpolicy.optional = cfe({ type="boolean", label="Optional", seq=2 })
	return cfe({ type="group", value=newpolicy, label="New Policy" })
end

function create_policy(self, newpolicy)
	local success = true
	local name = newpolicy.value.name.value

	if name == "" then
		newpolicy.value.name.errtxt = "Invalid name"
		success = false
	else
		local policies = list_policies()
		for i,pol in ipairs(policies.value) do
			if pol.name == newpolicy.value.name.value then
				newpolicy.value.name.errtxt = "Name already exists"
				success = false
				break
			end
		end
	end

	if success then
		local path
		if newpolicy.value.optional.value then
			path = etcoptionalpath
		else
			path = etcpath
		end
		path = path..name..".json"
		if posix.stat(path) then
			newpolicy.value.name.errtxt = path.." already exists"
			success = false
		else
			fs.write_file(path, "{}")
		end
	end

	if not success then
		newpolicy.errtxt = "Failed to create policy file"
	end

	return newpolicy
end

function get_delete_policy(self, clientdata)
	retval = {}
	retval.filename = cfe({ value=clientdata.filename or "", label="File Name" })
	return cfe({ type="group", value=retval, label="Delete Policy File" })
end

function delete_policy(self, delpolicy)
	if validateeditablefile(delpolicy.value.filename.value) then
		os.remove(delpolicy.value.filename.value)
	else
		delpolicy.errtxt = "Failed to delete policy"
		delpolicy.value.filename.errtxt="Policy not found"
	end

	return delpolicy
end

function read_policyfile(self, clientdata)
	-- Can read from all 4 locations
	return modelfunctions.getfiledetails(clientdata.filename, function(filename)
		local dir = posix.dirname(filename or "").."/"
		if string.find(filename, "%.json$") and (dir==etcpath or dir==etcoptionalpath or dir==usrpath or dir==usroptionalpath) then
			return true
		else
			return false
		end
		end)
end

function get_policyfile(self, clientdata)
	-- Can only get (for editing) from /etc/ locations
	return modelfunctions.getfiledetails(clientdata.filename, validateeditablefile)
end

function update_policyfile(self, filedetails)
	return modelfunctions.setfiledetails(self, filedetails, validateeditablefile, validatefiledetails)
end

function get_enablepolicy(self, clientdata)
	local policy = {}
	policy.name = cfe({ value=clientdata.name or "", label="Name", seq=1 })
	return cfe({ type="group", value=policy, label="Policy" })
end

function enable_policy(self, enable)
	enable.descr, enable.errtxt = modelfunctions.run_executable({"awall", "enable", enable.value.name.value}, true)
	return enable
end

function disable_policy(self, disable)
	disable.descr, disable.errtxt = modelfunctions.run_executable({"awall", "disable", disable.value.name.value}, true)
	return disable
end