X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;ds=sidebyside;f=modules%2Fluci-base%2Fluasrc%2Fdispatcher.lua;h=0bd19456f2d583d1b7846bde3df6d1c01d1862a2;hb=4f127c32544edabd420dbda114db50168a12ccfb;hp=5d9d1b0b1a5eaa9e7682f1fe51dda057ae768e88;hpb=49a2cb5ad11ccc0225fd3fa1de4b85a0618bbb99;p=project%2Fluci.git diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index 5d9d1b0b1..0bd19456f 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -27,14 +27,6 @@ function build_url(...) local path = {...} local url = { http.getenv("SCRIPT_NAME") or "" } - local k, v - for k, v in pairs(context.urltoken) do - url[#url+1] = "/;" - url[#url+1] = http.urlencode(k) - url[#url+1] = "=" - url[#url+1] = http.urlencode(v) - end - local p for _, p in ipairs(path) do if p:match("^[a-zA-Z0-9_%-%.%%/,;]+$") then @@ -43,6 +35,10 @@ function build_url(...) end end + if #path == 0 then + url[#url+1] = "/" + end + return table.concat(url, "") end @@ -105,7 +101,7 @@ function error500(message) return false end -function authenticator.htmlauth(validator, accs, default) +function authenticator.htmlauth(validator, accs, default, template) local user = http.formvalue("luci_username") local pass = http.formvalue("luci_password") @@ -113,24 +109,11 @@ function authenticator.htmlauth(validator, accs, default) return user end - if context.urltoken.stok then - context.urltoken.stok = nil - - local cookie = 'sysauth=%s; expires=%s; path=%s/' %{ - http.getcookie('sysauth') or 'x', - 'Thu, 01 Jan 1970 01:00:00 GMT', - build_url() - } - - http.header("Set-Cookie", cookie) - http.redirect(build_url()) - else - require("luci.i18n") - require("luci.template") - context.path = {} - http.status(403, "Forbidden") - luci.template.render("sysauth", {duser=default, fuser=user}) - end + require("luci.i18n") + require("luci.template") + context.path = {} + http.status(403, "Forbidden") + luci.template.render(template or "sysauth", {duser=default, fuser=user}) return false @@ -141,7 +124,6 @@ function httpdispatch(request, prefix) local r = {} context.request = r - context.urltoken = {} local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true) @@ -151,18 +133,8 @@ function httpdispatch(request, prefix) end end - local tokensok = true for node in pathinfo:gmatch("[^/]+") do - local tkey, tval - if tokensok then - tkey, tval = node:match(";(%w+)=([a-fA-F0-9]*)") - end - if tkey then - context.urltoken[tkey] = tval - else - tokensok = false - r[#r+1] = node - end + r[#r+1] = node end local stat, err = util.coxpcall(function() @@ -174,6 +146,48 @@ function httpdispatch(request, prefix) --context._disable_memtrace() end +local function require_post_security(target) + if type(target) == "table" then + if type(target.post) == "table" then + local param_name, required_val, request_val + + for param_name, required_val in pairs(target.post) do + request_val = http.formvalue(param_name) + + if (type(required_val) == "string" and + request_val ~= required_val) or + (required_val == true and + (request_val == nil or request_val == "")) + then + return false + end + end + + return true + end + + return (target.post == true) + end + + return false +end + +function test_post_security() + if http.getenv("REQUEST_METHOD") ~= "POST" then + http.status(405, "Method Not Allowed") + http.header("Allow", "POST") + return false + end + + if http.formvalue("token") ~= context.authtoken then + http.status(403, "Forbidden") + luci.template.render("csrftoken") + return false + end + + return true +end + function dispatch(request) --context._disable_memtrace = require "luci.debug".trap_memtrace("l") local ctx = context @@ -183,6 +197,7 @@ function dispatch(request) assert(conf.main, "/etc/config/luci seems to be corrupt, unable to find section 'main'") + local i18n = require "luci.i18n" local lang = conf.main.lang or "auto" if lang == "auto" then local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or "" @@ -194,7 +209,10 @@ function dispatch(request) end end end - require "luci.i18n".setlanguage(lang) + if lang == "auto" then + lang = i18n.default + end + i18n.setlanguage(lang) local c = ctx.tree local stat @@ -207,7 +225,6 @@ function dispatch(request) ctx.args = args ctx.requestargs = ctx.requestargs or args local n - local token = ctx.urltoken local preq = {} local freq = {} @@ -260,6 +277,13 @@ function dispatch(request) if cond then local env = getfenv(3) local scope = (type(env.self) == "table") and env.self + if type(val) == "table" then + if not next(val) then + return '' + else + val = util.serialize_json(val) + end + end return string.format( ' %s="%s"', tostring(key), util.pcdata(tostring( val @@ -285,13 +309,14 @@ function dispatch(request) resource = luci.config.main.resourcebase; ifattr = function(...) return _ifattr(...) end; attr = function(...) return _ifattr(true, ...) end; - token = ctx.urltoken.stok; url = build_url; }, {__index=function(table, key) if key == "controller" then return build_url() elseif key == "REQUEST_URI" then return build_url(unpack(ctx.requestpath)) + elseif key == "token" then + return ctx.authtoken else return rawget(table, key) or _G[key] end @@ -303,7 +328,7 @@ function dispatch(request) "Access Violation\nThe page at '" .. table.concat(request, "/") .. "/' " .. "has no parent node so the access to this location has been denied.\n" .. "This is a software bug, please report this message at " .. - "http://luci.subsignal.org/trac/newticket" + "https://github.com/openwrt/luci/issues" ) if track.sysauth then @@ -314,20 +339,17 @@ function dispatch(request) local def = (type(track.sysauth) == "string") and track.sysauth local accs = def and {track.sysauth} or track.sysauth local sess = ctx.authsession - local verifytoken = false if not sess then sess = http.getcookie("sysauth") sess = sess and sess:match("^[a-f0-9]*$") - verifytoken = true end local sdat = (util.ubus("session", "get", { ubus_rpc_session = sess }) or { }).values - local user + local user, token if sdat then - if not verifytoken or ctx.urltoken.stok == sdat.token then - user = sdat.user - end + user = sdat.user + token = sdat.token else local eu = http.getenv("HTTP_AUTH_USER") local ep = http.getenv("HTTP_AUTH_PASS") @@ -338,7 +360,7 @@ function dispatch(request) if not util.contains(accs, user) then if authen then - local user, sess = authen(sys.user.checkpasswd, accs, def) + local user, sess = authen(sys.user.checkpasswd, accs, def, track.sysauth_template) local token if not user or not util.contains(accs, user) then return @@ -360,12 +382,10 @@ function dispatch(request) end if sess and token then - http.header("Set-Cookie", 'sysauth=%s; path=%s/' %{ - sess, build_url() - }) + http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sess, build_url() }) - ctx.urltoken.stok = token ctx.authsession = sess + ctx.authtoken = token ctx.authuser = user http.redirect(build_url(unpack(ctx.requestpath))) @@ -377,20 +397,13 @@ function dispatch(request) end else ctx.authsession = sess + ctx.authtoken = token ctx.authuser = user end end - if c and type(c.target) == "table" and c.target.post == true then - if http.getenv("REQUEST_METHOD") ~= "POST" then - http.status(405, "Method Not Allowed") - http.header("Allow", "POST") - return - end - - if http.formvalue("token") ~= ctx.urltoken.stok then - http.status(403, "Forbidden") - luci.template.render("csrftoken") + if c and require_post_security(c.target) then + if not test_post_security(c) then return end end @@ -400,9 +413,6 @@ function dispatch(request) end if track.setuser then - -- trigger ubus connection before dropping root privs - util.ubus() - sys.process.setuser(track.setuser) end @@ -720,16 +730,20 @@ function call(name, ...) return {type = "call", argv = {...}, name = name, target = _call} end -function post(name, ...) +function post_on(params, name, ...) return { type = "call", - post = true, + post = params, argv = { ... }, name = name, target = _call } end +function post(...) + return post_on(true, ...) +end + local _template = function(self, ...) require "luci.template".render(self.view) @@ -744,15 +758,6 @@ local function _cbi(self, ...) local cbi = require "luci.cbi" local tpl = require "luci.template" local http = require "luci.http" - local disp = require "luci.dispatcher" - - if http.formvalue("cbi.submit") == "1" and - http.formvalue("token") ~= disp.context.urltoken.stok - then - http.status(403, "Forbidden") - luci.template.render("csrftoken") - return - end local config = self.config or {} local maps = cbi.load(self.model, ...) @@ -850,7 +855,13 @@ local function _cbi(self, ...) end function cbi(model, config) - return {type = "cbi", config = config, model = model, target = _cbi} + return { + type = "cbi", + post = { ["cbi.submit"] = "1" }, + config = config, + model = model, + target = _cbi + } end @@ -870,15 +881,6 @@ local function _form(self, ...) local cbi = require "luci.cbi" local tpl = require "luci.template" local http = require "luci.http" - local disp = require "luci.dispatcher" - - if http.formvalue("cbi.submit") == "1" and - http.formvalue("token") ~= disp.context.urltoken.stok - then - http.status(403, "Forbidden") - luci.template.render("csrftoken") - return - end local maps = luci.cbi.load(self.model, ...) local state = nil @@ -899,7 +901,12 @@ local function _form(self, ...) end function form(model) - return {type = "cbi", model = model, target = _form} + return { + type = "cbi", + post = { ["cbi.submit"] = "1" }, + model = model, + target = _form + } end translate = i18n.translate