X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=plugins%2Fmod_http_files.lua;h=3b60249559c6e7e42bee94699d0f14ba122f7c4b;hb=ce3e9d066610d7e15e31263f59fa597eca079064;hp=2e9f418298ff244614312d2fafd553e2e2371559;hpb=fea2a20a1c12fe7415426658e55095fee94fe656;p=prosody.git diff --git a/plugins/mod_http_files.lua b/plugins/mod_http_files.lua index 2e9f4182..3b602495 100644 --- a/plugins/mod_http_files.lua +++ b/plugins/mod_http_files.lua @@ -49,6 +49,38 @@ if not mime_map then end end +local forbidden_chars_pattern = "[/%z]"; +if prosody.platform == "windows" then + forbidden_chars_pattern = "[/%z\001-\031\127\"*:<>?|]" +end + +local urldecode = require "util.http".urldecode; +function sanitize_path(path) + if not path then return end + local out = {}; + + local c = 0; + for component in path:gmatch("([^/]+)") do + component = urldecode(component); + if component:find(forbidden_chars_pattern) then + return nil; + elseif component == ".." then + if c <= 0 then + return nil; + end + out[c] = nil; + c = c - 1; + elseif component ~= "." then + c = c + 1; + out[c] = component; + end + end + if path:sub(-1,-1) == "/" then + out[c+1] = ""; + end + return "/"..table.concat(out, "/"); +end + local cache = setmetatable({}, { __mode = "kv" }); -- Let the garbage collector have it if it wants to. function serve(opts) @@ -60,9 +92,14 @@ function serve(opts) local directory_index = opts.directory_index; local function serve_file(event, path) local request, response = event.request, event.response; - local orig_path = request.path; - local full_path = base_path .. (path and "/"..path or ""); - local attr = stat((full_path:gsub('%'..path_sep..'+$',''))); + local sanitized_path = sanitize_path(path); + if path and not sanitized_path then + return 400; + end + path = sanitized_path; + local orig_path = sanitize_path(request.path); + local full_path = base_path .. (path or ""):gsub("/", path_sep); + local attr = stat(full_path:match("^.*[^\\/]")); -- Strip trailing path separator because Windows if not attr then return 404; end