Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2015 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <talloc.h>
22 : #include <tevent.h>
23 :
24 : #include "util/util.h"
25 : #include "providers/ldap/sdap.h"
26 : #include "providers/ldap/sdap_async.h"
27 : #include "providers/ldap/ldap_common.h"
28 :
29 : struct sdap_search_bases_ex_state {
30 : struct tevent_context *ev;
31 : struct sdap_options *opts;
32 : struct sdap_handle *sh;
33 : const char *filter;
34 : const char **attrs;
35 : struct sdap_attr_map *map;
36 : int map_num_attrs;
37 : int timeout;
38 : bool allow_paging;
39 : bool return_first_reply;
40 :
41 : size_t base_iter;
42 : struct sdap_search_base *cur_base;
43 : struct sdap_search_base **bases;
44 :
45 : size_t reply_count;
46 : struct sysdb_attrs **reply;
47 : };
48 :
49 : static errno_t sdap_search_bases_ex_next_base(struct tevent_req *req);
50 : static void sdap_search_bases_ex_done(struct tevent_req *subreq);
51 :
52 : static struct tevent_req *
53 0 : sdap_search_bases_ex_send(TALLOC_CTX *mem_ctx,
54 : struct tevent_context *ev,
55 : struct sdap_options *opts,
56 : struct sdap_handle *sh,
57 : struct sdap_search_base **bases,
58 : struct sdap_attr_map *map,
59 : bool allow_paging,
60 : bool return_first_reply,
61 : int timeout,
62 : const char *filter,
63 : const char **attrs)
64 : {
65 : struct tevent_req *req;
66 : struct sdap_search_bases_ex_state *state;
67 : errno_t ret;
68 :
69 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_search_bases_ex_state);
70 0 : if (req == NULL) {
71 0 : return NULL;
72 : }
73 :
74 0 : if (bases == NULL) {
75 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No search base specified!\n");
76 0 : ret = ERR_INTERNAL;
77 0 : goto immediately;
78 : }
79 :
80 0 : state->ev = ev;
81 0 : state->opts = opts;
82 0 : state->sh = sh;
83 0 : state->bases = bases;
84 0 : state->map = map;
85 0 : state->filter = filter;
86 0 : state->attrs = attrs;
87 0 : state->allow_paging = allow_paging;
88 0 : state->return_first_reply = return_first_reply;
89 :
90 0 : state->timeout = timeout == 0
91 0 : ? dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT)
92 0 : : timeout;
93 :
94 0 : if (state->map != NULL) {
95 0 : for (state->map_num_attrs = 0;
96 0 : state->map[state->map_num_attrs].opt_name != NULL;
97 0 : state->map_num_attrs++) {
98 : /* no op */;
99 : }
100 : } else {
101 0 : state->map_num_attrs = 0;
102 : }
103 :
104 0 : if (state->attrs == NULL) {
105 0 : ret = build_attrs_from_map(state, state->map, state->map_num_attrs,
106 0 : NULL, &state->attrs, NULL);
107 0 : if (ret != EOK) {
108 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to build attrs from map "
109 : "[%d]: %s\n", ret, sss_strerror(ret));
110 0 : goto immediately;
111 : }
112 : }
113 :
114 0 : state->base_iter = 0;
115 0 : ret = sdap_search_bases_ex_next_base(req);
116 0 : if (ret == EAGAIN) {
117 : /* asynchronous processing */
118 0 : return req;
119 : }
120 :
121 : immediately:
122 0 : if (ret == EOK) {
123 0 : tevent_req_done(req);
124 : } else {
125 0 : tevent_req_error(req, ret);
126 : }
127 0 : tevent_req_post(req, ev);
128 :
129 0 : return req;
130 : }
131 :
132 0 : static errno_t sdap_search_bases_ex_next_base(struct tevent_req *req)
133 : {
134 : struct sdap_search_bases_ex_state *state;
135 : struct tevent_req *subreq;
136 : char *filter;
137 :
138 0 : state = tevent_req_data(req, struct sdap_search_bases_ex_state);
139 0 : state->cur_base = state->bases[state->base_iter];
140 0 : if (state->cur_base == NULL) {
141 0 : return EOK;
142 : }
143 :
144 : /* Combine lookup and search base filters. */
145 0 : filter = sdap_combine_filters(state, state->filter,
146 0 : state->cur_base->filter);
147 0 : if (filter == NULL) {
148 0 : return ENOMEM;
149 : }
150 :
151 0 : DEBUG(SSSDBG_TRACE_FUNC, "Issuing LDAP lookup with base [%s]\n",
152 : state->cur_base->basedn);
153 :
154 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
155 0 : state->cur_base->basedn,
156 0 : state->cur_base->scope, filter,
157 : state->attrs, state->map,
158 : state->map_num_attrs, state->timeout,
159 0 : state->allow_paging);
160 0 : if (subreq == NULL) {
161 0 : return ENOMEM;
162 : }
163 :
164 0 : tevent_req_set_callback(subreq, sdap_search_bases_ex_done, req);
165 :
166 0 : state->base_iter++;
167 0 : return EAGAIN;
168 : }
169 :
170 0 : static void sdap_search_bases_ex_done(struct tevent_req *subreq)
171 : {
172 : struct tevent_req *req;
173 : struct sdap_search_bases_ex_state *state;
174 : struct sysdb_attrs **attrs;
175 : size_t count;
176 : size_t i;
177 : int ret;
178 :
179 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
180 0 : state = tevent_req_data(req, struct sdap_search_bases_ex_state);
181 :
182 0 : DEBUG(SSSDBG_TRACE_FUNC, "Receiving data from base [%s]\n",
183 : state->cur_base->basedn);
184 :
185 0 : ret = sdap_get_generic_recv(subreq, state, &count, &attrs);
186 0 : talloc_zfree(subreq);
187 0 : if (ret != EOK) {
188 0 : tevent_req_error(req, ret);
189 0 : return;
190 : }
191 :
192 : /* Add rules to result. */
193 0 : if (count > 0) {
194 0 : if (state->return_first_reply == false) {
195 : /* Merge with previous reply. */
196 0 : state->reply = talloc_realloc(state, state->reply,
197 : struct sysdb_attrs *,
198 : state->reply_count + count);
199 0 : if (state->reply == NULL) {
200 0 : tevent_req_error(req, ENOMEM);
201 0 : return;
202 : }
203 :
204 0 : for (i = 0; i < count; i++) {
205 0 : state->reply[state->reply_count + i] = talloc_steal(state->reply,
206 : attrs[i]);
207 : }
208 :
209 0 : state->reply_count += count;
210 : } else {
211 : /* Return the first successful search result. */
212 0 : state->reply_count = count;
213 0 : state->reply = attrs;
214 0 : tevent_req_done(req);
215 0 : return;
216 : }
217 : }
218 :
219 : /* Try next search base. */
220 0 : ret = sdap_search_bases_ex_next_base(req);
221 0 : if (ret == EOK) {
222 0 : tevent_req_done(req);
223 0 : } else if (ret != EAGAIN) {
224 0 : tevent_req_error(req, ret);
225 : }
226 :
227 0 : return;
228 : }
229 :
230 0 : static int sdap_search_bases_ex_recv(struct tevent_req *req,
231 : TALLOC_CTX *mem_ctx,
232 : size_t *reply_count,
233 : struct sysdb_attrs ***reply)
234 : {
235 0 : struct sdap_search_bases_ex_state *state =
236 0 : tevent_req_data(req, struct sdap_search_bases_ex_state);
237 :
238 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
239 :
240 0 : *reply_count = state->reply_count;
241 0 : *reply = talloc_steal(mem_ctx, state->reply);
242 :
243 0 : return EOK;
244 : }
245 :
246 : struct tevent_req *
247 0 : sdap_search_bases_send(TALLOC_CTX *mem_ctx,
248 : struct tevent_context *ev,
249 : struct sdap_options *opts,
250 : struct sdap_handle *sh,
251 : struct sdap_search_base **bases,
252 : struct sdap_attr_map *map,
253 : bool allow_paging,
254 : int timeout,
255 : const char *filter,
256 : const char **attrs)
257 : {
258 0 : return sdap_search_bases_ex_send(mem_ctx, ev, opts, sh, bases, map,
259 : allow_paging, false, timeout,
260 : filter, attrs);
261 : }
262 :
263 0 : int sdap_search_bases_recv(struct tevent_req *req,
264 : TALLOC_CTX *mem_ctx,
265 : size_t *_reply_count,
266 : struct sysdb_attrs ***_reply)
267 : {
268 0 : return sdap_search_bases_ex_recv(req, mem_ctx, _reply_count, _reply);
269 : }
270 :
271 : struct tevent_req *
272 0 : sdap_search_bases_return_first_send(TALLOC_CTX *mem_ctx,
273 : struct tevent_context *ev,
274 : struct sdap_options *opts,
275 : struct sdap_handle *sh,
276 : struct sdap_search_base **bases,
277 : struct sdap_attr_map *map,
278 : bool allow_paging,
279 : int timeout,
280 : const char *filter,
281 : const char **attrs)
282 : {
283 0 : return sdap_search_bases_ex_send(mem_ctx, ev, opts, sh, bases, map,
284 : allow_paging, true, timeout,
285 : filter, attrs);
286 : }
287 :
288 0 : int sdap_search_bases_return_first_recv(struct tevent_req *req,
289 : TALLOC_CTX *mem_ctx,
290 : size_t *_reply_count,
291 : struct sysdb_attrs ***_reply)
292 : {
293 0 : return sdap_search_bases_ex_recv(req, mem_ctx, _reply_count, _reply);
294 : }
295 :
296 : struct sdap_deref_bases_ex_state {
297 : struct tevent_context *ev;
298 : struct sdap_options *opts;
299 : struct sdap_handle *sh;
300 : const char *filter;
301 : const char **attrs;
302 : const char *deref_attr;
303 : struct sdap_attr_map_info *maps;
304 : size_t num_maps;
305 : unsigned int flags;
306 : bool return_first_reply;
307 : int timeout;
308 :
309 : size_t base_iter;
310 : struct sdap_search_base *cur_base;
311 : struct sdap_search_base **bases;
312 :
313 : size_t reply_count;
314 : struct sdap_deref_attrs **reply;
315 : };
316 :
317 : static errno_t sdap_deref_bases_ex_next_base(struct tevent_req *req);
318 : static void sdap_deref_bases_ex_done(struct tevent_req *subreq);
319 :
320 : static struct tevent_req *
321 0 : sdap_deref_bases_ex_send(TALLOC_CTX *mem_ctx,
322 : struct tevent_context *ev,
323 : struct sdap_options *opts,
324 : struct sdap_handle *sh,
325 : struct sdap_search_base **bases,
326 : struct sdap_attr_map_info *maps,
327 : const char *filter,
328 : const char **attrs,
329 : const char *deref_attr,
330 : unsigned int flags,
331 : bool return_first_reply,
332 : int timeout)
333 : {
334 : struct tevent_req *req;
335 : struct sdap_deref_bases_ex_state *state;
336 : errno_t ret;
337 :
338 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_deref_bases_ex_state);
339 0 : if (req == NULL) {
340 0 : return NULL;
341 : }
342 :
343 0 : if (bases == NULL) {
344 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No search base specified!\n");
345 0 : ret = ERR_INTERNAL;
346 0 : goto immediately;
347 : }
348 :
349 0 : if (maps == NULL || attrs == NULL || deref_attr == NULL) {
350 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No attributes or map specified!\n");
351 0 : ret = ERR_INTERNAL;
352 0 : goto immediately;
353 : }
354 :
355 0 : state->ev = ev;
356 0 : state->opts = opts;
357 0 : state->sh = sh;
358 0 : state->bases = bases;
359 0 : state->maps = maps;
360 0 : state->filter = filter;
361 0 : state->attrs = attrs;
362 0 : state->deref_attr = deref_attr;
363 0 : state->return_first_reply = return_first_reply;
364 0 : state->flags = flags;
365 :
366 0 : state->timeout = timeout == 0
367 0 : ? dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT)
368 0 : : timeout;
369 :
370 0 : for (state->num_maps = 0; maps[state->num_maps].map != NULL;
371 0 : state->num_maps++) {
372 : /* no op */;
373 : }
374 :
375 0 : state->base_iter = 0;
376 0 : ret = sdap_deref_bases_ex_next_base(req);
377 0 : if (ret == EAGAIN) {
378 : /* asynchronous processing */
379 0 : return req;
380 : }
381 :
382 : immediately:
383 0 : if (ret == EOK) {
384 0 : tevent_req_done(req);
385 : } else {
386 0 : tevent_req_error(req, ret);
387 : }
388 0 : tevent_req_post(req, ev);
389 :
390 0 : return req;
391 : }
392 :
393 0 : static errno_t sdap_deref_bases_ex_next_base(struct tevent_req *req)
394 : {
395 : struct sdap_deref_bases_ex_state *state;
396 : struct tevent_req *subreq;
397 :
398 0 : state = tevent_req_data(req, struct sdap_deref_bases_ex_state);
399 0 : state->cur_base = state->bases[state->base_iter];
400 0 : if (state->cur_base == NULL) {
401 0 : return EOK;
402 : }
403 :
404 0 : DEBUG(SSSDBG_TRACE_FUNC, "Issuing LDAP deref lookup with base [%s]\n",
405 : state->cur_base->basedn);
406 :
407 0 : subreq = sdap_deref_search_with_filter_send(state, state->ev, state->opts,
408 0 : state->sh, state->cur_base->basedn, state->filter,
409 0 : state->deref_attr, state->attrs, state->num_maps, state->maps,
410 : state->timeout, state->flags);
411 0 : if (subreq == NULL) {
412 0 : return ENOMEM;
413 : }
414 :
415 0 : tevent_req_set_callback(subreq, sdap_deref_bases_ex_done, req);
416 :
417 0 : state->base_iter++;
418 0 : return EAGAIN;
419 : }
420 :
421 0 : static void sdap_deref_bases_ex_done(struct tevent_req *subreq)
422 : {
423 : struct tevent_req *req;
424 : struct sdap_deref_bases_ex_state *state;
425 : struct sdap_deref_attrs **attrs;
426 : size_t count;
427 : size_t i;
428 : int ret;
429 :
430 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
431 0 : state = tevent_req_data(req, struct sdap_deref_bases_ex_state);
432 :
433 0 : DEBUG(SSSDBG_TRACE_FUNC, "Receiving data from base [%s]\n",
434 : state->cur_base->basedn);
435 :
436 0 : ret = sdap_deref_search_with_filter_recv(subreq, state, &count, &attrs);
437 0 : talloc_zfree(subreq);
438 0 : if (ret != EOK) {
439 0 : tevent_req_error(req, ret);
440 0 : return;
441 : }
442 :
443 : /* Add rules to result. */
444 0 : if (count > 0) {
445 0 : if (state->return_first_reply == false) {
446 : /* Merge with previous reply. */
447 0 : state->reply = talloc_realloc(state, state->reply,
448 : struct sdap_deref_attrs *,
449 : state->reply_count + count);
450 0 : if (state->reply == NULL) {
451 0 : tevent_req_error(req, ENOMEM);
452 0 : return;
453 : }
454 :
455 0 : for (i = 0; i < count; i++) {
456 0 : state->reply[state->reply_count + i] = talloc_steal(state->reply,
457 : attrs[i]);
458 : }
459 :
460 0 : state->reply_count += count;
461 : } else {
462 : /* Return the first successful search result. */
463 0 : state->reply_count = count;
464 0 : state->reply = attrs;
465 0 : tevent_req_done(req);
466 0 : return;
467 : }
468 : }
469 :
470 : /* Try next search base. */
471 0 : ret = sdap_deref_bases_ex_next_base(req);
472 0 : if (ret == EOK) {
473 0 : tevent_req_done(req);
474 0 : } else if (ret != EAGAIN) {
475 0 : tevent_req_error(req, ret);
476 : }
477 :
478 0 : return;
479 : }
480 :
481 0 : static int sdap_deref_bases_ex_recv(struct tevent_req *req,
482 : TALLOC_CTX *mem_ctx,
483 : size_t *reply_count,
484 : struct sdap_deref_attrs ***reply)
485 : {
486 0 : struct sdap_deref_bases_ex_state *state =
487 0 : tevent_req_data(req, struct sdap_deref_bases_ex_state);
488 :
489 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
490 :
491 0 : *reply_count = state->reply_count;
492 0 : *reply = talloc_steal(mem_ctx, state->reply);
493 :
494 0 : return EOK;
495 : }
496 :
497 : struct tevent_req *
498 0 : sdap_deref_bases_send(TALLOC_CTX *mem_ctx,
499 : struct tevent_context *ev,
500 : struct sdap_options *opts,
501 : struct sdap_handle *sh,
502 : struct sdap_search_base **bases,
503 : struct sdap_attr_map_info *maps,
504 : const char *filter,
505 : const char **attrs,
506 : const char *deref_attr,
507 : unsigned int flags,
508 : int timeout)
509 : {
510 0 : return sdap_deref_bases_ex_send(mem_ctx, ev, opts, sh, bases, maps,
511 : filter, attrs, deref_attr, flags,
512 : false, timeout);
513 : }
514 :
515 0 : int sdap_deref_bases_recv(struct tevent_req *req,
516 : TALLOC_CTX *mem_ctx,
517 : size_t *_reply_count,
518 : struct sdap_deref_attrs ***_reply)
519 : {
520 0 : return sdap_deref_bases_ex_recv(req, mem_ctx, _reply_count, _reply);
521 : }
522 :
523 : struct tevent_req *
524 0 : sdap_deref_bases_return_first_send(TALLOC_CTX *mem_ctx,
525 : struct tevent_context *ev,
526 : struct sdap_options *opts,
527 : struct sdap_handle *sh,
528 : struct sdap_search_base **bases,
529 : struct sdap_attr_map_info *maps,
530 : const char *filter,
531 : const char **attrs,
532 : const char *deref_attr,
533 : unsigned int flags,
534 : int timeout)
535 : {
536 0 : return sdap_deref_bases_ex_send(mem_ctx, ev, opts, sh, bases, maps,
537 : filter, attrs, deref_attr, flags,
538 : true, timeout);
539 : }
540 :
541 0 : int sdap_deref_bases_return_first_recv(struct tevent_req *req,
542 : TALLOC_CTX *mem_ctx,
543 : size_t *_reply_count,
544 : struct sdap_deref_attrs ***_reply)
545 : {
546 0 : return sdap_deref_bases_ex_recv(req, mem_ctx, _reply_count, _reply);
547 : }
|