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