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
|
#!/usr/bin/haserl --shell=lua --accept-none
<%
posix = 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 firmware URL, replacing $SERV with SERVER_NAME
local firmwaretricks = {"Linksys", "Cisco", "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()
-- If it's a Grandstream, 404 the cfgMAC without extension
elseif string.match(user_agent, "Grandstream") and (f=="") then
http_code(404)
log:close()
os.exit()
end
log:write("Checking PROV Table for results\n")
-- Load the ACF mvc
mvc = require("acf.mvc")
-- We'll change the view resolver to call the template
APP=mvc:new()
APP:read_config("acf")
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 parameters
local clientdata = {mac=mac, ip=ip_address, agent=user_agent}
-- Dispatch the command
APP:dispatch("/provisioning/", "provisioning", "getfile", clientdata)
APP:destroy()
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
mvc = require("acf.mvc")
-- We'll change the view resolver to report HTTP code
APP=mvc:new()
APP:read_config("acf")
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
local clientdata = {mac=mac, data=data}
-- Dispatch the command
APP:dispatch("/provisioning/", "provisioning", "putfile", clientdata)
APP:destroy()
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()
%>
|