1 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
2
3 #include "auth-common.h"
4 #include "userdb.h"
5
6 #if defined(USERDB_LDAP) && (defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD))
7
8 #include "ioloop.h"
9 #include "array.h"
10 #include "str.h"
11 #include "auth-cache.h"
12 #include "db-ldap.h"
13
14 #include <ldap.h>
15
16 struct ldap_userdb_module {
17 struct userdb_module module;
18
19 struct ldap_connection *conn;
20 };
21
22 struct userdb_ldap_request {
23 struct ldap_request_search request;
24 userdb_callback_t *userdb_callback;
25 unsigned int entries;
26 };
27
28 struct userdb_iter_ldap_request {
29 struct ldap_request_search request;
30 struct ldap_userdb_iterate_context *ctx;
31 userdb_callback_t *userdb_callback;
32 };
33
34 struct ldap_userdb_iterate_context {
35 struct userdb_iterate_context ctx;
36 struct userdb_iter_ldap_request request;
37 pool_t pool;
38 struct ldap_connection *conn;
39 bool continued, in_callback;
40 };
41
42 static void
ldap_query_get_result(struct ldap_connection * conn,struct auth_request * auth_request,struct ldap_request_search * ldap_request,LDAPMessage * res)43 ldap_query_get_result(struct ldap_connection *conn,
44 struct auth_request *auth_request,
45 struct ldap_request_search *ldap_request,
46 LDAPMessage *res)
47 {
48 struct db_ldap_result_iterate_context *ldap_iter;
49 const char *name, *const *values;
50
51 ldap_iter = db_ldap_result_iterate_init(conn, ldap_request, res, TRUE);
52 while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) {
53 auth_request_set_userdb_field_values(auth_request,
54 name, values);
55 }
56 db_ldap_result_iterate_deinit(&ldap_iter);
57 }
58
59 static void
userdb_ldap_lookup_finish(struct auth_request * auth_request,struct userdb_ldap_request * urequest,LDAPMessage * res)60 userdb_ldap_lookup_finish(struct auth_request *auth_request,
61 struct userdb_ldap_request *urequest,
62 LDAPMessage *res)
63 {
64 enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE;
65
66 if (res == NULL) {
67 result = USERDB_RESULT_INTERNAL_FAILURE;
68 } else if (urequest->entries == 0) {
69 result = USERDB_RESULT_USER_UNKNOWN;
70 auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB);
71 } else if (urequest->entries > 1) {
72 e_error(authdb_event(auth_request),
73 "user_filter matched multiple objects, aborting");
74 result = USERDB_RESULT_INTERNAL_FAILURE;
75 } else {
76 result = USERDB_RESULT_OK;
77 }
78
79 urequest->userdb_callback(result, auth_request);
80 }
81
userdb_ldap_lookup_callback(struct ldap_connection * conn,struct ldap_request * request,LDAPMessage * res)82 static void userdb_ldap_lookup_callback(struct ldap_connection *conn,
83 struct ldap_request *request,
84 LDAPMessage *res)
85 {
86 struct userdb_ldap_request *urequest =
87 (struct userdb_ldap_request *) request;
88 struct auth_request *auth_request =
89 urequest->request.request.auth_request;
90
91 if (res == NULL || ldap_msgtype(res) == LDAP_RES_SEARCH_RESULT) {
92 userdb_ldap_lookup_finish(auth_request, urequest, res);
93 auth_request_unref(&auth_request);
94 return;
95 }
96
97 if (urequest->entries++ == 0) {
98 /* first entry */
99 ldap_query_get_result(conn, auth_request,
100 &urequest->request, res);
101 }
102 }
103
userdb_ldap_lookup(struct auth_request * auth_request,userdb_callback_t * callback)104 static void userdb_ldap_lookup(struct auth_request *auth_request,
105 userdb_callback_t *callback)
106 {
107 struct userdb_module *_module = auth_request->userdb->userdb;
108 struct ldap_userdb_module *module =
109 (struct ldap_userdb_module *)_module;
110 struct ldap_connection *conn = module->conn;
111 const char **attr_names = (const char **)conn->user_attr_names;
112 struct userdb_ldap_request *request;
113 const char *error;
114 string_t *str;
115
116 auth_request_ref(auth_request);
117 request = p_new(auth_request->pool, struct userdb_ldap_request, 1);
118 request->userdb_callback = callback;
119
120 str = t_str_new(512);
121 if (auth_request_var_expand(str, conn->set.base, auth_request,
122 ldap_escape, &error) <= 0) {
123 e_error(authdb_event(auth_request),
124 "Failed to expand base=%s: %s", conn->set.base, error);
125 callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
126 return;
127 }
128 request->request.base = p_strdup(auth_request->pool, str_c(str));
129
130 str_truncate(str, 0);
131 if (auth_request_var_expand(str, conn->set.user_filter, auth_request,
132 ldap_escape, &error) <= 0) {
133 e_error(authdb_event(auth_request),
134 "Failed to expand user_filter=%s: %s",
135 conn->set.user_filter, error);
136 callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
137 return;
138 }
139 request->request.filter = p_strdup(auth_request->pool, str_c(str));
140
141 request->request.attr_map = &conn->user_attr_map;
142 request->request.attributes = conn->user_attr_names;
143
144 e_debug(authdb_event(auth_request), "user search: "
145 "base=%s scope=%s filter=%s fields=%s",
146 request->request.base, conn->set.scope,
147 request->request.filter,
148 attr_names == NULL ? "(all)" :
149 t_strarray_join(attr_names, ","));
150
151 request->request.request.auth_request = auth_request;
152 request->request.request.callback = userdb_ldap_lookup_callback;
153 db_ldap_request(conn, &request->request.request);
154 }
155
userdb_ldap_iterate_callback(struct ldap_connection * conn,struct ldap_request * request,LDAPMessage * res)156 static void userdb_ldap_iterate_callback(struct ldap_connection *conn,
157 struct ldap_request *request,
158 LDAPMessage *res)
159 {
160 struct userdb_iter_ldap_request *urequest =
161 (struct userdb_iter_ldap_request *)request;
162 struct ldap_userdb_iterate_context *ctx = urequest->ctx;
163 struct db_ldap_result_iterate_context *ldap_iter;
164 const char *name, *const *values;
165
166 if (res == NULL || ldap_msgtype(res) == LDAP_RES_SEARCH_RESULT) {
167 if (res == NULL)
168 ctx->ctx.failed = TRUE;
169 ctx->ctx.callback(NULL, ctx->ctx.context);
170 return;
171 }
172
173 /* the iteration can take a while. reset the request's create time so
174 it won't be aborted while it's still running */
175 request->create_time = ioloop_time;
176
177 ctx->in_callback = TRUE;
178 ldap_iter = db_ldap_result_iterate_init(conn, &urequest->request,
179 res, TRUE);
180 while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) {
181 if (strcmp(name, "user") != 0) {
182 e_warning(authdb_event(request->auth_request), "iterate: "
183 "Ignoring field not named 'user': %s", name);
184 continue;
185 }
186 for (; *values != NULL; values++) {
187 ctx->continued = FALSE;
188 ctx->ctx.callback(*values, ctx->ctx.context);
189 }
190 }
191 db_ldap_result_iterate_deinit(&ldap_iter);
192 if (!ctx->continued)
193 db_ldap_enable_input(conn, FALSE);
194 ctx->in_callback = FALSE;
195 }
196
197 static struct userdb_iterate_context *
userdb_ldap_iterate_init(struct auth_request * auth_request,userdb_iter_callback_t * callback,void * context)198 userdb_ldap_iterate_init(struct auth_request *auth_request,
199 userdb_iter_callback_t *callback, void *context)
200 {
201 struct userdb_module *_module = auth_request->userdb->userdb;
202 struct ldap_userdb_module *module =
203 (struct ldap_userdb_module *)_module;
204 struct ldap_connection *conn = module->conn;
205 struct ldap_userdb_iterate_context *ctx;
206 struct userdb_iter_ldap_request *request;
207 const char **attr_names = (const char **)conn->iterate_attr_names;
208 const char *error;
209 string_t *str;
210
211 ctx = p_new(auth_request->pool, struct ldap_userdb_iterate_context, 1);
212 ctx->ctx.auth_request = auth_request;
213 ctx->ctx.callback = callback;
214 ctx->ctx.context = context;
215 ctx->conn = conn;
216 request = &ctx->request;
217 request->ctx = ctx;
218
219 auth_request_ref(auth_request);
220 request->request.request.auth_request = auth_request;
221
222 str = t_str_new(512);
223 if (auth_request_var_expand(str, conn->set.base, auth_request,
224 ldap_escape, &error) <= 0) {
225 e_error(authdb_event(auth_request),
226 "Failed to expand base=%s: %s", conn->set.base, error);
227 ctx->ctx.failed = TRUE;
228 }
229 request->request.base = p_strdup(auth_request->pool, str_c(str));
230
231 str_truncate(str, 0);
232 if (auth_request_var_expand(str, conn->set.iterate_filter,
233 auth_request, ldap_escape, &error) <= 0) {
234 e_error(authdb_event(auth_request),
235 "Failed to expand iterate_filter=%s: %s",
236 conn->set.iterate_filter, error);
237 ctx->ctx.failed = TRUE;
238 }
239 request->request.filter = p_strdup(auth_request->pool, str_c(str));
240 request->request.attr_map = &conn->iterate_attr_map;
241 request->request.attributes = conn->iterate_attr_names;
242 request->request.multi_entry = TRUE;
243
244 e_debug(auth_request->event, "ldap: iterate: base=%s scope=%s filter=%s fields=%s",
245 request->request.base, conn->set.scope,
246 request->request.filter, attr_names == NULL ? "(all)" :
247 t_strarray_join(attr_names, ","));
248 request->request.request.callback = userdb_ldap_iterate_callback;
249 db_ldap_request(conn, &request->request.request);
250 return &ctx->ctx;
251 }
252
userdb_ldap_iterate_next(struct userdb_iterate_context * _ctx)253 static void userdb_ldap_iterate_next(struct userdb_iterate_context *_ctx)
254 {
255 struct ldap_userdb_iterate_context *ctx =
256 (struct ldap_userdb_iterate_context *)_ctx;
257
258 ctx->continued = TRUE;
259 if (!ctx->in_callback)
260 db_ldap_enable_input(ctx->conn, TRUE);
261 }
262
userdb_ldap_iterate_deinit(struct userdb_iterate_context * _ctx)263 static int userdb_ldap_iterate_deinit(struct userdb_iterate_context *_ctx)
264 {
265 struct ldap_userdb_iterate_context *ctx =
266 (struct ldap_userdb_iterate_context *)_ctx;
267 int ret = _ctx->failed ? -1 : 0;
268
269 db_ldap_enable_input(ctx->conn, TRUE);
270 auth_request_unref(&ctx->request.request.request.auth_request);
271 return ret;
272 }
273
274 static struct userdb_module *
userdb_ldap_preinit(pool_t pool,const char * args)275 userdb_ldap_preinit(pool_t pool, const char *args)
276 {
277 struct ldap_userdb_module *module;
278 struct ldap_connection *conn;
279
280 module = p_new(pool, struct ldap_userdb_module, 1);
281 module->conn = conn = db_ldap_init(args, TRUE);
282 p_array_init(&conn->user_attr_map, pool, 16);
283 p_array_init(&conn->iterate_attr_map, pool, 16);
284
285 db_ldap_set_attrs(conn, conn->set.user_attrs, &conn->user_attr_names,
286 &conn->user_attr_map, NULL);
287 db_ldap_set_attrs(conn, conn->set.iterate_attrs,
288 &conn->iterate_attr_names,
289 &conn->iterate_attr_map, NULL);
290 module->module.blocking = conn->set.blocking;
291 module->module.default_cache_key =
292 auth_cache_parse_key(pool,
293 t_strconcat(conn->set.base,
294 conn->set.user_attrs,
295 conn->set.user_filter, NULL));
296 return &module->module;
297 }
298
userdb_ldap_init(struct userdb_module * _module)299 static void userdb_ldap_init(struct userdb_module *_module)
300 {
301 struct ldap_userdb_module *module =
302 (struct ldap_userdb_module *)_module;
303
304 if (!module->module.blocking || worker)
305 db_ldap_connect_delayed(module->conn);
306 }
307
userdb_ldap_deinit(struct userdb_module * _module)308 static void userdb_ldap_deinit(struct userdb_module *_module)
309 {
310 struct ldap_userdb_module *module =
311 (struct ldap_userdb_module *)_module;
312
313 db_ldap_unref(&module->conn);
314 }
315
316 #ifndef PLUGIN_BUILD
317 struct userdb_module_interface userdb_ldap =
318 #else
319 struct userdb_module_interface userdb_ldap_plugin =
320 #endif
321 {
322 "ldap",
323
324 userdb_ldap_preinit,
325 userdb_ldap_init,
326 userdb_ldap_deinit,
327
328 userdb_ldap_lookup,
329
330 userdb_ldap_iterate_init,
331 userdb_ldap_iterate_next,
332 userdb_ldap_iterate_deinit
333 };
334 #else
335 struct userdb_module_interface userdb_ldap = {
336 .name = "ldap"
337 };
338 #endif
339