luci-base: log login attempts
[project/luci.git] / modules / luci-base / luasrc / dispatcher.lua
index 2b5f7b4..16b3254 100644 (file)
@@ -174,7 +174,8 @@ local function session_retrieve(sid, allowed_users)
        if type(sdat) == "table" and
           type(sdat.values) == "table" and
           type(sdat.values.token) == "string" and
-          util.contains(allowed_users, sdat.values.username)
+          (not allowed_users or
+           util.contains(allowed_users, sdat.values.username))
        then
                return sid, sdat.values
        end
@@ -182,25 +183,36 @@ local function session_retrieve(sid, allowed_users)
        return nil, nil
 end
 
-local function session_setup(user, pass)
-       local login = util.ubus("session", "login", {
-               username = user,
-               password = pass,
-               timeout  = tonumber(luci.config.sauth.sessiontime)
-       })
-
-       if type(login) == "table" and
-          type(login.ubus_rpc_session) == "string"
-       then
-               util.ubus("session", "set", {
-                       ubus_rpc_session = login.ubus_rpc_session,
-                       values = { token = sys.uniqueid(16) }
+local function session_setup(user, pass, allowed_users)
+       if util.contains(allowed_users, user) then
+               local login = util.ubus("session", "login", {
+                       username = user,
+                       password = pass,
+                       timeout  = tonumber(luci.config.sauth.sessiontime)
                })
 
-               return login.ubus_rpc_session
+               local rp = context.requestpath
+                       and table.concat(context.requestpath, "/") or ""
+
+               if type(login) == "table" and
+                  type(login.ubus_rpc_session) == "string"
+               then
+                       util.ubus("session", "set", {
+                               ubus_rpc_session = login.ubus_rpc_session,
+                               values = { token = sys.uniqueid(16) }
+                       })
+
+                       io.stderr:write("luci: accepted login on /%s for %s from %s\n"
+                               %{ rp, user, http.getenv("REMOTE_ADDR") or "?" })
+
+                       return session_retrieve(login.ubus_rpc_session)
+               end
+
+               io.stderr:write("luci: failed login on /%s for %s from %s\n"
+                       %{ rp, user, http.getenv("REMOTE_ADDR") or "?" })
        end
 
-       return nil
+       return nil, nil
 end
 
 function dispatch(request)
@@ -216,10 +228,19 @@ function dispatch(request)
        local lang = conf.main.lang or "auto"
        if lang == "auto" then
                local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or ""
-               for lpat in aclang:gmatch("[%w-]+") do
-                       lpat = lpat and lpat:gsub("-", "_")
-                       if conf.languages[lpat] then
-                               lang = lpat
+               for aclang in aclang:gmatch("[%w_-]+") do
+                       local country, culture = aclang:match("^([a-z][a-z])[_-]([a-zA-Z][a-zA-Z])$")
+                       if country and culture then
+                               local cc = "%s_%s" %{ country, culture:lower() }
+                               if conf.languages[cc] then
+                                       lang = cc
+                                       break
+                               elseif conf.languages[country] then
+                                       lang = country
+                                       break
+                               end
+                       elseif conf.languages[aclang] then
+                               lang = aclang
                                break
                        end
                end
@@ -346,10 +367,15 @@ function dispatch(request)
                "https://github.com/openwrt/luci/issues"
        )
 
-       if track.sysauth then
+       if track.sysauth and not ctx.authsession then
                local authen = track.sysauth_authenticator
                local _, sid, sdat, default_user, allowed_users
 
+               if type(authen) == "string" and authen ~= "htmlauth" then
+                       error500("Unsupported authenticator %q configured" % authen)
+                       return
+               end
+
                if type(track.sysauth) == "table" then
                        default_user, allowed_users = nil, track.sysauth
                else
@@ -358,44 +384,39 @@ function dispatch(request)
 
                if type(authen) == "function" then
                        _, sid = authen(sys.user.checkpasswd, allowed_users)
-               elseif authen == "htmlauth" then
-                       sid, sdat = session_retrieve(http.getcookie("sysauth"), allowed_users)
+               else
+                       sid = http.getcookie("sysauth")
+               end
 
-                       if not sid then
-                               local user = http.getenv("HTTP_AUTH_USER")
-                               local pass = http.getenv("HTTP_AUTH_PASS")
+               sid, sdat = session_retrieve(sid, allowed_users)
 
-                               if user == nil and pass == nil then
-                                       user = http.formvalue("luci_username")
-                                       pass = http.formvalue("luci_password")
-                               end
+               if not (sid and sdat) and authen == "htmlauth" then
+                       local user = http.getenv("HTTP_AUTH_USER")
+                       local pass = http.getenv("HTTP_AUTH_PASS")
 
-                               if util.contains(allowed_users, user) then
-                                       sid, sdat = session_setup(user, pass), nil
-                               end
+                       if user == nil and pass == nil then
+                               user = http.formvalue("luci_username")
+                               pass = http.formvalue("luci_password")
+                       end
 
-                               if not sid then
-                                       require("luci.i18n")
-                                       require("luci.template")
-                                       context.path = {}
-                                       http.status(403, "Forbidden")
-                                       luci.template.render(track.sysauth_template or "sysauth", {
-                                               duser = default_user,
-                                               fuser = user
-                                       })
-                                       return
-                               end
+                       sid, sdat = session_setup(user, pass, allowed_users)
 
-                               http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() })
-                               http.redirect(build_url(unpack(ctx.requestpath)))
+                       if not sid then
+                               local tmpl = require "luci.template"
+
+                               context.path = {}
+
+                               http.status(403, "Forbidden")
+                               tmpl.render(track.sysauth_template or "sysauth", {
+                                       duser = default_user,
+                                       fuser = user
+                               })
+
+                               return
                        end
-               else
-                       error500("Unsupported authenticator configured")
-                       return
-               end
 
-               if not sdat then
-                       sid, sdat = session_retrieve(sid, allowed_users)
+                       http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() })
+                       http.redirect(build_url(unpack(ctx.requestpath)))
                end
 
                if not sid or not sdat then