summaryrefslogtreecommitdiffstats
path: root/cgi-bin/provisioning.cgi
blob: 5ac16847cf562864658855e49ec02c5a158827db (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
#!/usr/bin/haserl --shell=lua

<%
require "posix"

local path_info = ENV["PATH_INFO"] or ENV["REQUEST_URI"] or ""
local root = ENV["DOCUMENT_ROOT"] or ""
local request_method = ENV["REQUEST_METHOD"] or ""
local user_agent = ENV["HTTP_USER_AGENT"] or ""
local ip_address = ENV["REMOTE_ADDR"] or ""
local server = ENV["SERVER_NAME"] or ""

local log = io.open("/var/log/provisioning.log", "a+")
log:write("Running provisioning.cgi ".. os.date() .. "\n")
log:write("Processing a "..request_method.." on "..path_info.."\n")
--	for a,b in pairs(ENV) do log:write(a.."=", b,"\n") end

local ACL_FILE = "/etc/provisioning/acl.conf"

function acl_check (...)
	local allowed = false
	local f = io.open(ACL_FILE)
	if f then
		for line in f:lines() do
			if string.match(user_agent, line) or string.match(ip_address, line) then
				log:write("ALLOW MATCH FOUND " .. line .. "\n")
				allowed = true
				break
			end
		end
		f:close()
	end
	if not allowed then
		log:write("ALLOW MATCH NOT FOUND. ACCESS DENIED\n")
	end
	return allowed
end

function http_code (code)
	log:write("HTTP code processed " .. code .. "\n")
	if code == 200 then
		io.stdout:write("Status: 200 OK\n")
		io.stdout:write("Content-Type: \n\n")
	elseif code == 204 then
		io.stdout:write("Status: 204 No Content\n")
		io.stdout:write("Content-Type: \n\n")
	elseif code == 302 then
		-- redirect to same file with empty mac
		io.stdout:write("Location: " .. string.gsub(path_info, "%x%x%x%x%x%x%x%x%x%x%x%x", "000000000000") .. "\n")
		io.stdout:write("Content-Type: \n\n")
		io.stdout:write("<a href=\"".. string.gsub(path_info, "%x%x%x%x%x%x%x%x%x%x%x%x", "000000000000") .."\">New Link</a>")	
	elseif code == 404 then
		io.stdout:write("Status: 404 Not Found\n")
		io.stdout:write("Content-Type: \n\n")
		io.stdout:write("Status: 404 Not Found\n")
		io.stdout:write("\n")
	elseif code == 403 then
		io.stdout:write("Status: 403 Forbidden\n")
		io.stdout:write("Content-Type: \n\n")
		io.stdout:write("Status: 403 Forbidden\n")
		io.stdout:write("\n")
	else
		io.stdout:write("Status: 400 Bad Request\n")
		io.stdout:write("Content-Type: \n\n")
		io.stdout:write("Status: 400 Bad Request\n")
		io.stdout:write("\n")
	end
end

--------------------------------------------------------------------------------------------------------------
-- Code Begins Here --
--------------------------------------------------------------------------------------------------------------
if not acl_check() then
	http_code(403)
	log:close()
	os.exit()
end

local basename = posix.basename(path_info)
local mac = string.match(basename, "%x%x%x%x%x%x%x%x%x%x%x%x")

if ( request_method == "GET" ) then
	-- Hack to allow download of config files with firmare URL, replacing $SERV with SERVER_NAME
	local firmwaretricks = {"Linksys", "snom"}
	for i,n in ipairs(firmwaretricks) do
		if string.match(user_agent, n) and posix.stat(root.."/"..n.."/"..basename) then
			local f = io.open(root.."/"..n.."/"..basename, "r")
			if f then
				log:write("Translating local file\n")
				io.stdout:write("Content-Type: \n\n")
				io.stdout:write((string.gsub(f:read("*a"), "%$SERV", server)))
				f:close()
				log:close()
				os.exit()
			end
		end
	end

	-- don't even bother for files that don't contain a MAC
	if mac == nil then 
		http_code(404)
		log:close()
		os.exit()
	end

        -- If it's a Polycom, 404 the MAC.cfg and MAC-license files and redirect the MAC-directory.xml, MAC-phone.cfg, and MAC-web.cfg files to blanks
	local f = string.match(basename, mac.."(.*)")
	if string.match(user_agent, "Polycom") and (f==".cfg" or f=="-license.cfg" or mac=="000000000000") then
		http_code(404)
		log:close()
		os.exit()
	elseif string.match(user_agent, "Polycom") and (f=="-directory.xml" or f=="-phone.cfg" or f=="-web.cfg") then
		http_code(302)
		log:close()
		os.exit()
        end

	log:write("Checking PROV Table for results\n")
	-- Load the ACF mvc
	local PATH = package.path
	package.path = "/usr/share/acf/www/cgi-bin/?.lua;" .. package.path
	require("mvc")
	package.path = PATH
	-- We'll use the cli controller, but change the view resolver to call the template
	local pathinfo = ENV.PATH_INFO
	FRAMEWORK=mvc:new()
	FRAMEWORK:read_config("acf")
	APP=FRAMEWORK:new("acf_cli")
	APP.view_resolver = function(self)
		return function (data)
			if not data.errtxt and data.value.values and data.value.values.value.device and data.value.values.value.device.template then
				local func = haserl.loadfile(data.value.values.value.device.template)
				func(data.value.values.value)
				log:write("Success\n")
			else
				http_code(404)
			end
		end
	end
	-- Set up the action and parameters
	ENV.PATH_INFO = "/provisioning/provisioning/getfile"
	APP.clientdata = {mac=mac, ip=ip_address, agent=user_agent}
	-- Dispatch the command
	APP:dispatch()
	APP:destroy()
	FRAMEWORK:destroy()

	ENV.PATH_INFO = pathinfo
elseif ( request_method == "PUT" ) then
	local data = io.stdin:read("*all")
	local success = true

	-- Protect against writing to arbitrary paths
	if not mac or mac == "" or string.match(path_info, "%.%.") then
		http_code(403)
		log:close()
		os.exit()
	end

        -- If it's a Polycom, do not pass the MAC-directory.xml file to ACF
	-- Don't bother for .log files
	local f = string.match(basename, mac.."(.*)")
	if not string.match(path_info, "%.log$") then
		log:write("Checking PROV Table for results\n")
		-- Load the ACF mvc
		local PATH = package.path
		package.path = "/usr/share/acf/www/cgi-bin/?.lua;" .. package.path
		require("mvc")
		package.path = PATH
		-- We'll use the cli controller, but change the view resolver to report HTTP code
		local pathinfo = ENV.PATH_INFO
		FRAMEWORK=mvc:new()
		FRAMEWORK:read_config("acf")
		APP=FRAMEWORK:new("acf_cli")
		APP.view_resolver = function(self)
			return function (output)
				if output.errtxt then
					log:write(output.errtxt.."\n")
					success = false
				else
					data = output.value
				end
			end
		end
		-- Set up the action and parameters
		ENV.PATH_INFO = "/provisioning/provisioning/putfile"
		APP.clientdata = {mac=mac, data=data}
		-- Dispatch the command
		APP:dispatch()
		APP:destroy()
		FRAMEWORK:destroy()

		ENV.PATH_INFO = pathinfo
	end
	if success then
		local path = root..path_info
		log:write("Writing to "..path.."\n")
		posix.mkdir(posix.dirname(path))
		local f = io.open(path, "w+")
		f:write(data)
		f:close()
		http_code(200)
	else
		http_code(400)
	end
end
log:close() 
%>