aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/configmanager.lua33
-rw-r--r--core/eventmanager.lua16
-rw-r--r--core/hostmanager.lua6
-rw-r--r--core/modulemanager.lua10
-rw-r--r--core/usermanager.lua131
-rw-r--r--net/server_event.lua51
-rw-r--r--net/server_select.lua44
-rw-r--r--plugins/mod_console.lua124
-rw-r--r--plugins/mod_proxy65.lua41
-rwxr-xr-xprosody39
-rw-r--r--prosody.cfg.lua.dist233
-rw-r--r--util/sasl.lua21
-rw-r--r--util/sasl/anonymous.lua12
-rw-r--r--util/sasl/digest-md5.lua17
-rw-r--r--util/sasl/plain.lua28
-rw-r--r--util/sasl/scram.lua144
16 files changed, 565 insertions, 385 deletions
diff --git a/core/configmanager.lua b/core/configmanager.lua
index 54fb0a9a..9b03e1c7 100644
--- a/core/configmanager.lua
+++ b/core/configmanager.lua
@@ -30,10 +30,11 @@ local host_mt = { __index = global_config };
-- When key not found in section, check key in global's section
function section_mt(section_name)
return { __index = function (t, k)
- local section = rawget(global_config, section_name);
- if not section then return nil; end
- return section[k];
- end };
+ local section = rawget(global_config, section_name);
+ if not section then return nil; end
+ return section[k];
+ end
+ };
end
function getconfig()
@@ -112,16 +113,20 @@ do
function parsers.lua.load(data, filename)
local env;
-- The ' = true' are needed so as not to set off __newindex when we assign the functions below
- env = setmetatable({ Host = true, host = true, VirtualHost = true, Component = true, component = true,
- Include = true, include = true, RunScript = dofile }, { __index = function (t, k)
- return rawget(_G, k) or
- function (settings_table)
- config[__currenthost or "*"][k] = settings_table;
- end;
- end,
- __newindex = function (t, k, v)
- set(env.__currenthost or "*", "core", k, v);
- end});
+ env = setmetatable({
+ Host = true, host = true, VirtualHost = true,
+ Component = true, component = true,
+ Include = true, include = true, RunScript = dofile }, {
+ __index = function (t, k)
+ return rawget(_G, k) or
+ function (settings_table)
+ config[__currenthost or "*"][k] = settings_table;
+ end;
+ end,
+ __newindex = function (t, k, v)
+ set(env.__currenthost or "*", "core", k, v);
+ end
+ });
rawset(env, "__currenthost", "*") -- Default is global
function env.VirtualHost(name)
diff --git a/core/eventmanager.lua b/core/eventmanager.lua
index 0e766c30..1f69c8e1 100644
--- a/core/eventmanager.lua
+++ b/core/eventmanager.lua
@@ -10,24 +10,18 @@
local t_insert = table.insert;
local ipairs = ipairs;
+local events = _G.prosody.events;
+
module "eventmanager"
local event_handlers = {};
function add_event_hook(name, handler)
- if not event_handlers[name] then
- event_handlers[name] = {};
- end
- t_insert(event_handlers[name] , handler);
+ return events.add_handler(name, handler);
end
function fire_event(name, ...)
- local event_handlers = event_handlers[name];
- if event_handlers then
- for name, handler in ipairs(event_handlers) do
- handler(...);
- end
- end
+ return events.fire_event(name, ...);
end
-return _M; \ No newline at end of file
+return _M;
diff --git a/core/hostmanager.lua b/core/hostmanager.lua
index eb880449..c8928b27 100644
--- a/core/hostmanager.lua
+++ b/core/hostmanager.lua
@@ -42,7 +42,7 @@ local function load_enabled_hosts(config)
end
if not activated_any_host then
- log("error", "No hosts defined in the config file. This may cause unexpected behaviour as no modules will be loaded.");
+ log("error", "No active VirtualHost entries in the config file. This may cause unexpected behaviour as no modules will be loaded.");
end
eventmanager.fire_event("hosts-activated", defined_hosts);
@@ -60,8 +60,8 @@ function activate(host, host_config)
dialback_secret = configmanager.get(host, "core", "dialback_secret") or uuid_gen();
};
for option_name in pairs(host_config.core) do
- if option_name:match("_ports$") then
- log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in global Host \"*\" instead", host, option_name);
+ if option_name:match("_ports$") or option_name:match("_interface$") then
+ log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in the server-wide section instead", host, option_name);
end
end
diff --git a/core/modulemanager.lua b/core/modulemanager.lua
index 5e9eaedd..8e62aecb 100644
--- a/core/modulemanager.lua
+++ b/core/modulemanager.lua
@@ -19,7 +19,7 @@ local pluginloader = require "util.pluginloader";
local hosts = hosts;
local prosody = prosody;
-local loadfile, pcall = loadfile, pcall;
+local loadfile, pcall, xpcall = loadfile, pcall, xpcall;
local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv;
local pairs, ipairs = pairs, ipairs;
local t_insert, t_concat = table.insert, table.concat;
@@ -29,6 +29,14 @@ local rawget = rawget;
local error = error;
local tostring, tonumber = tostring, tonumber;
+local debug_traceback = debug.traceback;
+local unpack, select = unpack, select;
+pcall = function(f, ...)
+ local n = select("#", ...);
+ local params = {...};
+ return xpcall(function() f(unpack(params, 1, n)) end, function(e) return tostring(e).."\n"..debug_traceback(); end);
+end
+
local array, set = require "util.array", require "util.set";
local autoload_modules = {"presence", "message", "iq"};
diff --git a/core/usermanager.lua b/core/usermanager.lua
index 8d7270c2..1ee4736e 100644
--- a/core/usermanager.lua
+++ b/core/usermanager.lua
@@ -16,82 +16,117 @@ local jid_bare = require "util.jid".bare;
local config = require "core.configmanager";
local hosts = hosts;
+local prosody = _G.prosody;
+
module "usermanager"
-local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
+local new_default_provider;
-function validate_credentials(host, username, password, method)
- log("debug", "User '%s' is being validated", username);
- if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
- local credentials = datamanager.load(username, host, "accounts") or {};
+prosody.events.add_handler("host-activated", function (host)
+ local host_session = hosts[host];
+ host_session.events.add_handler("item-added/auth-provider", function (provider)
+ if config.get(host, "core", "authentication") == provider.name then
+ host_session.users = provider;
+ end
+ end);
+ host_session.events.add_handler("item-removed/auth-provider", function (provider)
+ if host_session.users == provider then
+ host_session.users = new_default_provider(host);
+ end
+ end);
+ host_session.users = new_default_provider(host); -- Start with the default usermanager provider
+end);
+
+local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
- if method == nil then method = "PLAIN"; end
- if method == "PLAIN" and credentials.password then -- PLAIN, do directly
+function new_default_provider(host)
+ local provider = { name = "default" };
+
+ function provider.test_password(username, password)
+ if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
+ local credentials = datamanager.load(username, host, "accounts") or {};
+
if password == credentials.password then
return true;
else
return nil, "Auth failed. Invalid username or password.";
end
- end
- -- must do md5
- -- make credentials md5
- local pwd = credentials.password;
- if not pwd then pwd = credentials.md5; else pwd = hashes.md5(pwd, true); end
- -- make password md5
- if method == "PLAIN" then
- password = hashes.md5(password or "", true);
- elseif method ~= "DIGEST-MD5" then
- return nil, "Unsupported auth method";
end
- -- compare
- if password == pwd then
- return true;
- else
- return nil, "Auth failed. Invalid username or password.";
+
+ function provider.get_password(username)
+ if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+ return (datamanager.load(username, host, "accounts") or {}).password;
end
+
+ function provider.set_password(username, password)
+ if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+ local account = datamanager.load(username, host, "accounts");
+ if account then
+ account.password = password;
+ return datamanager.store(username, host, "accounts", account);
+ end
+ return nil, "Account not available.";
+ end
+
+ function provider.user_exists(username)
+ if is_cyrus(host) then return true; end
+ return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
+ end
+
+ function provider.create_user(username, password)
+ if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
+ return datamanager.store(username, host, "accounts", {password = password});
+ end
+
+ function provider.get_supported_methods()
+ return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config
+ end
+
+ function provider.is_admin(jid)
+ host = host or "*";
+ local admins = config.get(host, "core", "admins");
+ if host ~= "*" and admins == config.get("*", "core", "admins") then
+ return nil;
+ end
+ if type(admins) == "table" then
+ jid = jid_bare(jid);
+ for _,admin in ipairs(admins) do
+ if admin == jid then return true; end
+ end
+ elseif admins then
+ log("warn", "Option 'admins' for host '%s' is not a table", host);
+ end
+ return nil;
+ end
+ return provider;
+end
+
+function validate_credentials(host, username, password, method)
+ return hosts[host].users.test_password(username, password);
end
function get_password(username, host)
- if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
- return (datamanager.load(username, host, "accounts") or {}).password
+ return hosts[host].users.get_password(username);
end
+
function set_password(username, host, password)
- if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
- local account = datamanager.load(username, host, "accounts");
- if account then
- account.password = password;
- return datamanager.store(username, host, "accounts", account);
- end
- return nil, "Account not available.";
+ return hosts[host].users.set_password(username, password);
end
function user_exists(username, host)
- if is_cyrus(host) then return true; end
- return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
+ return hosts[host].users.user_exists(username);
end
function create_user(username, password, host)
- if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
- return datamanager.store(username, host, "accounts", {password = password});
+ return hosts[host].users.create_user(username, password);
end
function get_supported_methods(host)
- return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config
+ return hosts[host].users.get_supported_methods();
end
function is_admin(jid, host)
- host = host or "*";
- local admins = config.get(host, "core", "admins");
- if host ~= "*" and admins == config.get("*", "core", "admins") then
- return nil;
- end
- if type(admins) == "table" then
- jid = jid_bare(jid);
- for _,admin in ipairs(admins) do
- if admin == jid then return true; end
- end
- elseif admins then log("warn", "Option 'admins' for host '%s' is not a table", host); end
- return nil;
+ return hosts[host].users.is_admin(jid);
end
return _M;
diff --git a/net/server_event.lua b/net/server_event.lua
index be9e7f0a..43e70a0f 100644
--- a/net/server_event.lua
+++ b/net/server_event.lua
@@ -161,7 +161,7 @@ do
self:_lock( false, false, false )
--vdebug( "start listening on client socket with id:", self.id )
self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ); -- register callback
- (self.onconnect or self.onincoming)(self)
+ self:onconnect()
self.eventsession = nil
return -1
end
@@ -282,8 +282,21 @@ do
return nointerface, noreading, nowriting
end
+ --TODO: Deprecate
function interface_mt:lock_read(switch)
- return self:_lock(self.nointerface, switch, self.nowriting);
+ if switch then
+ return self:pause();
+ else
+ return self:resume();
+ end
+ end
+
+ function interface_mt:pause()
+ return self:_lock(self.nointerface, true, self.nowriting);
+ end
+
+ function interface_mt:resume()
+ return self:_lock(self.nointerface, false, self.nowriting);
end
function interface_mt:counter(c)
@@ -389,6 +402,13 @@ do
self.starttls = false; -- prevent starttls()
end
end
+
+ function interface_mt:set_mode(pattern)
+ if pattern then
+ self._pattern = pattern;
+ end
+ return self._pattern;
+ end
function interface_mt:set_send(new_send)
-- No-op, we always use the underlying connection's send
@@ -437,6 +457,7 @@ do
-- Stub handlers
function interface_mt:onconnect()
+ return self:onincoming(nil);
end
function interface_mt:onincoming()
end
@@ -444,6 +465,8 @@ do
end
function interface_mt:ontimeout()
end
+ function interface_mt:ondrain()
+ end
function interface_mt:onstatus()
debug("server.lua: Dummy onstatus()")
end
@@ -524,6 +547,7 @@ do
if succ then -- writing succesful
interface.writebuffer = ""
interface.writebufferlen = 0
+ interface:ondrain();
if interface.fatalerror then
debug "closing client after writing"
interface:_close() -- close interface if needed
@@ -585,7 +609,7 @@ do
interface.eventreadtimeout = nil
end
end
- local buffer, err, part = interface.conn:receive( pattern ) -- receive buffer with "pattern"
+ local buffer, err, part = interface.conn:receive( interface._pattern ) -- receive buffer with "pattern"
--vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) )
buffer = buffer or part or ""
local len = string_len( buffer )
@@ -821,11 +845,32 @@ function hook_signal(signal_num, handler)
return signal_events[signal_num];
end
+local function link(sender, receiver, buffersize)
+ sender:set_mode(buffersize);
+ local sender_locked;
+
+ function receiver:ondrain()
+ if sender_locked then
+ sender:resume();
+ sender_locked = nil;
+ end
+ end
+
+ function sender:onincoming(data)
+ receiver:write(data);
+ if receiver.writebufferlen >= buffersize then
+ sender_locked = true;
+ sender:pause();
+ end
+ end
+end
+
return {
cfg = cfg,
base = base,
loop = loop,
+ link = link,
event = event,
event_base = base,
addevent = newevent,
diff --git a/net/server_select.lua b/net/server_select.lua
index 48262ccc..e66f105b 100644
--- a/net/server_select.lua
+++ b/net/server_select.lua
@@ -252,6 +252,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
local dispatch = listeners.onincoming
local status = listeners.onstatus
local disconnect = listeners.ondisconnect
+ local drain = listeners.ondrain
local bufferqueue = { } -- buffer array
local bufferqueuelen = 0 -- end of buffer array
@@ -284,6 +285,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
dispatch = listeners.onincoming
disconnect = listeners.ondisconnect
status = listeners.onstatus
+ drain = listeners.ondrain
end
handler.getstats = function( )
return readtraffic, sendtraffic
@@ -379,7 +381,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
handler.socket = function( self )
return socket
end
- handler.pattern = function( self, new )
+ handler.set_mode = function( self, new )
pattern = new or pattern
return pattern
end
@@ -392,6 +394,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
maxreadlen = readlen or maxreadlen
return bufferlen, maxreadlen, maxsendlen
end
+ --TODO: Deprecate
handler.lock_read = function (self, switch)
if switch == true then
local tmp = _readlistlen
@@ -409,6 +412,12 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
end
return noread
end
+ handler.pause = function (self)
+ return self:lock_read(true);
+ end
+ handler.resume = function (self)
+ return self:lock_read(false);
+ end
handler.lock = function( self, switch )
handler.lock_read (switch)
if switch == true then
@@ -430,7 +439,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
end
local _readbuffer = function( ) -- this function reads data
local buffer, err, part = receive( socket, pattern ) -- receive buffer with "pattern"
- if not err or (err == "wantread" or err == "timeout") or (part and string_len(part) > 0) then -- received something
+ if not err or (err == "wantread" or err == "timeout") then -- received something
local buffer = buffer or part or ""
local len = string_len( buffer )
if len > maxreadlen then
@@ -472,6 +481,9 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
_sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
_ = needtls and handler:starttls(nil, true)
_writetimes[ handler ] = nil
+ if drain then
+ drain(handler)
+ end
_ = toclose and handler:close( )
return true
elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
@@ -508,6 +520,9 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
out_put( "server.lua: ssl handshake done" )
handler.readbuffer = _readbuffer -- when handshake is done, replace the handshake function with regular functions
handler.sendbuffer = _sendbuffer
+ out_put ("server.lua: compression used: "..tostring(client:compression()))
+ out_put ("server.lua: finished: "..tostring(client:getfinished()):sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_"))
+ out_put ("server.lua: peer finished: "..tostring(client:getpeerfinished()):sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_"))
_ = status and status( handler, "ssl-handshake-complete" )
_readlistlen = addsocket(_readlist, client, _readlistlen)
return true
@@ -617,7 +632,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
listeners.onconnect(handler);
handler.sendbuffer = _sendbuffer;
if bufferqueuelen > 0 then
- return _senddbuffer();
+ return _sendbuffer();
end
end
end
@@ -663,6 +678,28 @@ closesocket = function( socket )
--mem_free( )
end
+local function link(sender, receiver, buffersize)
+ sender:set_mode(buffersize);
+ local sender_locked;
+ local _sendbuffer = receiver.sendbuffer;
+ function receiver.sendbuffer()
+ _sendbuffer();
+ if sender_locked and receiver.bufferlen() < buffersize then
+ sender:lock_read(false); -- Unlock now
+ sender_locked = nil;
+ end
+ end
+
+ local _readbuffer = sender.readbuffer;
+ function sender.readbuffer()
+ _readbuffer();
+ if not sender_locked and receiver.bufferlen() >= buffersize then
+ sender_locked = true;
+ sender:lock_read(true);
+ end
+ end
+end
+
----------------------------------// PUBLIC //--
addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
@@ -886,6 +923,7 @@ return {
wrapclient = wrapclient,
loop = loop,
+ link = link,
stats = stats,
closeall = closeall,
addtimer = addtimer,
diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua
index 8f574704..4457a2f3 100644
--- a/plugins/mod_console.lua
+++ b/plugins/mod_console.lua
@@ -53,76 +53,76 @@ end
local sessions = {};
+function console_listener.onconnect(conn)
+ -- Handle new connection
+ local session = console:new_session(conn);
+ sessions[conn] = session;
+ printbanner(session);
+end
+
function console_listener.onincoming(conn, data)
local session = sessions[conn];
-
- if not session then
- -- Handle new connection
- session = console:new_session(conn);
- sessions[conn] = session;
- printbanner(session);
- end
- if data then
- -- Handle data
- (function(session, data)
- local useglobalenv;
-
- if data:match("^>") then
- data = data:gsub("^>", "");
- useglobalenv = true;
- elseif data == "\004" then
- commands["bye"](session, data);
+
+ -- Handle data
+ (function(session, data)
+ local useglobalenv;
+
+ if data:match("^>") then
+ data = data:gsub("^>", "");
+ useglobalenv = true;
+ elseif data == "\004" then
+ commands["bye"](session, data);
+ return;
+ else
+ local command = data:lower();
+ command = data:match("^%w+") or data:match("%p");
+ if commands[command] then
+ commands[command](session, data);
return;
- else
- local command = data:lower();
- command = data:match("^%w+") or data:match("%p");
- if commands[command] then
- commands[command](session, data);
- return;
- end
end
+ end
- session.env._ = data;
-
- local chunk, err = loadstring("return "..data);
+ session.env._ = data;
+
+ local chunk, err = loadstring("return "..data);
+ if not chunk then
+ chunk, err = loadstring(data);
if not chunk then
- chunk, err = loadstring(data);
- if not chunk then
- err = err:gsub("^%[string .-%]:%d+: ", "");
- err = err:gsub("^:%d+: ", "");
- err = err:gsub("'<eof>'", "the end of the line");
- session.print("Sorry, I couldn't understand that... "..err);
- return;
- end
- end
-
- setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil);
-
- local ranok, taskok, message = pcall(chunk);
-
- if not (ranok or message or useglobalenv) and commands[data:lower()] then
- commands[data:lower()](session, data);
+ err = err:gsub("^%[string .-%]:%d+: ", "");
+ err = err:gsub("^:%d+: ", "");
+ err = err:gsub("'<eof>'", "the end of the line");
+ session.print("Sorry, I couldn't understand that... "..err);
return;
end
-
- if not ranok then
- session.print("Fatal error while running command, it did not complete");
- session.print("Error: "..taskok);
- return;
- end
-
- if not message then
- session.print("Result: "..tostring(taskok));
- return;
- elseif (not taskok) and message then
- session.print("Command completed with a problem");
- session.print("Message: "..tostring(message));
- return;
- end
-
- session.print("OK: "..tostring(message));
- end)(session, data);
- end
+ end
+
+ setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil);
+
+ local ranok, taskok, message = pcall(chunk);
+
+ if not (ranok or message or useglobalenv) and commands[data:lower()] then
+ commands[data:lower()](session, data);
+ return;
+ end
+
+ if not ranok then
+ session.print("Fatal error while running command, it did not complete");
+ session.print("Error: "..taskok);
+ return;
+ end
+
+ if not message then
+ session.print("Result: "..tostring(taskok));
+ return;
+ elseif (not taskok) and message then
+ session.print("Command completed with a problem");
+ session.print("Message: "..tostring(message));
+ return;
+ end
+
+ session.print("OK: "..tostring(message));
+ end)(session, data);
+
session.send(string.char(0));
end
diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua
index 5c9ae329..190d30be 100644
--- a/plugins/mod_proxy65.lua
+++ b/plugins/mod_proxy65.lua
@@ -20,6 +20,7 @@ local componentmanager = require "core.componentmanager";
local config_get = require "core.configmanager".get;
local connlisteners = require "net.connlisteners";
local sha1 = require "util.hashes".sha1;
+local server = require "net.server";
local host, name = module:get_host(), "SOCKS5 Bytestreams Service";
local sessions, transfers, component, replies_cache = {}, {}, nil, {};
@@ -28,6 +29,7 @@ local proxy_port = config_get(host, "core", "proxy65_port") or 5000;
local proxy_interface = config_get(host, "core", "proxy65_interface") or "*";
local proxy_address = config_get(host, "core", "proxy65_address") or (proxy_interface ~= "*" and proxy_interface) or host;
local proxy_acl = config_get(host, "core", "proxy65_acl");
+local max_buffer_size = 4096;
local connlistener = { default_port = proxy_port, default_interface = proxy_interface, default_mode = "*a" };
@@ -84,8 +86,8 @@ function connlistener.onincoming(conn, data)
transfers[sha].initiator = conn;
session.sha = sha;
module:log("debug", "initiator connected ... ");
- throttle_sending(conn, transfers[sha].target);
- throttle_sending(transfers[sha].target, conn);
+ server.link(conn, transfers[sha].target, max_buffer_size);
+ server.link(transfers[sha].target, conn, max_buffer_size);
end
conn:write(string.char(5, 0, 0, 3, sha:len()) .. sha .. string.char(0, 0)); -- VER, REP, RSV, ATYP, BND.ADDR (sha), BND.PORT (2 Byte)
conn:lock_read(true)
@@ -234,8 +236,12 @@ function handle_to_domain(origin, stanza)
elseif xmlns == "http://jabber.org/protocol/bytestreams" then
origin.send(get_stream_host(origin, stanza));
return true;
+ else
+ origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
+ return true;
end
elseif stanza.name == "iq" and type == "set" then
+ module:log("debug", "Received activation request from %s", stanza.attr.from);
local reply, from, to, sid = set_activation(stanza);
if reply ~= nil and from ~= nil and to ~= nil and sid ~= nil then
local sha = sha1(sid .. from .. to, true);
@@ -246,6 +252,15 @@ function handle_to_domain(origin, stanza)
transfers[sha].activated = true;
transfers[sha].target:lock_read(false);
transfers[sha].initiator:lock_read(false);
+ else
+ module:log("debug", "Both parties were not yet connected");
+ local message = "Neither party is connected to the proxy";
+ if transfers[sha].initiator then
+ message = "The recipient is not connected to the proxy";
+ elseif transfers[sha].target then
+ message = "The sender (you) is not connected to the proxy";
+ end
+ origin.send(st.error_reply(stanza, "cancel", "not-allowed", message));
end
else
module:log("error", "activation failed: sid: %s, initiator: %s, target: %s", tostring(sid), tostring(from), tostring(to));
@@ -262,25 +277,3 @@ end
connlisteners.start(module.host .. ':proxy65');
component = componentmanager.register_component(host, handle_to_domain);
-local sender_lock_threshold = 4096;
-function throttle_sending(sender, receiver)
- sender:pattern(sender_lock_threshold);
- local sender_locked;
- local _sendbuffer = receiver.sendbuffer;
- function receiver.sendbuffer()
- _sendbuffer();
- if sender_locked and receiver.bufferlen() < sender_lock_threshold then
- sender:lock_read(false); -- Unlock now
- sender_locked = nil;
- end
- end
-
- local _readbuffer = sender.readbuffer;
- function sender.readbuffer()
- _readbuffer();
- if not sender_locked and receiver.bufferlen() >= sender_lock_threshold then
- sender_locked = true;
- sender:lock_read(true);
- end
- end
-end
diff --git a/prosody b/prosody
index 0f705b62..8e96eb46 100755
--- a/prosody
+++ b/prosody
@@ -29,6 +29,10 @@ if CFG_DATADIR then
end
end
+-- Global 'prosody' object
+prosody = { events = require "util.events".new(); };
+local prosody = prosody;
+
-- Load the config-parsing module
config = require "core.configmanager"
@@ -120,15 +124,34 @@ function sandbox_require()
end
end
+function set_function_metatable()
+ local mt = {};
+ function mt.__index(f, upvalue)
+ local i, name, value = 0;
+ repeat
+ i = i + 1;
+ name, value = debug.getupvalue(f, i);
+ until name == upvalue or name == nil;
+ return value;
+ end
+ function mt.__newindex(f, upvalue, value)
+ local i, name = 0;
+ repeat
+ i = i + 1;
+ name = debug.getupvalue(f, i);
+ until name == upvalue or name == nil;
+ if name then
+ debug.setupvalue(f, i, value);
+ end
+ end
+ debug.setmetatable(function() end, mt);
+end
+
function init_global_state()
bare_sessions = {};
full_sessions = {};
hosts = {};
- -- Global 'prosody' object
- prosody = {};
- local prosody = prosody;
-
prosody.bare_sessions = bare_sessions;
prosody.full_sessions = full_sessions;
prosody.hosts = hosts;
@@ -138,8 +161,6 @@ function init_global_state()
prosody.arg = _G.arg;
- prosody.events = require "util.events".new();
-
prosody.platform = "unknown";
if os.getenv("WINDIR") then
prosody.platform = "windows";
@@ -170,7 +191,6 @@ function init_global_state()
-- Function to reopen logfiles
function prosody.reopen_logfiles()
log("info", "Re-opening log files");
- eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
prosody.events.fire_event("reopen-log-files");
end
@@ -263,7 +283,6 @@ function load_secondary_libraries()
require "util.import"
require "core.xmlhandlers"
require "core.rostermanager"
- require "core.eventmanager"
require "core.hostmanager"
require "core.modulemanager"
require "core.usermanager"
@@ -307,7 +326,6 @@ end
function prepare_to_start()
log("info", "Prosody is using the %s backend for connection handling", server.get_backend());
-- Signal to modules that we are ready to start
- eventmanager.fire_event("server-starting");
prosody.events.fire_event("server-starting");
-- start listening on sockets
@@ -415,6 +433,7 @@ read_config();
init_logging();
check_dependencies();
sandbox_require();
+set_function_metatable();
load_libraries();
init_global_state();
read_version();
@@ -424,14 +443,12 @@ init_data_store();
init_global_protection();
prepare_to_start();
-eventmanager.fire_event("server-started");
prosody.events.fire_event("server-started");
loop();
log("info", "Shutting down...");
cleanup();
-eventmanager.fire_event("server-stopped");
prosody.events.fire_event("server-stopped");
log("info", "Shutdown complete");
diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist
index c959b4fe..a17eb877 100644
--- a/prosody.cfg.lua.dist
+++ b/prosody.cfg.lua.dist
@@ -1,138 +1,127 @@
-- Prosody Example Configuration File
+--
+-- Information on configuring Prosody can be found on our
+-- website at http://prosody.im/doc/configure
+--
+-- Tip: You can check that the syntax of this file is correct
+-- when you have finished by running: luac -p prosody.cfg.lua
+-- If there are any errors, it will let you know what and where
+-- they are, otherwise it will keep quiet.
--
--- If it wasn't already obvious, -- starts a comment, and all
--- text after it on a line is ignored by Prosody.
---
--- The config is split into sections, a global section, and one
--- for each defined host that we serve. You can add as many host
--- sections as you like.
---
--- Lists are written { "like", "this", "one" }
--- Lists can also be of { 1, 2, 3 } numbers, and other things.
--- Either commas, or semi-colons; may be used
--- as seperators.
---
--- A table is a list of values, except each value has a name. An
--- example table would be:
---
--- ssl = { key = "keyfile.key", certificate = "certificate.cert" }
---
--- Whitespace (that is tabs, spaces, line breaks) is mostly
--- insignificant, so
--- can
--- be placed anywhere that you deem fitting.
---
--- Tip: You can check that the syntax of this file is correct when you
--- have finished by running: luac -p prosody.cfg.lua
--- If there are any errors, it will let you know what and where they
--- are, otherwise it will keep quiet.
---
--- The only thing left to do is rename this file to remove the .dist
--- ending, and fill in the
+-- The only thing left to do is rename this file to remove the .dist ending, and fill in the
-- blanks. Good luck, and happy Jabbering!
--- Server-wide settings go in this section
-Host "*"
-
- -- This is a (by default, empty) list of accounts that are admins for the
- -- server. Note that you must create the accounts separately (see
- -- http://prosody.im/doc/creating_accounts)
- -- Example: admins = { "user1@example.com", "user2@example.net" }
- admins = { }
-
- -- Enable use of libevent for better performance under high load
- -- For more information see: http://prosody.im/doc/libevent
- --use_libevent = true;
-
- -- This is the list of modules Prosody will load on startup. It looks for
- -- mod_modulename.lua in the plugins folder, so make sure that exists too.
- -- Documentation on modules can be found at: http://prosody.im/doc/modules
- modules_enabled = {
- -- Generally required
- "roster"; -- Allow users to have a roster. Recommended ;)
- "saslauth"; -- Authentication for clients and servers. Recommended if
- -- you want to log in.
- "dialback"; -- s2s dialback support
- "disco"; -- Service discovery
- "posix"; -- POSIX functionality, daemonizes, enables syslog, etc.
-
- -- Not essential, but recommended
- "private"; -- Private XML storage (for room bookmarks, etc.)
- "vcard"; -- Allow users to set vCards
- "tls"; -- Support for secure TLS on c2s/s2s connections
- --"privacy"; -- Support privacy lists
- --"compression"; -- Stream compression for client-to-server streams
-
- -- Nice to have
- "legacyauth"; -- Legacy authentication. Only used by some old
- -- clients and bots.
- "version"; -- Replies to server version requests
- "uptime"; -- Report how long server has been running
- "time"; -- Let others know the time here on this server
- "ping"; -- Replies to XMPP pings with pongs
- "pep"; -- Enables users to publish their mood, activity, playing
- -- music and more
- "register"; -- Allow users to register on this server using a client
- -- and change passwords
-
- -- Other specific functionality
- --"console"; -- telnet to port 5582
- -- (needs console_enabled = true)
- --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
- --"httpserver"; -- Serve static files from a directory over
- -- HTTP
- --"groups"; -- Shared roster support
- --"announce"; -- Send announcement to all online users
- --"welcome"; -- Welcome users who register accounts
- --"watchregistrations"; -- Alert admins of registrations
- }
- -- These modules are auto-loaded, should you for (for some mad
- -- reason) want to disable them then uncomment them below.
- modules_disabled = {
- --"presence";
- --"message";
- --"iq";
- }
+---------- Server-wide settings ----------
+-- Settings in this section apply to the whole server and are the default settings
+-- for any virtual hosts
- -- Disable account creation by default, for security
- -- For more information see http://prosody.im/doc/creating_accounts
- allow_registration = false;
+-- This is a (by default, empty) list of accounts that are admins
+-- for the server. Note that you must create the accounts separately
+-- (see http://prosody.im/doc/creating_accounts for info)
+-- Example: admins = { "user1@example.com", "user2@example.net" }
+admins = { }
- --These are the SSL/TLS-related settings.
- --ssl = {
- -- key = "certs/localhost.key";
- -- certificate = "certs/localhost.cert";
- --}
+-- Enable use of libevent for better performance under high load
+-- For more information see: http://prosody.im/doc/libevent
+--use_libevent = true;
- -- Require encryption on client/server connections?
- --c2s_require_encryption = false
- --s2s_require_encryption = false
+-- This is the list of modules Prosody will load on startup.
+-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
+-- Documentation on modules can be found at: http://prosody.im/doc/modules
+modules_enabled = {
- -- Logging configuration
- -- For advanced logging see http://prosody.im/doc/logging
- log = "prosody.log";
- debug = false; -- Log debug messages?
+ -- Generally required
+ "roster"; -- Allow users to have a roster. Recommended ;)
+ "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
+ "tls"; -- Add support for secure TLS on c2s/s2s connections
+ "dialback"; -- s2s dialback support
+ "disco"; -- Service discovery
+
+ -- Not essential, but recommended
+ "private"; -- Private XML storage (for room bookmarks, etc.)
+ "vcard"; -- Allow users to set vCards
+ --"privacy"; -- Support privacy lists
+ --"compression"; -- Stream compression
+
+ -- Nice to have
+ "legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
+ "version"; -- Replies to server version requests
+ "uptime"; -- Report how long server has been running
+ "time"; -- Let others know the time here on this server
+ "ping"; -- Replies to XMPP pings with pongs
+ "pep"; -- Enables users to publish their mood, activity, playing music and more
+ "register"; -- Allow users to register on this server using a client and change passwords
+
+ -- Other specific functionality
+ --"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
+ --"console"; -- Opens admin telnet interface on localhost port 5582
+ --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
+ --"httpserver"; -- Serve static files from a directory over HTTP
+ --"groups"; -- Shared roster support
+ --"announce"; -- Send announcement to all online users
+ --"welcome"; -- Welcome users who register accounts
+ --"watchregistrations"; -- Alert admins of registrations
+};
+
+-- These modules are auto-loaded, should you
+-- for (for some mad reason) want to disable
+-- them then uncomment them below
+modules_disabled = {
+ -- "presence";
+ -- "message";
+ -- "iq";
+};
+
+-- Disable account creation by default, for security
+-- For more information see http://prosody.im/doc/creating_accounts
+allow_registration = false;
+
+-- These are the SSL/TLS-related settings. If you don't want
+-- to use SSL/TLS, you may comment or remove this
+ssl = {
+ key = "certs/localhost.key";
+ certificate = "certs/localhost.cert";
+}
+
+-- Require encryption on client/server connections?
+--c2s_require_encryption = false
+--s2s_require_encryption = false
+
+-- Logging configuration
+-- For advanced logging see http://prosody.im/doc/logging
+log = "prosody.log";
+debug = false; -- Log debug messages?
+
+----------- Virtual hosts -----------
+-- You need to add a VirtualHost entry for each domain you wish Prosody to serve.
+-- Settings under each VirtualHost entry apply *only* to that host.
+
+VirtualHost "localhost"
+
+VirtualHost "example.com"
+ enabled = false -- Remove this line to enable this host
--- This allows clients to connect to localhost. No harm in it.
-Host "localhost"
+ -- Assign this host a certificate for TLS, otherwise it would use the one
+ -- set in the global section (if any).
+ -- Note that old-style SSL on port 5223 only supports one certificate, and will always
+ -- use the global one.
+ ssl = {
+ key = "certs/example.com.key";
+ certificate = "certs/example.com.crt";
+ }
--- Section for example.com
--- (replace example.com with your domain name)
-Host "example.com"
- enabled = false -- This will disable the host, preserving the config, but
- -- denying connections (remove to enable!)
+------ Components ------
+-- You can specify components to add hosts that provide special services,
+-- like multi-user conferences, and transports.
+-- For more information on components, see http://prosody.im/doc/components
- -- Assign this host a certificate for TLS, otherwise it would use the one
- -- set in the global section (if any). Note that old-style SSL on port 5223
- -- only supports one certificate, and will always use the global one.
- --ssl = {
- -- key = "certs/example.com.key";
- -- certificate = "certs/example.com.crt";
- --}
-
--- Set up a MUC (multi-user chat) room server on conference.example.com:
+---Set up a MUC (multi-user chat) room server on conference.example.com:
--Component "conference.example.com" "muc"
-- Set up a SOCKS5 bytestream proxy for server-proxied file transfers:
--Component "proxy.example.com" "proxy65"
+
+---Set up an external component (default component port is 5347)
+--Component "gateway.example.com"
+-- component_secret = "password"
diff --git a/util/sasl.lua b/util/sasl.lua
index eb71956b..306acc0c 100644
--- a/util/sasl.lua
+++ b/util/sasl.lua
@@ -41,27 +41,6 @@ Authentication Backend Prototypes:
state = false : disabled
state = true : enabled
state = nil : non-existant
-
-plain:
- function(username, realm)
- return password, state;
- end
-
-plain-test:
- function(username, realm, password)
- return true or false, state;
- end
-
-digest-md5:
- function(username, domain, realm, encoding) -- domain and realm are usually the same; for some broken
- -- implementations it's not
- return digesthash, state;
- end
-
-digest-md5-test:
- function(username, domain, realm, encoding, digesthash)
- return true or false, state;
- end
]]
local method = {};
diff --git a/util/sasl/anonymous.lua b/util/sasl/anonymous.lua
index 65650294..f3e31a7f 100644
--- a/util/sasl/anonymous.lua
+++ b/util/sasl/anonymous.lua
@@ -1,5 +1,5 @@
-- sasl.lua v0.4
--- Copyright (C) 2008-2009 Tobias Markmann
+-- Copyright (C) 2008-2010 Tobias Markmann
--
-- All rights reserved.
--
@@ -20,6 +20,16 @@ module "anonymous"
--=========================
--SASL ANONYMOUS according to RFC 4505
+
+--[[
+Supported Authentication Backends
+
+anonymous:
+ function(username, realm)
+ return true; --for normal usage just return true; if you don't like the supplied username you can return false.
+ end
+]]
+
local function anonymous(self, message)
local username;
repeat
diff --git a/util/sasl/digest-md5.lua b/util/sasl/digest-md5.lua
index 04acf04d..8986ca45 100644
--- a/util/sasl/digest-md5.lua
+++ b/util/sasl/digest-md5.lua
@@ -1,5 +1,5 @@
-- sasl.lua v0.4
--- Copyright (C) 2008-2009 Tobias Markmann
+-- Copyright (C) 2008-2010 Tobias Markmann
--
-- All rights reserved.
--
@@ -29,6 +29,21 @@ module "digest-md5"
--=========================
--SASL DIGEST-MD5 according to RFC 2831
+--[[
+Supported Authentication Backends
+
+digest-md5:
+ function(username, domain, realm, encoding) -- domain and realm are usually the same; for some broken
+ -- implementations it's not
+ return digesthash, state;
+ end
+
+digest-md5-test:
+ function(username, domain, realm, encoding, digesthash)
+ return true or false, state;
+ end
+]]
+
local function digest(self, message)
--TODO complete support for authzid
diff --git a/util/sasl/plain.lua b/util/sasl/plain.lua
index ae5c777a..2abbc53a 100644
--- a/util/sasl/plain.lua
+++ b/util/sasl/plain.lua
@@ -1,5 +1,5 @@
-- sasl.lua v0.4
--- Copyright (C) 2008-2009 Tobias Markmann
+-- Copyright (C) 2008-2010 Tobias Markmann
--
-- All rights reserved.
--
@@ -19,6 +19,26 @@ module "plain"
-- ================================
-- SASL PLAIN according to RFC 4616
+
+--[[
+Supported Authentication Backends
+
+plain:
+ function(username, realm)
+ return password, state;
+ end
+
+plain-test:
+ function(username, realm, password)
+ return true or false, state;
+ end
+
+plain-hashed:
+ function(username, realm)
+ return hashed_password, hash_function, state;
+ end
+]]
+
local function plain(self, message)
if not message then
return "failure", "malformed-request";
@@ -46,6 +66,10 @@ local function plain(self, message)
if correct_password == password then correct = true; else correct = false; end
elseif self.profile.plain_test then
correct, state = self.profile.plain_test(authentication, self.realm, password);
+ elseif self.profile.plain_hashed then
+ local hashed_password, hash_f;
+ hashed_password, hash_f, state = self.profile.plain_hashed(authentication, self.realm);
+ if hashed_password == hash_f(password) then correct = true; else correct = false; end
end
self.username = authentication
@@ -61,7 +85,7 @@ local function plain(self, message)
end
function init(registerMechanism)
- registerMechanism("PLAIN", {"plain", "plain_test"}, plain);
+ registerMechanism("PLAIN", {"plain", "plain_test", "plain_hashed"}, plain);
end
return _M;
diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua
index 103e8a90..4875731f 100644
--- a/util/sasl/scram.lua
+++ b/util/sasl/scram.lua
@@ -1,5 +1,5 @@
-- sasl.lua v0.4
--- Copyright (C) 2008-2009 Tobias Markmann
+-- Copyright (C) 2008-2010 Tobias Markmann
--
-- All rights reserved.
--
@@ -28,6 +28,16 @@ module "scram"
--=========================
--SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10
+
+--[[
+Supported Authentication Backends
+
+scram-{MECH}:
+ function(username, realm)
+ return salted_password, iteration_count, salt, state;
+ end
+]]
+
local default_i = 4096
local function bp( b )
@@ -82,77 +92,95 @@ local function validate_username(username)
return username;
end
-local function scram_sha_1(self, message)
- if not self.state then self["state"] = {} end
+local function scram_gen(hash_name, H_f, HMAC_f)
+ local function scram_hash(self, message)
+ if not self.state then self["state"] = {} end
- if not self.state.name then
- -- we are processing client_first_message
- local client_first_message = message;
- self.state["client_first_message"] = client_first_message;
- self.state["name"] = client_first_message:match("n=(.+),r=")
- self.state["clientnonce"] = client_first_message:match("r=([^,]+)")
-
- if not self.state.name or not self.state.clientnonce then
- return "failure", "malformed-request";
- end
-
- self.state.name = validate_username(self.state.name);
if not self.state.name then
- log("debug", "Username violates either SASLprep or contains forbidden character sequences.")
- return "failure", "malformed-request", "Invalid username.";
- end
+ -- we are processing client_first_message
+ local client_first_message = message;
+ self.state["client_first_message"] = client_first_message;
+ self.state["name"] = client_first_message:match("n=(.+),r=")
+ self.state["clientnonce"] = client_first_message:match("r=([^,]+)")
- self.state["servernonce"] = generate_uuid();
- self.state["salt"] = generate_uuid();
+ if not self.state.name or not self.state.clientnonce then
+ return "failure", "malformed-request";
+ end
- local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i;
- self.state["server_first_message"] = server_first_message;
- return "challenge", server_first_message
- else
- if type(message) ~= "string" then return "failure", "malformed-request" end
- -- we are processing client_final_message
- local client_final_message = message;
+ self.state.name = validate_username(self.state.name);
+ if not self.state.name then
+ log("debug", "Username violates either SASLprep or contains forbidden character sequences.")
+ return "failure", "malformed-request", "Invalid username.";
+ end
- self.state["proof"] = client_final_message:match("p=(.+)");
- self.state["nonce"] = client_final_message:match("r=(.+),p=");
- self.state["channelbinding"] = client_final_message:match("c=(.+),r=");
- if not self.state.proof or not self.state.nonce or not self.state.channelbinding then
- return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message.";
- end
+ self.state["servernonce"] = generate_uuid();
+
+ -- retreive credentials
+ if self.profile.plain then
+ password, state = self.profile.plain(self.state.name, self.realm)
+ if state == nil then return "failure", "not-authorized"
+ elseif state == false then return "failure", "account-disabled" end
+
+ password = saslprep(password);
+ if not password then
+ log("debug", "Password violates SASLprep.");
+ return "failure", "not-authorized", "Invalid password."
+ end
+ self.state.salt = generate_uuid();
+ self.state.iteration_count = default_i;
+ self.state.salted_password = Hi(HMAC_f, password, self.state.salt, default_i);
+ elseif self.profile["scram_"..hash_name] then
+ salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm);
+ if state == nil then return "failure", "not-authorized"
+ elseif state == false then return "failure", "account-disabled" end
+
+ self.state.salted_password = salted_password;
+ self.state.iteration_count = iteration_count;
+ self.state.salt = salt
+ end
- local password, state;
- if self.profile.plain then
- password, state = self.profile.plain(self.state.name, self.realm)
- if state == nil then return "failure", "not-authorized"
- elseif state == false then return "failure", "account-disabled" end
- password = saslprep(password);
- if not password then
- log("debug", "Password violates SASLprep.");
- return "failure", "not-authorized", "Invalid password."
+ local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count;
+ self.state["server_first_message"] = server_first_message;
+ return "challenge", server_first_message
+ else
+ if type(message) ~= "string" then return "failure", "malformed-request" end
+ -- we are processing client_final_message
+ local client_final_message = message;
+
+ self.state["proof"] = client_final_message:match("p=(.+)");
+ self.state["nonce"] = client_final_message:match("r=(.+),p=");
+ self.state["channelbinding"] = client_final_message:match("c=(.+),r=");
+ if not self.state.proof or not self.state.nonce or not self.state.channelbinding then
+ return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message.";
end
- end
- local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i)
- local ClientKey = hmac_sha1(SaltedPassword, "Client Key")
- local ServerKey = hmac_sha1(SaltedPassword, "Server Key")
- local StoredKey = sha1(ClientKey)
- local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+")
- local ClientSignature = hmac_sha1(StoredKey, AuthMessage)
- local ClientProof = binaryXOR(ClientKey, ClientSignature)
- local ServerSignature = hmac_sha1(ServerKey, AuthMessage)
+ local SaltedPassword = self.state.salted_password;
+ local ClientKey = HMAC_f(SaltedPassword, "Client Key")
+ local ServerKey = HMAC_f(SaltedPassword, "Server Key")
+ local StoredKey = H_f(ClientKey)
+ local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+")
+ local ClientSignature = HMAC_f(StoredKey, AuthMessage)
+ local ClientProof = binaryXOR(ClientKey, ClientSignature)
+ local ServerSignature = HMAC_f(ServerKey, AuthMessage)
- if base64.encode(ClientProof) == self.state.proof then
- local server_final_message = "v="..base64.encode(ServerSignature);
- self["username"] = self.state.name;
- return "success", server_final_message;
- else
- return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated.";
+ if base64.encode(ClientProof) == self.state.proof then
+ local server_final_message = "v="..base64.encode(ServerSignature);
+ self["username"] = self.state.name;
+ return "success", server_final_message;
+ else
+ return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated.";
+ end
end
end
+ return scram_hash;
end
function init(registerMechanism)
- registerMechanism("SCRAM-SHA-1", {"plain"}, scram_sha_1);
+ local function registerSCRAMMechanism(hash_name, hash, hmac_hash)
+ registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash));
+ end
+
+ registerSCRAMMechanism("SHA-1", sha1, hmac_sha1);
end
return _M; \ No newline at end of file