17 |
17 |
18 function new_default_provider(host) |
18 function new_default_provider(host) |
19 local provider = { name = "dovecot", c = nil }; |
19 local provider = { name = "dovecot", c = nil }; |
20 log("debug", "initializing dovecot authentication provider for host '%s'", host); |
20 log("debug", "initializing dovecot authentication provider for host '%s'", host); |
21 |
21 |
|
22 -- Closes the socket |
|
23 function provider.close(self) |
|
24 if (provider.c ~= nil) then |
|
25 provider.c:close(); |
|
26 end |
|
27 provider.c = nil; |
|
28 end |
|
29 |
22 -- The following connects to a new socket and send the handshake |
30 -- The following connects to a new socket and send the handshake |
23 function provider.connect(self) |
31 function provider.connect(self) |
24 -- Destroy old socket |
32 -- Destroy old socket |
25 if (provider.c ~= nil) then |
33 provider:close(); |
26 provider.c:close(); |
|
27 end |
|
28 |
34 |
29 provider.c = socket.unix(); |
35 provider.c = socket.unix(); |
30 |
36 |
31 -- Create a connection to dovecot socket |
37 -- Create a connection to dovecot socket |
32 local socket = "/var/run/dovecot/auth-login"; |
38 local socket = "/var/run/dovecot/auth-login"; |
33 local r, e = provider.c:connect(socket); |
39 local r, e = provider.c:connect(socket); |
34 if (not r) then |
40 if (not r) then |
35 log("warn", "error connecting to dovecot socket at '%s'. error was '%s'. check permissions", socket, e); |
41 log("warn", "error connecting to dovecot socket at '%s'. error was '%s'. check permissions", socket, e); |
|
42 provider:close(); |
36 return false; |
43 return false; |
37 end |
44 end |
38 |
45 |
39 -- Send our handshake |
46 -- Send our handshake |
40 local pid = pposix.getpid(); |
47 local pid = pposix.getpid(); |
60 local v1 = parts(); |
67 local v1 = parts(); |
61 local v2 = parts(); |
68 local v2 = parts(); |
62 |
69 |
63 if (not (v1 == "1" and v2 == "1")) then |
70 if (not (v1 == "1" and v2 == "1")) then |
64 log("warn", "server version is not 1.1. it is %s.%s", v1, v2); |
71 log("warn", "server version is not 1.1. it is %s.%s", v1, v2); |
|
72 provider:close(); |
65 return false; |
73 return false; |
66 end |
74 end |
67 elseif (first == "MECH") then |
75 elseif (first == "MECH") then |
68 -- Mechanisms should include PLAIN |
76 -- Mechanisms should include PLAIN |
69 local ok = false; |
77 local ok = false; |
72 ok = true; |
80 ok = true; |
73 end |
81 end |
74 end |
82 end |
75 if (not ok) then |
83 if (not ok) then |
76 log("warn", "server doesn't support PLAIN mechanism. It supports '%s'", l); |
84 log("warn", "server doesn't support PLAIN mechanism. It supports '%s'", l); |
|
85 provider:close(); |
77 return false; |
86 return false; |
78 end |
87 end |
79 elseif (first == "DONE") then |
88 elseif (first == "DONE") then |
80 done = true; |
89 done = true; |
81 end |
90 end |
82 end |
91 end |
83 return true; |
92 return true; |
84 end |
93 end |
85 |
94 |
|
95 -- Wrapper for send(). Handles errors |
86 function provider.send(self, data) |
96 function provider.send(self, data) |
87 local r, e = provider.c:send(data); |
97 local r, e = provider.c:send(data); |
88 if (not r) then |
98 if (not r) then |
89 log("warn", "error sending '%s' to dovecot. error was '%s'", data, e); |
99 log("warn", "error sending '%s' to dovecot. error was '%s'", data, e); |
|
100 provider:close(); |
90 return false; |
101 return false; |
91 end |
102 end |
92 return true; |
103 return true; |
93 end |
104 end |
94 |
105 |
|
106 -- Wrapper for receive(). Handles errors |
95 function provider.receive(self) |
107 function provider.receive(self) |
96 local r, e = provider.c:receive(); |
108 local r, e = provider.c:receive(); |
97 if (not r) then |
109 if (not r) then |
98 log("warn", "error receiving data from dovecot. error was '%s'", socket, e); |
110 log("warn", "error receiving data from dovecot. error was '%s'", socket, e); |
|
111 provider:close(); |
99 return false; |
112 return false; |
100 end |
113 end |
101 return r; |
114 return r; |
102 end |
115 end |
103 |
116 |
104 function provider.test_password(username, password) |
117 function provider.test_password(username, password) |
105 log("debug", "test password '%s' for user %s at host %s", password, username, module.host); |
118 log("debug", "test password '%s' for user %s at host %s", password, username, module.host); |
106 |
119 |
107 if (not provider:connect()) then |
120 local tries = 0; |
108 return nil, "Auth failed. Dovecot communications error"; |
121 |
|
122 if (provider.c == nil or tries > 0) then |
|
123 if (not provider:connect()) then |
|
124 return nil, "Auth failed. Dovecot communications error"; |
|
125 end |
109 end |
126 end |
110 |
127 |
111 -- Send auth data |
128 -- Send auth data |
112 username = username .. "@" .. module.host; -- FIXME: this is actually a hack for my server |
129 username = username .. "@" .. module.host; -- FIXME: this is actually a hack for my server |
113 local b64 = base64.encode(username .. "\0" .. username .. "\0" .. password); |
130 local b64 = base64.encode(username .. "\0" .. username .. "\0" .. password); |
128 return true; |
145 return true; |
129 else |
146 else |
130 return nil, "Auth failed. Invalid username or password."; |
147 return nil, "Auth failed. Invalid username or password."; |
131 end |
148 end |
132 end |
149 end |
133 |
150 |
134 function provider.get_password(username) |
151 function provider.get_password(username) |
135 return nil, "Cannot get_password in dovecot backend."; |
152 return nil, "Cannot get_password in dovecot backend."; |
136 end |
153 end |
137 |
154 |
138 function provider.set_password(username, password) |
155 function provider.set_password(username, password) |
139 return nil, "Cannot set_password in dovecot backend."; |
156 return nil, "Cannot set_password in dovecot backend."; |
140 end |
157 end |
141 |
158 |
142 function provider.user_exists(username) |
159 function provider.user_exists(username) |
143 --TODO: Send an auth request. If it returns FAIL <id> user=<user> then user exists. |
160 --TODO: Send an auth request. If it returns FAIL <id> user=<user> then user exists. |
144 return nil, "user_exists not yet implemented in dovecot backend."; |
161 return nil, "user_exists not yet implemented in dovecot backend."; |
145 end |
162 end |
146 |
163 |
147 function provider.create_user(username, password) |
164 function provider.create_user(username, password) |
148 return nil, "Cannot create_user in dovecot backend."; |
165 return nil, "Cannot create_user in dovecot backend."; |
149 end |
166 end |
150 |
167 |
151 function provider.get_sasl_handler() |
168 function provider.get_sasl_handler() |
152 local realm = module:get_option("sasl_realm") or module.host; |
169 local realm = module:get_option("sasl_realm") or module.host; |
153 local getpass_authentication_profile = { |
170 local getpass_authentication_profile = { |
154 plain_test = function(username, password, realm) |
171 plain_test = function(username, password, realm) |
155 local prepped_username = nodeprep(username); |
172 local prepped_username = nodeprep(username); |
157 log("debug", "NODEprep failed on username: %s", username); |
174 log("debug", "NODEprep failed on username: %s", username); |
158 return "", nil; |
175 return "", nil; |
159 end |
176 end |
160 return usermanager.test_password(prepped_username, realm, password), true; |
177 return usermanager.test_password(prepped_username, realm, password), true; |
161 end |
178 end |
162 }; |
179 }; |
163 return new_sasl(realm, getpass_authentication_profile); |
180 return new_sasl(realm, getpass_authentication_profile); |
164 end |
181 end |
165 |
182 |
166 return provider; |
183 return provider; |
167 end |
184 end |
168 |
185 |
169 module:add_item("auth-provider", new_default_provider(module.host)); |
186 module:add_item("auth-provider", new_default_provider(module.host)); |
170 |
|