1+ local nodeprep = require " util.encodings" .stringprep .nodeprep ;
2+ local lpc = require " lpc" ;
3+
4+ local config = require " core.configmanager" ;
5+ local log = module ._log ;
6+ local host = module .host ;
7+ local script_type = config .get (host , " external_auth_protocol" ) or " generic" ;
8+ assert (script_type == " ejabberd" or script_type == " generic" );
9+ local command = config .get (host , " external_auth_command" ) or " " ;
10+ assert (type (command ) == " string" );
11+ assert (not host :find (" :" ));
12+ local usermanager = require " core.usermanager" ;
13+ local jid_bare = require " util.jid" .bare ;
14+ local new_sasl = require " util.sasl" .new ;
15+
16+ local pid ;
17+ local readfile ;
18+ local writefile ;
19+
20+ local function send_query (text )
21+ if pid and lpc .wait (pid ,1 ) ~= nil then
22+ log (" debug" ," error, process died, force reopen" );
23+ pid = nil ;
24+ end
25+ if not pid then
26+ log (" debug" , " Opening process " .. command );
27+ pid , writefile , readfile = lpc .run (command );
28+ end
29+ if not pid then
30+ log (" debug" , " Process failed to open" );
31+ return nil ;
32+ end
33+
34+ writefile :write (text );
35+ writefile :flush ();
36+ if script_type == " ejabberd" then
37+ return readfile :read (4 );
38+ elseif script_type == " generic" then
39+ return readfile :read ();
40+ end
41+ end
42+
43+ function do_query (kind , username , password )
44+ if not username then return nil , " not-acceptable" ; end
45+ username = nodeprep (username );
46+ if not username then return nil , " jid-malformed" ; end
47+
48+ local query = (password and " %s:%s:%s:%s" or " %s:%s:%s" ):format (kind , username , host , password );
49+ local len = # query
50+ if len > 1000 then return nil , " policy-violation" ; end
51+
52+ if script_type == " ejabberd" then
53+ local lo = len % 256 ;
54+ local hi = (len - lo ) / 256 ;
55+ query = string.char (hi , lo ).. query ;
56+ end
57+ if script_type == " generic" then
58+ query = query .. ' \n ' ;
59+ end
60+
61+ local response = send_query (query );
62+ if (script_type == " ejabberd" and response == " \0\2\0\0 " ) or
63+ (script_type == " generic" and response == " 0" ) then
64+ return nil , " not-authorized" ;
65+ elseif (script_type == " ejabberd" and response == " \0\2\0\1 " ) or
66+ (script_type == " generic" and response == " 1" ) then
67+ return true ;
68+ else
69+ log (" debug" , " Nonsense back" );
70+ return nil , " internal-server-error" ;
71+ end
72+ end
73+
74+ function new_external_provider (host )
75+ local provider = { name = " external" };
76+
77+ function provider .test_password (username , password )
78+ return do_query (" auth" , username , password );
79+ end
80+
81+ function provider .set_password (username , password )
82+ return do_query (" setpass" , username , password );
83+ end
84+
85+ function provider .user_exists (username )
86+ return do_query (" isuser" , username );
87+ end
88+
89+ function provider .create_user (username , password ) return nil , " Account creation/modification not available." ; end
90+
91+ function provider .get_sasl_handler ()
92+ local testpass_authentication_profile = {
93+ plain_test = function (sasl , username , password , realm )
94+ return usermanager .test_password (username , realm , password ), true ;
95+ end ,
96+ };
97+ return new_sasl (module .host , testpass_authentication_profile );
98+ end
99+
100+ function provider .is_admin (jid )
101+ local admins = config .get (host , " admins" );
102+ if admins ~= config .get (" *" , " admins" ) then
103+ if type (admins ) == " table" then
104+ jid = jid_bare (jid );
105+ for _ ,admin in ipairs (admins ) do
106+ if admin == jid then return true ; end
107+ end
108+ elseif admins then
109+ log (" error" , " Option 'admins' for host '%s' is not a table" , host );
110+ end
111+ end
112+ return usermanager .is_admin (jid );
113+ end
114+
115+ return provider ;
116+ end
117+
118+ module :add_item (" auth-provider" , new_external_provider (host ));
0 commit comments