#!/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("New Link") 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 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() %>