# HG changeset patch # User Javier Torres # Date 1288474719 -7200 # Node ID cfcd4efb0fa444a3f7b5582d70a3bdf22446f387 # Parent 76f3310ec113aba78d63a2ff9df6ddde3d4b59ec mod_auth_dovecot: Remove asserts (use logger) and refactor socket code diff -r 76f3310ec113 -r cfcd4efb0fa4 mod_auth_dovecot/mod_auth_dovecot.lua --- a/mod_auth_dovecot/mod_auth_dovecot.lua Sat Oct 30 23:38:19 2010 +0200 +++ b/mod_auth_dovecot/mod_auth_dovecot.lua Sat Oct 30 23:38:39 2010 +0200 @@ -16,60 +16,121 @@ local prosody = _G.prosody; function new_default_provider(host) - local provider = { name = "dovecot" }; + local provider = { name = "dovecot", c = nil }; log("debug", "initializing dovecot authentication provider for host '%s'", host); - - function provider.test_password(username, password) - log("debug", "test password '%s' for user %s at host %s", password, username, module.host); + + -- The following connects to a new socket and send the handshake + function provider.connect(self) + -- Destroy old socket + if (provider.c ~= nil) then + provider.c:close(); + end - c = assert(socket.unix()); - assert(c:connect("/var/run/dovecot/auth-login")); -- FIXME: Hardcoded is bad + provider.c = socket.unix(); - local pid = pposix.getpid(); - + -- Create a connection to dovecot socket + local socket = "/var/run/dovecot/auth-login"; + local r, e = provider.c:connect(socket); + if (not r) then + log("warn", "error connecting to dovecot socket at '%s'. error was '%s'. check permissions", socket, e); + return false; + end + -- Send our handshake - -- FIXME: Oh no! There are asserts everywhere - assert(c:send("VERSION\t1\t1\n")); - assert(c:send("CPID\t" .. pid .. "\n")); - - -- Check their handshake + local pid = pposix.getpid(); + if not provider:send("VERSION\t1\t1\n") then + return false + end + if (not provider:send("CPID\t" .. pid .. "\n")) then + return false + end + + -- Parse Dovecot's handshake local done = false; while (not done) do - local l = assert(c:receive()); + local l = provider:receive(); + if (not l) then + return false; + end + parts = string.gmatch(l, "[^\t]+"); first = parts(); if (first == "VERSION") then - assert(parts() == "1"); - assert(parts() == "1"); + -- Version should be 1.1 + local v1 = parts(); + local v2 = parts(); + + if (not (v1 == "1" and v2 == "1")) then + log("warn", "server version is not 1.1. it is %s.%s", v1, v2); + return false; + end elseif (first == "MECH") then + -- Mechanisms should include PLAIN local ok = false; for p in parts do if p == "PLAIN" then ok = true; end end - assert(ok); + if (not ok) then + log("warn", "server doesn't support PLAIN mechanism. It supports '%s'", l); + return false; + end elseif (first == "DONE") then done = true; end end - + return true; + end + + function provider.send(self, data) + local r, e = provider.c:send(data); + if (not r) then + log("warn", "error sending '%s' to dovecot. error was '%s'", data, e); + return false; + end + return true; + end + + function provider.receive(self) + local r, e = provider.c:receive(); + if (not r) then + log("warn", "error receiving data from dovecot. error was '%s'", socket, e); + return false; + end + return r; + end + + function provider.test_password(username, password) + log("debug", "test password '%s' for user %s at host %s", password, username, module.host); + + if (not provider:connect()) then + return nil, "Auth failed. Dovecot communications error"; + end + -- Send auth data username = username .. "@" .. module.host; -- FIXME: this is actually a hack for my server local b64 = base64.encode(username .. "\0" .. username .. "\0" .. password); local id = "54321"; -- FIXME: probably can just be a fixed value if making one request per connection - assert(c:send("AUTH\t" .. id .. "\tPLAIN\tservice=XMPP\tresp=" .. b64 .. "\n")); - local l = assert(c:receive()); - assert(c:close()); + if (not provider:send("AUTH\t" .. id .. "\tPLAIN\tservice=XMPP\tresp=" .. b64 .. "\n")) then + return nil, "Auth failed. Dovecot communications error"; + end + + -- Get response + local l = provider:receive(); + if (not l) then + return nil, "Auth failed. Dovecot communications error"; + end local parts = string.gmatch(l, "[^\t]+"); - + + -- Check response if (parts() == "OK") then return true; else return nil, "Auth failed. Invalid username or password."; end end - + function provider.get_password(username) return nil, "Cannot get_password in dovecot backend."; end @@ -77,32 +138,32 @@ function provider.set_password(username, password) return nil, "Cannot set_password in dovecot backend."; end - + function provider.user_exists(username) - --TODO: Send an auth request. If it returns FAIL user= then user exists. - return nil, "user_exists not yet implemented in dovecot backend."; + --TODO: Send an auth request. If it returns FAIL user= then user exists. + return nil, "user_exists not yet implemented in dovecot backend."; end - + function provider.create_user(username, password) return nil, "Cannot create_user in dovecot backend."; end - + function provider.get_sasl_handler() local realm = module:get_option("sasl_realm") or module.host; local getpass_authentication_profile = { plain_test = function(username, password, realm) - local prepped_username = nodeprep(username); - if not prepped_username then - log("debug", "NODEprep failed on username: %s", username); - return "", nil; - end - return usermanager.test_password(prepped_username, realm, password), true; - end - }; - return new_sasl(realm, getpass_authentication_profile); - end - - return provider; + local prepped_username = nodeprep(username); + if not prepped_username then + log("debug", "NODEprep failed on username: %s", username); + return "", nil; + end + return usermanager.test_password(prepped_username, realm, password), true; + end + }; + return new_sasl(realm, getpass_authentication_profile); +end + +return provider; end module:add_item("auth-provider", new_default_provider(module.host));