-- acf model for squid module (..., package.seeall) -- Load libraries require("modelfunctions") require("validator") require("format") require("fs") -- Set variables local squidconf = "/etc/squid/squid.conf" local squiddigestusers = "/etc/squid/users.list" local processname = "squid" local packagename = "squid" local baseurl = "/etc/squid/" local config, configcontent local validate_config = function(newconfig) local success = true success = modelfunctions.validatemulti(newconfig.value.authmethod) for i,val in ipairs(newconfig.value.httpports.value) do local before, after = string.match(val, "^([^:]+):([^:]+)$") if not (before and after) then after = val end if not validator.is_port(after) then newconfig.value.httpports.errtxt = "Invalid port" success = false break end end return success, newconfig end getstatus = function() return modelfunctions.getstatus(processname, packagename, "Squid status") end startstop_service = function(action) return modelfunctions.startstop_service(processname, action, {"Start", "Stop", "Restart", "Reload", "Rotate"}) end get_configfile = function() return modelfunctions.getfiledetails(squidconf) end update_configfile = function( filedetails ) return modelfunctions.setfiledetails(filedetails, {squidconf}) end read_digest_userlist = function() local retval = modelfunctions.getfiledetails(squiddigestusers) retval.value.filecontent.descr = "List of username:password(plaintext) entries, one per line." -- check to see if the file is being used configcontent = configcontent or fs.read_file(squidconf) or "" config = config or format.parse_linesandwords(configcontent) retval.value.status = cfe({ errtxt="Digest authentication not enabled", label="User list status" }) for i,line in ipairs(config) do if line[1] == "auth_param" and line[2] == "digest" and line[3] == "program" then if line[#line] == squiddigestusers then retval.value.status.value = "User list in use" retval.value.status.errtxt = nil else retval.value.status.errtxt = "Digest authentication not using this user list" end end end return retval end update_digest_userlist = function( userlistdetails ) -- FIXME - validate modelfunctions.setfiledetails(userlistdetails, {squiddigestusers}) return read_digest_userlist() end enable_digest_userlist = function() configcontent = configcontent or fs.read_file(squidconf) or "" local newline = "auth_param digest program /usr/sbin/digest_pw_auth "..squiddigestusers local lastauth, authline local lines = {} -- first loop to comment out / uncomment existing lines local linenum = 0 for line in string.gmatch(configcontent, "([^\n]*)\n?") do linenum = linenum + 1 if not authline and not string.match(line, "^[%s#]*$") then local first, second, third = string.match(line, "([^%s#]+)%s+(%S+)%s+(%S+)") if first == "auth_param" then lastauth = linenum if second == "digest" and third == "program" then authline = linenum line = string.gsub(line, "^[%s#]+", "") local fifth = string.match(line, "^%S+%s+%S+%s+%S+%s+%S+%s+(%S+)") line = string.gsub(line, fifth, squiddigestusers) end end end lines[#lines+1] = line end if not authline then if not lastauth then lines[#lines+1] = newline else table.insert(lines, lastauth+1, newline) end end fs.write_file(squidconf, string.gsub(table.concat(lines, "\n"), "\n+$", "")) config = nil configcontent = nil return cfe({ value="Successfully enabled user list", label="Enable digest user list result" }) end --[[ get_saccess = function() local config = {} config.s_ip = get_file_contents( "/etc/squid/anoniplist" ) config.s_browser = get_file_contents( "/etc/squid/anonbrowserlist" ) config.s_domain = get_file_contents( "/etc/squid/anondomainlist" ) return config end update_saccess = function( config ) write_file_contents( "/etc/squid/anoniplist", config.s_ip ) write_file_contents( "/etc/squid/anonbrowserlist", config.s_browser ) write_file_contents( "/etc/squid/anondomainlist", config.s_domain ) return end write_file_contents = function( name, contents ) local ptr = io.open( name, "wb+" ) if ptr ~= nil then ptr:write( format.dostounix( contents ) ) ptr:close() end return end get_file_contents = function( name ) local retval = "" local ptr = io.open( name ) if ptr ~= nil then retval = ptr:read( "*a" ) ptr:close() if retval == nil then retval = "" end end return retval end --]] read_config = function() local retval = { httpports = { type="list", value={}, label="HTTP Ports", descr="List of port, IP:port, or hostname:port entries that Squid will listen on" }, accesslog = { type="boolean", value=false, label="Log Access" }, diskcache = { type="boolean", value=false, label="Disk Cache" }, authmethod = { type="multi", value={}, label="Authentication Methods", option={"negotiate", "ntlm", "digest", "basic"} }, } configcontent = configcontent or fs.read_file(squidconf) or "" config = config or format.parse_linesandwords(configcontent) if config then for i,line in ipairs(config) do if line[1] == "http_port" then table.insert(retval.httpports.value, line[2]) elseif line[1] == "access_log" then retval.accesslog.value = (line[2] ~= "none") elseif line[1] == "cache_dir" then retval.diskcache.value = (line[2] ~= "null") elseif line[1] == "auth_param" and line[3] == "program" then table.insert(retval.authmethod.value, line[2]) end end end return cfe({ type="group", value=retval, label="Squid Config" }) end update_config = function(newconfig) local success, newconfig = validate_config(newconfig) if success then configcontent = configcontent or fs.read_file(squidconf) or "" local lastport, lastlog, lastcache, lastauth local didports = {} local didlog, didcache local didauths = {} local reverseports = {} for i,port in ipairs(newconfig.value.httpports.value) do reverseports[port] = i end local reverseauths = {} for i,auth in ipairs(newconfig.value.authmethod.value) do reverseauths[auth] = i end local lines = {} -- first loop to comment out / uncomment existing lines local linenum = 0 for line in string.gmatch(configcontent, "([^\n]*)\n?") do linenum = linenum + 1 if not string.match(line, "^[%s#]*$") then local first, second = string.match(line, "([^%s#]+)%s+(%S+)") if first == "http_port" then lastport = linenum line = string.gsub(line, "^[%s#]+", "") if not reverseports[second] then line = "# "..line else didports[second] = true end elseif first == "access_log" then lastlog = linenum line = string.gsub(line, "^[%s#]+", "") if (newconfig.value.accesslog.value and second == "none") or (not newconfig.value.accesslog.value and second ~= "none") then line = "# "..line else didlog = true end elseif first == "cache_dir" then lastcache = linenum line = string.gsub(line, "^[%s#]+", "") if (newconfig.value.diskcache.value and second == "null") or (not newconfig.value.diskcache.value and second ~= "null") then line = "# "..line else didcache = true end elseif first == "auth_param" then lastauth = linenum if string.match(line, "[^%s#]+%s+%S+%s+(%S+)") == "program" then line = string.gsub(line, "^[%s#]+", "") if not reverseauths[second] then line = "# "..line else didauths[second] = true end end end end lines[#lines+1] = line end -- We've gone through the file, now check to see if everything is done local tobedone = {} local line for i,port in ipairs(newconfig.value.httpports.value) do if not didports[port] then line = "http_port "..port if lastport then table.insert(tobedone, {linenum=lastport+1, line=line}) else table.insert(lines, line) end end end if not didlog then if newconfig.value.accesslog.value then line = "access_log /var/log/squid/access.log" else line = "access_log none" end if lastlog then table.insert(tobedone, {linenum=lastlog+1, line=line}) else table.insert(lines, line) end end if not didcache then if newconfig.value.diskcache.value then line = "cache_dir diskd /var/cache/squid 400 16 256" else line = "cache_dir null" end if lastcache then table.insert(tobedone, {linenum=lastcache+1, line=line}) else table.insert(lines, line) end end for i,auth in ipairs(newconfig.value.authmethod.value) do if not didauths[auth] then line = "auth_param "..auth.." program " -- These entries have not been tested and probably don't work if auth == "basic" then line = line .. "/usr/libexec/ncsa_auth /usr/etc/passwd" elseif auth == "digest" then line = line .. "/usr/sbin/digest_pw_auth /etc/squid/users.list" elseif auth == "ntlm" then line = line .. "/usr/sbin/wb_ntlmauth" elseif auth == "negotiate" then line = line .. "/usr/sbin/ntlm_auth --helper-protocol=gss-spnego" end if lastauth then table.insert(tobedone, {linenum=lastauth+1, line=line}) else table.insert(lines, line) end end end if #tobedone > 0 then table.sort(tobedone, function(a,b) return (a.linenum > b.linenum) end) for i,entry in ipairs(tobedone) do table.insert(lines, entry.linenum, entry.line) end end -- finally, write the file fs.write_file(squidconf, string.gsub(table.concat(lines, "\n"), "\n+$", "")) config = nil configcontent = nil else newconfig.errtxt = "Failed to set config" end return newconfig end --[[ read_acls = function() local acls = cfe({ type="structure", value={}, label="Squid Access Lists" }) configcontent = configcontent or fs.read_file(squidconf) or "" config = config or format.parse_linesandwords(configcontent) for i,line in ipairs(config) do if line[1] == "acl" then table.insert(acls.value, {line=line.line, linenum=line.linenum}) end end return acls end read_acl = function(linenum) local line = cfe({ label="Squid Access List" }) local linecfe = cfe({ value=linenum, label="Line number" }) configcontent = configcontent or fs.read_file(squidconf) or "" line.value = format.getline(configcontent, linenum) or "" return cfe({ type="group", value={line=line, linenum=linecfe}, label="Squid Access List" }) end update_acl = function(acl) -- local success, acl = validate_acl(acl) configcontent = configcontent or fs.read_file(squidconf) or "" configcontent = format.replaceline(configcontent, acl.value.linenum.value, acl.value.line.value) fs.write_file(squidconf, string.gsub(configcontent, "\n+$", "")) config = nil configcontent = nil return acl end create_acl = function(acl) -- local success, acl = validate_acl(acl) configcontent = configcontent or fs.read_file(squidconf) or "" config = config or format.parse_linesandwords(configcontent) local linenum = -1 for i=#config,1,-1 do if config[i][1] == "acl" then linenum = config[i].linenum configcontent = format.insertline(configcontent, linenum, acl.value.line.value) break end end if linenum == -1 then configcontent = string.gsub(configcontent, "\n?$", "\n") .. acl.value.line.value end fs.write_file(squidconf, string.gsub(configcontent, "\n+$", "")) config = nil configcontent = nil return acl end delete_acl = function(linenum) configcontent = configcontent or fs.read_file(squidconf) or "" configcontent = format.replaceline(configcontent, linenum) fs.write_file(squidconf, string.gsub(configcontent, "\n+$", "")) config = nil configcontent = nil return acl end --]] function listfiles() local retval = cfe({ type="list", value={}, label="Squid Files" }) if not fs.is_dir(baseurl) then fs.create_directory(baseurl) end for file in posix.files(baseurl) do file = baseurl..file if fs.is_file(file) and file ~= squidconf and file ~= squiddigestusers then table.insert(retval.value, file) end end table.sort(retval.value) return retval end function getnewfile() local filename = cfe({ label="File Name", descr="Must be in "..baseurl }) return cfe({ type="group", value={filename=filename}, label="Squid File" }) end function createfile(filedetails) local success = true local path = string.match(filedetails.value.filename.value, "^%s*(.*%S)%s*$") or "" if not string.find(path, "/") then path = baseurl..path end if not validator.is_valid_filename(path, baseurl) then success = false filedetails.value.filename.errtxt = "Invalid filename" else if not fs.is_dir(baseurl) then fs.create_directory(baseurl) end if posix.stat(path) then success = false filedetails.value.filename.errtxt = "Filename already exists" end end if success then fs.create_file(path) else filedetails.errtxt = "Failed to Create File" end return filedetails end function readfile(filename) return modelfunctions.getfiledetails(filename, listfiles().value) end function updatefile(filedetails) return modelfunctions.setfiledetails(filedetails, listfiles().value) end function deletefile(filename) local retval = cfe({ label="Delete Squid File result", errtxt = "Failed to delete Squid File - invalid filename" }) for i,file in ipairs(listfiles().value) do if filename == file then retval.value = "Deleted Squid File" retval.errtxt = nil os.remove(filename) break end end return retval end