Line data Source code
1 : /*
2 : SSSD
3 :
4 : Async LDAP Helper routines
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 :
23 : #include <ctype.h>
24 : #include "util/util.h"
25 : #include "util/strtonum.h"
26 : #include "providers/ldap/sdap_async_private.h"
27 :
28 : #define REPLY_REALLOC_INCREMENT 10
29 :
30 : /* ==LDAP-Memory-Handling================================================= */
31 :
32 0 : static int lmsg_destructor(void *mem)
33 : {
34 0 : ldap_msgfree((LDAPMessage *)mem);
35 0 : return 0;
36 : }
37 :
38 0 : static int sdap_msg_attach(TALLOC_CTX *memctx, LDAPMessage *msg)
39 : {
40 : void *h;
41 :
42 0 : if (!msg) return EINVAL;
43 :
44 0 : h = sss_mem_attach(memctx, msg, lmsg_destructor);
45 0 : if (!h) return ENOMEM;
46 :
47 0 : return EOK;
48 : }
49 :
50 : /* ==sdap-hanlde-utility-functions======================================== */
51 :
52 : static inline void sdap_handle_release(struct sdap_handle *sh);
53 : static int sdap_handle_destructor(void *mem);
54 :
55 0 : struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx)
56 : {
57 : struct sdap_handle *sh;
58 :
59 0 : sh = talloc_zero(memctx, struct sdap_handle);
60 0 : if (!sh) return NULL;
61 :
62 0 : talloc_set_destructor((TALLOC_CTX *)sh, sdap_handle_destructor);
63 :
64 0 : return sh;
65 : }
66 :
67 0 : static int sdap_handle_destructor(void *mem)
68 : {
69 0 : struct sdap_handle *sh = talloc_get_type(mem, struct sdap_handle);
70 :
71 : /* if the structure is currently locked, then mark it to be released
72 : * and prevent talloc from freeing the memory */
73 0 : if (sh->destructor_lock) {
74 0 : sh->release_memory = true;
75 0 : return -1;
76 : }
77 :
78 0 : sdap_handle_release(sh);
79 0 : return 0;
80 : }
81 :
82 0 : static void sdap_handle_release(struct sdap_handle *sh)
83 : {
84 : struct sdap_op *op;
85 :
86 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
87 : "Trace: sh[%p], connected[%d], ops[%p], ldap[%p], "
88 : "destructor_lock[%d], release_memory[%d]\n",
89 : sh, (int)sh->connected, sh->ops, sh->ldap,
90 : (int)sh->destructor_lock, (int)sh->release_memory);
91 :
92 0 : if (sh->destructor_lock) return;
93 0 : sh->destructor_lock = true;
94 :
95 : /* make sure nobody tries to reuse this connection from now on */
96 0 : sh->connected = false;
97 :
98 0 : remove_ldap_connection_callbacks(sh);
99 :
100 0 : while (sh->ops) {
101 0 : op = sh->ops;
102 0 : op->callback(op, NULL, EIO, op->data);
103 : /* calling the callback may result in freeing the op */
104 : /* check if it is still the same or avoid freeing */
105 0 : if (op == sh->ops) talloc_free(op);
106 : }
107 :
108 0 : if (sh->ldap) {
109 0 : ldap_unbind_ext(sh->ldap, NULL, NULL);
110 0 : sh->ldap = NULL;
111 : }
112 :
113 : /* ok, we have done the job, unlock now */
114 0 : sh->destructor_lock = false;
115 :
116 : /* finally if a destructor was ever called, free sh before
117 : * exiting */
118 0 : if (sh->release_memory) {
119 : /* neutralize the destructor as we already handled
120 : * all was needed to be released */
121 0 : talloc_set_destructor((TALLOC_CTX *)sh, NULL);
122 0 : talloc_free(sh);
123 : }
124 : }
125 :
126 : /* ==Parse-Results-And-Handle-Disconnections============================== */
127 : static void sdap_process_message(struct tevent_context *ev,
128 : struct sdap_handle *sh, LDAPMessage *msg);
129 : static void sdap_process_result(struct tevent_context *ev, void *pvt);
130 : static void sdap_process_next_reply(struct tevent_context *ev,
131 : struct tevent_timer *te,
132 : struct timeval tv, void *pvt);
133 :
134 0 : void sdap_ldap_result(struct tevent_context *ev, struct tevent_fd *fde,
135 : uint16_t flags, void *pvt)
136 : {
137 0 : sdap_process_result(ev, pvt);
138 0 : }
139 :
140 0 : static void sdap_ldap_next_result(struct tevent_context *ev,
141 : struct tevent_timer *te,
142 : struct timeval tv, void *pvt)
143 : {
144 0 : sdap_process_result(ev, pvt);
145 0 : }
146 :
147 0 : static void sdap_process_result(struct tevent_context *ev, void *pvt)
148 : {
149 0 : struct sdap_handle *sh = talloc_get_type(pvt, struct sdap_handle);
150 0 : struct timeval no_timeout = {0, 0};
151 : struct tevent_timer *te;
152 : LDAPMessage *msg;
153 : int ret;
154 :
155 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
156 : "Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n",
157 : sh, (int)sh->connected, sh->ops, sh->ldap);
158 :
159 0 : if (!sh->connected || !sh->ldap) {
160 0 : DEBUG(SSSDBG_OP_FAILURE, "ERROR: LDAP connection is not connected!\n");
161 0 : sdap_handle_release(sh);
162 0 : return;
163 : }
164 :
165 0 : ret = ldap_result(sh->ldap, LDAP_RES_ANY, 0, &no_timeout, &msg);
166 0 : if (ret == 0) {
167 : /* this almost always means we have reached the end of
168 : * the list of received messages */
169 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Trace: ldap_result found nothing!\n");
170 0 : return;
171 : }
172 :
173 0 : if (ret == -1) {
174 0 : ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &ret);
175 0 : DEBUG(SSSDBG_OP_FAILURE,
176 : "ldap_result error: [%s]\n", ldap_err2string(ret));
177 0 : sdap_handle_release(sh);
178 0 : return;
179 : }
180 :
181 : /* We don't know if this will be the last result.
182 : *
183 : * important: we must do this before actually processing the message
184 : * because the message processing might even free the sdap_handler
185 : * so it must be the last operation.
186 : * FIXME: use tevent_immediate/tevent_queues, when avilable */
187 0 : memset(&no_timeout, 0, sizeof(struct timeval));
188 :
189 0 : te = tevent_add_timer(ev, sh, no_timeout, sdap_ldap_next_result, sh);
190 0 : if (!te) {
191 0 : DEBUG(SSSDBG_CRIT_FAILURE,
192 : "Failed to add critical timer to fetch next result!\n");
193 : }
194 :
195 : /* now process this message */
196 0 : sdap_process_message(ev, sh, msg);
197 : }
198 :
199 0 : static const char *sdap_ldap_result_str(int msgtype)
200 : {
201 0 : switch (msgtype) {
202 : case LDAP_RES_BIND:
203 0 : return "LDAP_RES_BIND";
204 :
205 : case LDAP_RES_SEARCH_ENTRY:
206 0 : return "LDAP_RES_SEARCH_ENTRY";
207 :
208 : case LDAP_RES_SEARCH_REFERENCE:
209 0 : return "LDAP_RES_SEARCH_REFERENCE";
210 :
211 : case LDAP_RES_SEARCH_RESULT:
212 0 : return "LDAP_RES_SEARCH_RESULT";
213 :
214 : case LDAP_RES_MODIFY:
215 0 : return "LDAP_RES_MODIFY";
216 :
217 : case LDAP_RES_ADD:
218 0 : return "LDAP_RES_ADD";
219 :
220 : case LDAP_RES_DELETE:
221 0 : return "LDAP_RES_DELETE";
222 :
223 : case LDAP_RES_MODDN:
224 : /* These are the same result
225 : case LDAP_RES_MODRDN:
226 : case LDAP_RES_RENAME:
227 : */
228 0 : return "LDAP_RES_RENAME";
229 :
230 : case LDAP_RES_COMPARE:
231 0 : return "LDAP_RES_COMPARE";
232 :
233 : case LDAP_RES_EXTENDED:
234 0 : return "LDAP_RES_EXTENDED";
235 :
236 : case LDAP_RES_INTERMEDIATE:
237 0 : return "LDAP_RES_INTERMEDIATE";
238 :
239 : case LDAP_RES_ANY:
240 0 : return "LDAP_RES_ANY";
241 :
242 : case LDAP_RES_UNSOLICITED:
243 0 : return "LDAP_RES_UNSOLICITED";
244 :
245 : default:
246 : /* Unmatched, fall through */
247 0 : break;
248 : }
249 :
250 : /* Unknown result type */
251 0 : return "Unknown result type!";
252 : }
253 :
254 : /* process a messgae calling the right operation callback.
255 : * msg is completely taken care of (including freeeing it)
256 : * NOTE: this function may even end up freeing the sdap_handle
257 : * so sdap_hanbdle must not be used after this function is called
258 : */
259 0 : static void sdap_process_message(struct tevent_context *ev,
260 : struct sdap_handle *sh, LDAPMessage *msg)
261 : {
262 : struct sdap_msg *reply;
263 : struct sdap_op *op;
264 : int msgid;
265 : int msgtype;
266 : int ret;
267 :
268 0 : msgid = ldap_msgid(msg);
269 0 : if (msgid == -1) {
270 0 : DEBUG(SSSDBG_OP_FAILURE, "can't fire callback, message id invalid!\n");
271 0 : ldap_msgfree(msg);
272 0 : return;
273 : }
274 :
275 0 : msgtype = ldap_msgtype(msg);
276 :
277 0 : for (op = sh->ops; op; op = op->next) {
278 0 : if (op->msgid == msgid) break;
279 : }
280 :
281 0 : if (op == NULL) {
282 0 : DEBUG(SSSDBG_OP_FAILURE,
283 : "Unmatched msgid, discarding message (type: %0x)\n",
284 : msgtype);
285 0 : ldap_msgfree(msg);
286 0 : return;
287 : }
288 :
289 : /* shouldn't happen */
290 0 : if (op->done) {
291 0 : DEBUG(SSSDBG_OP_FAILURE,
292 : "Operation [%p] already handled (type: %0x)\n", op, msgtype);
293 0 : ldap_msgfree(msg);
294 0 : return;
295 : }
296 :
297 0 : DEBUG(SSSDBG_TRACE_ALL,
298 : "Message type: [%s]\n", sdap_ldap_result_str(msgtype));
299 :
300 0 : switch (msgtype) {
301 : case LDAP_RES_SEARCH_ENTRY:
302 : case LDAP_RES_SEARCH_REFERENCE:
303 : /* go and process entry */
304 0 : break;
305 :
306 : case LDAP_RES_BIND:
307 : case LDAP_RES_SEARCH_RESULT:
308 : case LDAP_RES_MODIFY:
309 : case LDAP_RES_ADD:
310 : case LDAP_RES_DELETE:
311 : case LDAP_RES_MODDN:
312 : case LDAP_RES_COMPARE:
313 : case LDAP_RES_EXTENDED:
314 : case LDAP_RES_INTERMEDIATE:
315 : /* no more results expected with this msgid */
316 0 : op->done = true;
317 0 : break;
318 :
319 : default:
320 : /* unkwon msg type ?? */
321 0 : DEBUG(SSSDBG_CRIT_FAILURE,
322 : "Couldn't figure out the msg type! [%0x]\n", msgtype);
323 0 : ldap_msgfree(msg);
324 0 : return;
325 : }
326 :
327 0 : reply = talloc_zero(op, struct sdap_msg);
328 0 : if (!reply) {
329 0 : ldap_msgfree(msg);
330 0 : ret = ENOMEM;
331 : } else {
332 0 : reply->msg = msg;
333 0 : ret = sdap_msg_attach(reply, msg);
334 0 : if (ret != EOK) {
335 0 : ldap_msgfree(msg);
336 0 : talloc_zfree(reply);
337 : }
338 : }
339 :
340 0 : if (op->list) {
341 : /* list exist, queue it */
342 :
343 0 : op->last->next = reply;
344 0 : op->last = reply;
345 :
346 : } else {
347 : /* create list, then call callback */
348 0 : op->list = op->last = reply;
349 :
350 : /* must be the last operation as it may end up freeing all memory
351 : * including all ops handlers */
352 0 : op->callback(op, reply, ret, op->data);
353 : }
354 : }
355 :
356 0 : static void sdap_unlock_next_reply(struct sdap_op *op)
357 : {
358 : struct timeval tv;
359 : struct tevent_timer *te;
360 : struct sdap_msg *next_reply;
361 :
362 0 : if (op->list) {
363 0 : next_reply = op->list->next;
364 : /* get rid of the previous reply, it has been processed already */
365 0 : talloc_zfree(op->list);
366 0 : op->list = next_reply;
367 : }
368 :
369 : /* if there are still replies to parse, queue a new operation */
370 0 : if (op->list) {
371 : /* use a very small timeout, so that fd operations have a chance to be
372 : * served while processing a long reply */
373 0 : tv = tevent_timeval_current();
374 :
375 : /* wait 5 microsecond */
376 0 : tv.tv_usec += 5;
377 0 : tv.tv_sec += tv.tv_usec / 1000000;
378 0 : tv.tv_usec = tv.tv_usec % 1000000;
379 :
380 0 : te = tevent_add_timer(op->ev, op, tv,
381 : sdap_process_next_reply, op);
382 0 : if (!te) {
383 0 : DEBUG(SSSDBG_CRIT_FAILURE,
384 : "Failed to add critical timer for next reply!\n");
385 0 : op->callback(op, NULL, EFAULT, op->data);
386 : }
387 : }
388 0 : }
389 :
390 0 : static void sdap_process_next_reply(struct tevent_context *ev,
391 : struct tevent_timer *te,
392 : struct timeval tv, void *pvt)
393 : {
394 0 : struct sdap_op *op = talloc_get_type(pvt, struct sdap_op);
395 :
396 0 : op->callback(op, op->list, EOK, op->data);
397 0 : }
398 :
399 : /* ==LDAP-Operations-Helpers============================================== */
400 :
401 0 : static int sdap_op_destructor(void *mem)
402 : {
403 0 : struct sdap_op *op = (struct sdap_op *)mem;
404 :
405 0 : DLIST_REMOVE(op->sh->ops, op);
406 :
407 0 : if (op->done) {
408 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Operation %d finished\n", op->msgid);
409 0 : return 0;
410 : }
411 :
412 : /* we don't check the result here, if a message was really abandoned,
413 : * hopefully the server will get an abandon.
414 : * If the operation was already fully completed, this is going to be
415 : * just a noop */
416 0 : DEBUG(SSSDBG_TRACE_LIBS, "Abandoning operation %d\n", op->msgid);
417 0 : ldap_abandon_ext(op->sh->ldap, op->msgid, NULL, NULL);
418 :
419 0 : return 0;
420 : }
421 :
422 0 : static void sdap_op_timeout(struct tevent_req *req)
423 : {
424 0 : struct sdap_op *op = tevent_req_callback_data(req, struct sdap_op);
425 :
426 : /* should never happen, but just in case */
427 0 : if (op->done) {
428 0 : DEBUG(SSSDBG_OP_FAILURE, "Timeout happened after op was finished !?\n");
429 0 : return;
430 : }
431 :
432 : /* signal the caller that we have a timeout */
433 0 : DEBUG(SSSDBG_TRACE_LIBS, "Issuing timeout for %d\n", op->msgid);
434 0 : op->callback(op, NULL, ETIMEDOUT, op->data);
435 : }
436 :
437 0 : int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev,
438 : struct sdap_handle *sh, int msgid,
439 : sdap_op_callback_t *callback, void *data,
440 : int timeout, struct sdap_op **_op)
441 : {
442 : struct sdap_op *op;
443 :
444 0 : op = talloc_zero(memctx, struct sdap_op);
445 0 : if (!op) return ENOMEM;
446 :
447 0 : op->sh = sh;
448 0 : op->msgid = msgid;
449 0 : op->callback = callback;
450 0 : op->data = data;
451 0 : op->ev = ev;
452 :
453 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
454 : "New operation %d timeout %d\n", op->msgid, timeout);
455 :
456 : /* check if we need to set a timeout */
457 0 : if (timeout) {
458 : struct tevent_req *req;
459 : struct timeval tv;
460 :
461 0 : tv = tevent_timeval_current();
462 0 : tv = tevent_timeval_add(&tv, timeout, 0);
463 :
464 : /* allocate on op, so when it get freed the timeout is removed */
465 0 : req = tevent_wakeup_send(op, ev, tv);
466 0 : if (!req) {
467 0 : talloc_zfree(op);
468 0 : return ENOMEM;
469 : }
470 0 : tevent_req_set_callback(req, sdap_op_timeout, op);
471 : }
472 :
473 0 : DLIST_ADD(sh->ops, op);
474 :
475 0 : talloc_set_destructor((TALLOC_CTX *)op, sdap_op_destructor);
476 :
477 0 : *_op = op;
478 0 : return EOK;
479 : }
480 :
481 : /* ==Modify-Password====================================================== */
482 :
483 : struct sdap_exop_modify_passwd_state {
484 : struct sdap_handle *sh;
485 :
486 : struct sdap_op *op;
487 :
488 : char *user_error_message;
489 : };
490 :
491 : static void sdap_exop_modify_passwd_done(struct sdap_op *op,
492 : struct sdap_msg *reply,
493 : int error, void *pvt);
494 :
495 0 : struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx,
496 : struct tevent_context *ev,
497 : struct sdap_handle *sh,
498 : char *user_dn,
499 : const char *password,
500 : const char *new_password,
501 : int timeout)
502 : {
503 0 : struct tevent_req *req = NULL;
504 : struct sdap_exop_modify_passwd_state *state;
505 : int ret;
506 0 : BerElement *ber = NULL;
507 0 : struct berval *bv = NULL;
508 : int msgid;
509 0 : LDAPControl **request_controls = NULL;
510 0 : LDAPControl *ctrls[2] = { NULL, NULL };
511 :
512 0 : req = tevent_req_create(memctx, &state,
513 : struct sdap_exop_modify_passwd_state);
514 0 : if (!req) return NULL;
515 :
516 0 : state->sh = sh;
517 0 : state->user_error_message = NULL;
518 :
519 0 : ber = ber_alloc_t( LBER_USE_DER );
520 0 : if (ber == NULL) {
521 0 : DEBUG(SSSDBG_TRACE_LIBS, "ber_alloc_t failed.\n");
522 0 : talloc_zfree(req);
523 0 : return NULL;
524 : }
525 :
526 0 : ret = ber_printf( ber, "{tststs}", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
527 : user_dn,
528 : LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, password,
529 : LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, new_password);
530 0 : if (ret == -1) {
531 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ber_printf failed.\n");
532 0 : ber_free(ber, 1);
533 0 : talloc_zfree(req);
534 0 : return NULL;
535 : }
536 :
537 0 : ret = ber_flatten(ber, &bv);
538 0 : ber_free(ber, 1);
539 0 : if (ret == -1) {
540 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ber_flatten failed.\n");
541 0 : talloc_zfree(req);
542 0 : return NULL;
543 : }
544 :
545 0 : ret = sdap_control_create(state->sh, LDAP_CONTROL_PASSWORDPOLICYREQUEST,
546 : 0, NULL, 0, &ctrls[0]);
547 0 : if (ret != LDAP_SUCCESS && ret != LDAP_NOT_SUPPORTED) {
548 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_control_create failed to create "
549 : "Password Policy control.\n");
550 0 : ret = ERR_INTERNAL;
551 0 : goto fail;
552 : }
553 0 : request_controls = ctrls;
554 :
555 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Executing extended operation\n");
556 :
557 0 : ret = ldap_extended_operation(state->sh->ldap, LDAP_EXOP_MODIFY_PASSWD,
558 : bv, request_controls, NULL, &msgid);
559 0 : ber_bvfree(bv);
560 0 : if (ctrls[0]) ldap_control_free(ctrls[0]);
561 0 : if (ret == -1 || msgid == -1) {
562 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ldap_extended_operation failed\n");
563 0 : ret = ERR_NETWORK_IO;
564 0 : goto fail;
565 : }
566 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
567 : "ldap_extended_operation sent, msgid = %d\n", msgid);
568 :
569 0 : ret = sdap_op_add(state, ev, state->sh, msgid,
570 0 : sdap_exop_modify_passwd_done, req, timeout, &state->op);
571 0 : if (ret) {
572 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
573 0 : ret = ERR_INTERNAL;
574 0 : goto fail;
575 : }
576 :
577 0 : return req;
578 :
579 : fail:
580 0 : tevent_req_error(req, ret);
581 0 : tevent_req_post(req, ev);
582 0 : return req;
583 : }
584 :
585 0 : static void sdap_exop_modify_passwd_done(struct sdap_op *op,
586 : struct sdap_msg *reply,
587 : int error, void *pvt)
588 : {
589 0 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
590 0 : struct sdap_exop_modify_passwd_state *state = tevent_req_data(req,
591 : struct sdap_exop_modify_passwd_state);
592 0 : char *errmsg = NULL;
593 : int ret;
594 0 : LDAPControl **response_controls = NULL;
595 : int c;
596 : ber_int_t pp_grace;
597 : ber_int_t pp_expire;
598 : LDAPPasswordPolicyError pp_error;
599 : int result;
600 :
601 0 : if (error) {
602 0 : tevent_req_error(req, error);
603 0 : return;
604 : }
605 :
606 0 : ret = ldap_parse_result(state->sh->ldap, reply->msg,
607 : &result, NULL, &errmsg, NULL,
608 : &response_controls, 0);
609 0 : if (ret != LDAP_SUCCESS) {
610 0 : DEBUG(SSSDBG_OP_FAILURE,
611 : "ldap_parse_result failed (%d)\n", state->op->msgid);
612 0 : ret = ERR_INTERNAL;
613 0 : goto done;
614 : }
615 :
616 0 : if (response_controls == NULL) {
617 0 : DEBUG(SSSDBG_FUNC_DATA, "Server returned no controls.\n");
618 : } else {
619 0 : for (c = 0; response_controls[c] != NULL; c++) {
620 0 : DEBUG(SSSDBG_TRACE_ALL, "Server returned control [%s].\n",
621 : response_controls[c]->ldctl_oid);
622 0 : if (strcmp(response_controls[c]->ldctl_oid,
623 : LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
624 0 : ret = ldap_parse_passwordpolicy_control(state->sh->ldap,
625 0 : response_controls[c],
626 : &pp_expire, &pp_grace,
627 : &pp_error);
628 0 : if (ret != LDAP_SUCCESS) {
629 0 : DEBUG(SSSDBG_CRIT_FAILURE,
630 : "ldap_parse_passwordpolicy_control failed.\n");
631 0 : ret = ERR_NETWORK_IO;
632 0 : goto done;
633 : }
634 :
635 0 : DEBUG(SSSDBG_TRACE_LIBS,
636 : "Password Policy Response: expire [%d] grace [%d] "
637 : "error [%s].\n", pp_expire, pp_grace,
638 : ldap_passwordpolicy_err2txt(pp_error));
639 : }
640 : }
641 : }
642 :
643 0 : DEBUG(SSSDBG_MINOR_FAILURE, "ldap_extended_operation result: %s(%d), %s\n",
644 : sss_ldap_err2string(result), result, errmsg);
645 :
646 0 : switch (result) {
647 : case LDAP_SUCCESS:
648 0 : ret = EOK;
649 0 : break;
650 : case LDAP_CONSTRAINT_VIOLATION:
651 0 : if (errmsg && strlen(errmsg) != 0) {
652 0 : state->user_error_message = talloc_strdup(state, errmsg);
653 : } else {
654 0 : state->user_error_message = talloc_strdup(state,
655 : "Please make sure the password meets the "
656 : "complexity constraints.");
657 : }
658 :
659 0 : if (state->user_error_message == NULL) {
660 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed\n");
661 0 : ret = ENOMEM;
662 0 : goto done;
663 : }
664 :
665 0 : ret = ERR_CHPASS_DENIED;
666 0 : break;
667 : default:
668 0 : if (errmsg) {
669 0 : state->user_error_message = talloc_strdup(state, errmsg);
670 0 : if (state->user_error_message == NULL) {
671 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
672 0 : ret = ENOMEM;
673 0 : goto done;
674 : }
675 : }
676 0 : ret = ERR_NETWORK_IO;
677 0 : break;
678 : }
679 :
680 : done:
681 0 : ldap_controls_free(response_controls);
682 0 : ldap_memfree(errmsg);
683 :
684 0 : if (ret == EOK) {
685 0 : tevent_req_done(req);
686 : } else {
687 0 : tevent_req_error(req, ret);
688 : }
689 : }
690 :
691 0 : errno_t sdap_exop_modify_passwd_recv(struct tevent_req *req,
692 : TALLOC_CTX * mem_ctx,
693 : char **user_error_message)
694 : {
695 0 : struct sdap_exop_modify_passwd_state *state = tevent_req_data(req,
696 : struct sdap_exop_modify_passwd_state);
697 :
698 0 : *user_error_message = talloc_steal(mem_ctx, state->user_error_message);
699 :
700 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
701 :
702 0 : return EOK;
703 : }
704 :
705 : /* ==Update-passwordLastChanged-attribute====================== */
706 : struct update_last_changed_state {
707 : struct tevent_context *ev;
708 : struct sdap_handle *sh;
709 : struct sdap_op *op;
710 :
711 : const char *dn;
712 : LDAPMod **mods;
713 : };
714 :
715 : static void sdap_modify_shadow_lastchange_done(struct sdap_op *op,
716 : struct sdap_msg *reply,
717 : int error, void *pvt);
718 :
719 : struct tevent_req *
720 0 : sdap_modify_shadow_lastchange_send(TALLOC_CTX *mem_ctx,
721 : struct tevent_context *ev,
722 : struct sdap_handle *sh,
723 : const char *dn,
724 : char *lastchanged_name)
725 : {
726 : struct tevent_req *req;
727 : struct update_last_changed_state *state;
728 : char **values;
729 : errno_t ret;
730 : int msgid;
731 :
732 0 : req = tevent_req_create(mem_ctx, &state, struct update_last_changed_state);
733 0 : if (req == NULL) {
734 0 : return NULL;
735 : }
736 :
737 0 : state->ev = ev;
738 0 : state->sh = sh;
739 0 : state->dn = dn;
740 0 : state->mods = talloc_zero_array(state, LDAPMod *, 2);
741 0 : if (state->mods == NULL) {
742 0 : ret = ENOMEM;
743 0 : goto done;
744 : }
745 0 : state->mods[0] = talloc_zero(state->mods, LDAPMod);
746 0 : state->mods[1] = talloc_zero(state->mods, LDAPMod);
747 0 : if (!state->mods[0] || !state->mods[1]) {
748 0 : ret = ENOMEM;
749 0 : goto done;
750 : }
751 0 : values = talloc_zero_array(state->mods[0], char *, 2);
752 0 : if (values == NULL) {
753 0 : ret = ENOMEM;
754 0 : goto done;
755 : }
756 : /* The attribute contains number of days since the epoch */
757 0 : values[0] = talloc_asprintf(values, "%ld", (long)time(NULL)/86400);
758 0 : if (values[0] == NULL) {
759 0 : ret = ENOMEM;
760 0 : goto done;
761 : }
762 0 : state->mods[0]->mod_op = LDAP_MOD_REPLACE;
763 0 : state->mods[0]->mod_type = lastchanged_name;
764 0 : state->mods[0]->mod_vals.modv_strvals = values;
765 0 : state->mods[1] = NULL;
766 :
767 0 : ret = ldap_modify_ext(state->sh->ldap, state->dn, state->mods,
768 : NULL, NULL, &msgid);
769 0 : if (ret) {
770 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to send operation!\n");
771 0 : goto done;
772 : }
773 :
774 0 : ret = sdap_op_add(state, state->ev, state->sh, msgid,
775 0 : sdap_modify_shadow_lastchange_done, req, 5, &state->op);
776 0 : if (ret) {
777 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
778 0 : goto done;
779 : }
780 :
781 : done:
782 0 : if (ret != EOK) {
783 0 : tevent_req_error(req, ret);
784 0 : tevent_req_post(req, ev);
785 : }
786 0 : return req;
787 : }
788 :
789 0 : static void sdap_modify_shadow_lastchange_done(struct sdap_op *op,
790 : struct sdap_msg *reply,
791 : int error, void *pvt)
792 : {
793 0 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
794 : struct update_last_changed_state *state;
795 0 : state = tevent_req_data(req, struct update_last_changed_state);
796 : char *errmsg;
797 : int result;
798 0 : errno_t ret = EOK;
799 : int lret;
800 :
801 0 : if (error) {
802 0 : tevent_req_error(req, error);
803 0 : return;
804 : }
805 :
806 0 : lret = ldap_parse_result(state->sh->ldap, reply->msg,
807 : &result, NULL, &errmsg, NULL,
808 : NULL, 0);
809 0 : if (lret != LDAP_SUCCESS) {
810 0 : DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed (%d)\n",
811 : state->op->msgid);
812 0 : ret = EIO;
813 0 : goto done;
814 : }
815 :
816 0 : DEBUG(SSSDBG_TRACE_LIBS, "Updating lastPwdChange result: %s(%d), %s\n",
817 : sss_ldap_err2string(result),
818 : result, errmsg);
819 :
820 : done:
821 0 : ldap_memfree(errmsg);
822 :
823 0 : if (ret == EOK) {
824 0 : tevent_req_done(req);
825 : } else {
826 0 : tevent_req_error(req, ret);
827 : }
828 : }
829 :
830 0 : errno_t sdap_modify_shadow_lastchange_recv(struct tevent_req *req)
831 : {
832 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
833 :
834 0 : return EOK;
835 : }
836 :
837 :
838 : /* ==Fetch-RootDSE============================================= */
839 :
840 : struct sdap_get_rootdse_state {
841 : struct tevent_context *ev;
842 : struct sdap_options *opts;
843 : struct sdap_handle *sh;
844 :
845 : struct sysdb_attrs *rootdse;
846 : };
847 :
848 : static void sdap_get_rootdse_done(struct tevent_req *subreq);
849 : static void sdap_get_matching_rule_done(struct tevent_req *subreq);
850 :
851 0 : struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx,
852 : struct tevent_context *ev,
853 : struct sdap_options *opts,
854 : struct sdap_handle *sh)
855 : {
856 : struct tevent_req *req, *subreq;
857 : struct sdap_get_rootdse_state *state;
858 0 : const char *attrs[] = {
859 : "*",
860 : "altServer",
861 : SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS,
862 : "supportedControl",
863 : "supportedExtension",
864 : "supportedFeatures",
865 : "supportedLDAPVersion",
866 : "supportedSASLMechanisms",
867 : SDAP_ROOTDSE_ATTR_AD_VERSION,
868 : SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT,
869 : SDAP_IPA_LAST_USN, SDAP_AD_LAST_USN,
870 : NULL
871 : };
872 :
873 0 : DEBUG(SSSDBG_TRACE_ALL, "Getting rootdse\n");
874 :
875 0 : req = tevent_req_create(memctx, &state, struct sdap_get_rootdse_state);
876 0 : if (!req) return NULL;
877 :
878 0 : state->ev = ev;
879 0 : state->opts = opts;
880 0 : state->sh = sh;
881 0 : state->rootdse = NULL;
882 :
883 0 : subreq = sdap_get_generic_send(state, ev, opts, sh,
884 : "", LDAP_SCOPE_BASE,
885 : "(objectclass=*)", attrs, NULL, 0,
886 0 : dp_opt_get_int(state->opts->basic,
887 : SDAP_SEARCH_TIMEOUT),
888 : false);
889 0 : if (!subreq) {
890 0 : talloc_zfree(req);
891 0 : return NULL;
892 : }
893 0 : tevent_req_set_callback(subreq, sdap_get_rootdse_done, req);
894 :
895 0 : return req;
896 : }
897 :
898 : /* This is not a real attribute, it's just there to avoid
899 : * actually pulling real data down, to save bandwidth
900 : */
901 : #define SDAP_MATCHING_RULE_TEST_ATTR "sssmatchingruletest"
902 :
903 0 : static void sdap_get_rootdse_done(struct tevent_req *subreq)
904 : {
905 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
906 : struct tevent_req);
907 0 : struct sdap_get_rootdse_state *state = tevent_req_data(req,
908 : struct sdap_get_rootdse_state);
909 : struct sysdb_attrs **results;
910 : size_t num_results;
911 : int ret;
912 : const char *filter;
913 0 : const char *attrs[] = { SDAP_MATCHING_RULE_TEST_ATTR, NULL };
914 :
915 0 : ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
916 0 : talloc_zfree(subreq);
917 0 : if (ret) {
918 0 : tevent_req_error(req, ret);
919 0 : return;
920 : }
921 :
922 0 : if (num_results == 0 || !results) {
923 0 : DEBUG(SSSDBG_OP_FAILURE, "RootDSE could not be retrieved. "
924 : "Please check that anonymous access to RootDSE is allowed\n"
925 : );
926 0 : tevent_req_error(req, ENOENT);
927 0 : return;
928 : }
929 :
930 0 : if (num_results > 1) {
931 0 : DEBUG(SSSDBG_OP_FAILURE,
932 : "Multiple replies when searching for RootDSE ??\n");
933 0 : tevent_req_error(req, EIO);
934 0 : return;
935 : }
936 :
937 0 : state->rootdse = talloc_steal(state, results[0]);
938 0 : talloc_zfree(results);
939 :
940 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Got rootdse\n");
941 :
942 : /* Auto-detect the ldap matching rule if requested */
943 0 : if ((!dp_opt_get_bool(state->opts->basic,
944 : SDAP_AD_MATCHING_RULE_INITGROUPS))
945 0 : && !dp_opt_get_bool(state->opts->basic,
946 : SDAP_AD_MATCHING_RULE_GROUPS)) {
947 : /* This feature is disabled for both groups
948 : * and initgroups. Skip the auto-detection
949 : * lookup.
950 : */
951 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
952 : "Skipping auto-detection of match rule\n");
953 0 : tevent_req_done(req);
954 0 : return;
955 : }
956 :
957 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
958 : "Auto-detecting support for match rule\n");
959 :
960 : /* Create a filter using the matching rule. It need not point
961 : * at any valid data. We're only going to be looking for the
962 : * error code.
963 : */
964 0 : filter = "("SDAP_MATCHING_RULE_TEST_ATTR":"
965 : SDAP_MATCHING_RULE_IN_CHAIN":=)";
966 :
967 : /* Perform a trivial query with the matching rule in play.
968 : * If it returns success, we know it is available. If it
969 : * returns EIO, we know it isn't.
970 : */
971 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
972 : "", LDAP_SCOPE_BASE, filter, attrs, NULL,
973 0 : 0, dp_opt_get_int(state->opts->basic,
974 : SDAP_SEARCH_TIMEOUT),
975 : false);
976 0 : if (!subreq) {
977 0 : tevent_req_error(req, ENOMEM);
978 0 : return;
979 : }
980 0 : tevent_req_set_callback(subreq, sdap_get_matching_rule_done, req);
981 : }
982 :
983 0 : static void sdap_get_matching_rule_done(struct tevent_req *subreq)
984 : {
985 : errno_t ret;
986 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
987 : struct tevent_req);
988 0 : struct sdap_get_rootdse_state *state = tevent_req_data(req,
989 : struct sdap_get_rootdse_state);
990 : size_t num_results;
991 : struct sysdb_attrs **results;
992 :
993 0 : ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
994 0 : talloc_zfree(subreq);
995 0 : if (ret == EOK) {
996 : /* The search succeeded */
997 0 : state->opts->support_matching_rule = true;
998 0 : } else if (ret == EIO) {
999 : /* The search failed. Disable support for
1000 : * matching rule lookups.
1001 : */
1002 0 : state->opts->support_matching_rule = false;
1003 : } else {
1004 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1005 : "Unexpected error while testing for matching rule support\n");
1006 0 : tevent_req_error(req, ret);
1007 0 : return;
1008 : }
1009 :
1010 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1011 : "LDAP server %s the matching rule extension\n",
1012 : state->opts->support_matching_rule
1013 : ? "supports"
1014 : : "does not support");
1015 :
1016 0 : tevent_req_done(req);
1017 : }
1018 :
1019 0 : int sdap_get_rootdse_recv(struct tevent_req *req,
1020 : TALLOC_CTX *memctx,
1021 : struct sysdb_attrs **rootdse)
1022 : {
1023 0 : struct sdap_get_rootdse_state *state = tevent_req_data(req,
1024 : struct sdap_get_rootdse_state);
1025 :
1026 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1027 :
1028 0 : *rootdse = talloc_steal(memctx, state->rootdse);
1029 :
1030 0 : return EOK;
1031 : }
1032 :
1033 : /* ==Helpers for parsing replies============================== */
1034 : struct sdap_reply {
1035 : size_t reply_max;
1036 : size_t reply_count;
1037 : struct sysdb_attrs **reply;
1038 : };
1039 :
1040 0 : static errno_t add_to_reply(TALLOC_CTX *mem_ctx,
1041 : struct sdap_reply *sreply,
1042 : struct sysdb_attrs *msg)
1043 : {
1044 0 : if (sreply->reply == NULL || sreply->reply_max == sreply->reply_count) {
1045 0 : sreply->reply_max += REPLY_REALLOC_INCREMENT;
1046 0 : sreply->reply = talloc_realloc(mem_ctx, sreply->reply,
1047 : struct sysdb_attrs *,
1048 : sreply->reply_max);
1049 0 : if (sreply->reply == NULL) {
1050 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc failed.\n");
1051 0 : return ENOMEM;
1052 : }
1053 : }
1054 :
1055 0 : sreply->reply[sreply->reply_count++] = talloc_steal(sreply->reply, msg);
1056 :
1057 0 : return EOK;
1058 : }
1059 :
1060 : struct sdap_deref_reply {
1061 : size_t reply_max;
1062 : size_t reply_count;
1063 : struct sdap_deref_attrs **reply;
1064 : };
1065 :
1066 0 : static errno_t add_to_deref_reply(TALLOC_CTX *mem_ctx,
1067 : int num_maps,
1068 : struct sdap_deref_reply *dreply,
1069 : struct sdap_deref_attrs **res)
1070 : {
1071 : int i;
1072 :
1073 0 : if (res == NULL) {
1074 : /* Nothing to add, probably ACIs prevented us from dereferencing
1075 : * the attribute */
1076 0 : return EOK;
1077 : }
1078 :
1079 0 : for (i=0; i < num_maps; i++) {
1080 0 : if (res[i]->attrs == NULL) continue; /* Nothing in this map */
1081 :
1082 0 : if (dreply->reply == NULL ||
1083 0 : dreply->reply_max == dreply->reply_count) {
1084 0 : dreply->reply_max += REPLY_REALLOC_INCREMENT;
1085 0 : dreply->reply = talloc_realloc(mem_ctx, dreply->reply,
1086 : struct sdap_deref_attrs *,
1087 : dreply->reply_max);
1088 0 : if (dreply->reply == NULL) {
1089 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc failed.\n");
1090 0 : return ENOMEM;
1091 : }
1092 : }
1093 :
1094 0 : dreply->reply[dreply->reply_count++] =
1095 0 : talloc_steal(dreply->reply, res[i]);
1096 : }
1097 :
1098 0 : return EOK;
1099 : }
1100 :
1101 0 : static void sdap_print_server(struct sdap_handle *sh)
1102 : {
1103 : int ret;
1104 : int fd;
1105 : struct sockaddr_storage ss;
1106 0 : socklen_t ss_len = sizeof(ss);
1107 : char ip[NI_MAXHOST];
1108 :
1109 0 : if (!DEBUG_IS_SET(SSSDBG_TRACE_INTERNAL)) {
1110 0 : return;
1111 : }
1112 :
1113 0 : ret = get_fd_from_ldap(sh->ldap, &fd);
1114 0 : if (ret != EOK) {
1115 0 : DEBUG(SSSDBG_MINOR_FAILURE, "cannot get sdap fd\n");
1116 0 : return;
1117 : }
1118 :
1119 0 : ret = getpeername(fd, (struct sockaddr *) &ss, &ss_len);
1120 0 : if (ret == -1) {
1121 0 : DEBUG(SSSDBG_MINOR_FAILURE, "getsockname failed\n");
1122 0 : return;
1123 : }
1124 :
1125 0 : ret = getnameinfo((struct sockaddr *) &ss, ss_len,
1126 : ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
1127 0 : if (ret != 0) {
1128 0 : DEBUG(SSSDBG_MINOR_FAILURE, "getnameinfo failed\n");
1129 0 : return;
1130 : }
1131 :
1132 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Searching %s\n", ip);
1133 : }
1134 :
1135 : /* ==Generic Search exposing all options======================= */
1136 : typedef errno_t (*sdap_parse_cb)(struct sdap_handle *sh,
1137 : struct sdap_msg *msg,
1138 : void *pvt);
1139 :
1140 : struct sdap_get_generic_ext_state {
1141 : struct tevent_context *ev;
1142 : struct sdap_options *opts;
1143 : struct sdap_handle *sh;
1144 : const char *search_base;
1145 : int scope;
1146 : const char *filter;
1147 : const char **attrs;
1148 : int timeout;
1149 : int attrsonly;
1150 : int sizelimit;
1151 :
1152 : struct sdap_op *op;
1153 :
1154 : struct berval cookie;
1155 :
1156 : LDAPControl **serverctrls;
1157 : int nserverctrls;
1158 : LDAPControl **clientctrls;
1159 :
1160 : size_t ref_count;
1161 : char **refs;
1162 :
1163 : sdap_parse_cb parse_cb;
1164 : void *cb_data;
1165 :
1166 : bool allow_paging;
1167 : };
1168 :
1169 : static errno_t sdap_get_generic_ext_step(struct tevent_req *req);
1170 :
1171 : static void sdap_get_generic_op_finished(struct sdap_op *op,
1172 : struct sdap_msg *reply,
1173 : int error, void *pvt);
1174 :
1175 : static struct tevent_req *
1176 0 : sdap_get_generic_ext_send(TALLOC_CTX *memctx,
1177 : struct tevent_context *ev,
1178 : struct sdap_options *opts,
1179 : struct sdap_handle *sh,
1180 : const char *search_base,
1181 : int scope,
1182 : const char *filter,
1183 : const char **attrs,
1184 : int attrsonly,
1185 : LDAPControl **serverctrls,
1186 : LDAPControl **clientctrls,
1187 : int sizelimit,
1188 : int timeout,
1189 : bool allow_paging,
1190 : sdap_parse_cb parse_cb,
1191 : void *cb_data)
1192 : {
1193 : errno_t ret;
1194 : struct sdap_get_generic_ext_state *state;
1195 : struct tevent_req *req;
1196 : int i;
1197 : LDAPControl *control;
1198 :
1199 0 : req = tevent_req_create(memctx, &state, struct sdap_get_generic_ext_state);
1200 0 : if (!req) return NULL;
1201 :
1202 0 : state->ev = ev;
1203 0 : state->opts = opts;
1204 0 : state->sh = sh;
1205 0 : state->search_base = search_base;
1206 0 : state->scope = scope;
1207 0 : state->filter = filter;
1208 0 : state->attrs = attrs;
1209 0 : state->attrsonly = attrsonly;
1210 0 : state->op = NULL;
1211 0 : state->sizelimit = sizelimit;
1212 0 : state->timeout = timeout;
1213 0 : state->cookie.bv_len = 0;
1214 0 : state->cookie.bv_val = NULL;
1215 0 : state->parse_cb = parse_cb;
1216 0 : state->cb_data = cb_data;
1217 0 : state->clientctrls = clientctrls;
1218 :
1219 0 : if (state->sh == NULL || state->sh->ldap == NULL) {
1220 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1221 : "Trying LDAP search while not connected.\n");
1222 0 : tevent_req_error(req, EIO);
1223 0 : tevent_req_post(req, ev);
1224 0 : return req;
1225 : }
1226 :
1227 0 : sdap_print_server(sh);
1228 :
1229 : /* Be extra careful and never allow paging for BASE searches,
1230 : * even if requested.
1231 : */
1232 0 : if (scope == LDAP_SCOPE_BASE) {
1233 0 : state->allow_paging = false;
1234 : } else {
1235 0 : state->allow_paging = allow_paging;
1236 : }
1237 :
1238 : /* Also check for deref/asq requests and force
1239 : * paging on for those requests
1240 : */
1241 : /* X-DEREF */
1242 0 : control = ldap_control_find(LDAP_CONTROL_X_DEREF,
1243 : serverctrls,
1244 : NULL);
1245 0 : if (control) {
1246 0 : state->allow_paging = true;
1247 : }
1248 :
1249 : /* ASQ */
1250 0 : control = ldap_control_find(LDAP_SERVER_ASQ_OID,
1251 : serverctrls,
1252 : NULL);
1253 0 : if (control) {
1254 0 : state->allow_paging = true;
1255 : }
1256 :
1257 0 : for (state->nserverctrls=0;
1258 0 : serverctrls && serverctrls[state->nserverctrls];
1259 0 : state->nserverctrls++) ;
1260 :
1261 : /* One extra space for NULL, one for page control */
1262 0 : state->serverctrls = talloc_array(state, LDAPControl *,
1263 : state->nserverctrls+2);
1264 0 : if (!state->serverctrls) {
1265 0 : tevent_req_error(req, ENOMEM);
1266 0 : tevent_req_post(req, ev);
1267 0 : return req;
1268 : }
1269 :
1270 0 : for (i=0; i < state->nserverctrls; i++) {
1271 0 : state->serverctrls[i] = serverctrls[i];
1272 : }
1273 0 : state->serverctrls[i] = NULL;
1274 :
1275 0 : ret = sdap_get_generic_ext_step(req);
1276 0 : if (ret != EOK) {
1277 0 : tevent_req_error(req, ret);
1278 0 : tevent_req_post(req, ev);
1279 0 : return req;
1280 : }
1281 :
1282 0 : return req;
1283 : }
1284 :
1285 0 : static errno_t sdap_get_generic_ext_step(struct tevent_req *req)
1286 : {
1287 0 : struct sdap_get_generic_ext_state *state =
1288 0 : tevent_req_data(req, struct sdap_get_generic_ext_state);
1289 : char *errmsg;
1290 : int lret;
1291 : int optret;
1292 : errno_t ret;
1293 : int msgid;
1294 : bool disable_paging;
1295 :
1296 0 : LDAPControl *page_control = NULL;
1297 :
1298 : /* Make sure to free any previous operations so
1299 : * if we are handling a large number of pages we
1300 : * don't waste memory.
1301 : */
1302 0 : talloc_zfree(state->op);
1303 :
1304 0 : DEBUG(SSSDBG_TRACE_FUNC,
1305 : "calling ldap_search_ext with [%s][%s].\n",
1306 : state->filter ? state->filter : "no filter",
1307 : state->search_base);
1308 0 : if (DEBUG_IS_SET(SSSDBG_TRACE_LIBS)) {
1309 : int i;
1310 :
1311 0 : if (state->attrs) {
1312 0 : for (i = 0; state->attrs[i]; i++) {
1313 0 : DEBUG(SSSDBG_TRACE_LIBS,
1314 : "Requesting attrs: [%s]\n", state->attrs[i]);
1315 : }
1316 : }
1317 : }
1318 :
1319 0 : disable_paging = dp_opt_get_bool(state->opts->basic, SDAP_DISABLE_PAGING);
1320 :
1321 0 : if (!disable_paging
1322 0 : && state->allow_paging
1323 0 : && sdap_is_control_supported(state->sh,
1324 : LDAP_CONTROL_PAGEDRESULTS)) {
1325 0 : lret = ldap_create_page_control(state->sh->ldap,
1326 0 : state->sh->page_size,
1327 0 : state->cookie.bv_val ?
1328 : &state->cookie :
1329 : NULL,
1330 : false,
1331 : &page_control);
1332 0 : if (lret != LDAP_SUCCESS) {
1333 0 : ret = EIO;
1334 0 : goto done;
1335 : }
1336 0 : state->serverctrls[state->nserverctrls] = page_control;
1337 0 : state->serverctrls[state->nserverctrls+1] = NULL;
1338 : }
1339 :
1340 0 : lret = ldap_search_ext(state->sh->ldap, state->search_base,
1341 : state->scope, state->filter,
1342 0 : discard_const(state->attrs),
1343 : state->attrsonly, state->serverctrls,
1344 : state->clientctrls, NULL, state->sizelimit, &msgid);
1345 0 : ldap_control_free(page_control);
1346 0 : state->serverctrls[state->nserverctrls] = NULL;
1347 0 : if (lret != LDAP_SUCCESS) {
1348 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1349 : "ldap_search_ext failed: %s\n", sss_ldap_err2string(lret));
1350 0 : if (lret == LDAP_SERVER_DOWN) {
1351 0 : ret = ETIMEDOUT;
1352 0 : optret = sss_ldap_get_diagnostic_msg(state, state->sh->ldap,
1353 : &errmsg);
1354 0 : if (optret == LDAP_SUCCESS) {
1355 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Connection error: %s\n", errmsg);
1356 0 : sss_log(SSS_LOG_ERR, "LDAP connection error: %s", errmsg);
1357 : }
1358 : else {
1359 0 : sss_log(SSS_LOG_ERR, "LDAP connection error, %s",
1360 : sss_ldap_err2string(lret));
1361 : }
1362 0 : } else if (lret == LDAP_FILTER_ERROR) {
1363 0 : ret = ERR_INVALID_FILTER;
1364 : } else {
1365 0 : ret = EIO;
1366 : }
1367 0 : goto done;
1368 : }
1369 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "ldap_search_ext called, msgid = %d\n", msgid);
1370 :
1371 0 : ret = sdap_op_add(state, state->ev, state->sh, msgid,
1372 : sdap_get_generic_op_finished, req,
1373 : state->timeout,
1374 : &state->op);
1375 0 : if (ret != EOK) {
1376 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
1377 0 : goto done;
1378 : }
1379 :
1380 : done:
1381 0 : return ret;
1382 : }
1383 :
1384 : static errno_t
1385 0 : sdap_get_generic_ext_add_references(struct sdap_get_generic_ext_state *state,
1386 : char **refs)
1387 : {
1388 : int i;
1389 :
1390 0 : if (refs == NULL) {
1391 : /* Rare, but it's possible that we might get a reference result with
1392 : * no references attached.
1393 : */
1394 0 : return EOK;
1395 : }
1396 :
1397 0 : for (i = 0; refs[i]; i++) {
1398 0 : DEBUG(SSSDBG_TRACE_LIBS, "Additional References: %s\n", refs[i]);
1399 : }
1400 :
1401 : /* Extend the size of the ref array */
1402 0 : state->refs = talloc_realloc(state, state->refs, char *,
1403 : state->ref_count + i);
1404 0 : if (state->refs == NULL) {
1405 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1406 : "talloc_realloc failed extending ref_array.\n");
1407 0 : return ENOMEM;
1408 : }
1409 :
1410 : /* Copy in all the references */
1411 0 : for (i = 0; refs[i]; i++) {
1412 0 : state->refs[state->ref_count + i] =
1413 0 : talloc_strdup(state->refs, refs[i]);
1414 :
1415 0 : if (state->refs[state->ref_count + i] == NULL) {
1416 0 : return ENOMEM;
1417 : }
1418 : }
1419 :
1420 0 : state->ref_count += i;
1421 :
1422 0 : return EOK;
1423 : }
1424 :
1425 0 : static void sdap_get_generic_op_finished(struct sdap_op *op,
1426 : struct sdap_msg *reply,
1427 : int error, void *pvt)
1428 : {
1429 0 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
1430 0 : struct sdap_get_generic_ext_state *state = tevent_req_data(req,
1431 : struct sdap_get_generic_ext_state);
1432 0 : char *errmsg = NULL;
1433 0 : char **refs = NULL;
1434 : int result;
1435 : int ret;
1436 : int lret;
1437 : ber_int_t total_count;
1438 : struct berval cookie;
1439 0 : LDAPControl **returned_controls = NULL;
1440 : LDAPControl *page_control;
1441 :
1442 0 : if (error) {
1443 0 : tevent_req_error(req, error);
1444 0 : return;
1445 : }
1446 :
1447 0 : switch (ldap_msgtype(reply->msg)) {
1448 : case LDAP_RES_SEARCH_REFERENCE:
1449 0 : ret = ldap_parse_reference(state->sh->ldap, reply->msg,
1450 : &refs, NULL, 0);
1451 0 : if (ret != LDAP_SUCCESS) {
1452 0 : DEBUG(SSSDBG_OP_FAILURE,
1453 : "ldap_parse_reference failed (%d)\n", state->op->msgid);
1454 0 : tevent_req_error(req, EIO);
1455 0 : return;
1456 : }
1457 :
1458 0 : ret = sdap_get_generic_ext_add_references(state, refs);
1459 0 : if (ret != EOK) {
1460 0 : DEBUG(SSSDBG_OP_FAILURE,
1461 : "sdap_get_generic_ext_add_references failed: %s(%d)",
1462 : sss_strerror(ret), ret);
1463 0 : ldap_memvfree((void **)refs);
1464 0 : tevent_req_error(req, ret);
1465 0 : return;
1466 : }
1467 :
1468 : /* Remove the original strings */
1469 0 : ldap_memvfree((void **)refs);
1470 :
1471 : /* unlock the operation so that we can proceed with the next result */
1472 0 : sdap_unlock_next_reply(state->op);
1473 0 : break;
1474 :
1475 : case LDAP_RES_SEARCH_ENTRY:
1476 0 : ret = state->parse_cb(state->sh, reply, state->cb_data);
1477 0 : if (ret != EOK) {
1478 0 : DEBUG(SSSDBG_CRIT_FAILURE, "reply parsing callback failed.\n");
1479 0 : tevent_req_error(req, ret);
1480 0 : return;
1481 : }
1482 :
1483 0 : sdap_unlock_next_reply(state->op);
1484 0 : break;
1485 :
1486 : case LDAP_RES_SEARCH_RESULT:
1487 0 : ret = ldap_parse_result(state->sh->ldap, reply->msg,
1488 : &result, NULL, &errmsg, &refs,
1489 : &returned_controls, 0);
1490 0 : if (ret != LDAP_SUCCESS) {
1491 0 : DEBUG(SSSDBG_OP_FAILURE,
1492 : "ldap_parse_result failed (%d)\n", state->op->msgid);
1493 0 : tevent_req_error(req, EIO);
1494 0 : return;
1495 : }
1496 :
1497 0 : DEBUG(SSSDBG_TRACE_FUNC, "Search result: %s(%d), %s\n",
1498 : sss_ldap_err2string(result), result,
1499 : errmsg ? errmsg : "no errmsg set");
1500 :
1501 0 : if (result == LDAP_SIZELIMIT_EXCEEDED) {
1502 : /* Try to return what we've got */
1503 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1504 : "LDAP sizelimit was exceeded, returning incomplete data\n");
1505 0 : } else if (result == LDAP_INAPPROPRIATE_MATCHING) {
1506 : /* This error should only occur when we're testing for
1507 : * specialized functionality like the ldap matching rule
1508 : * filter for Active Directory. Warn at a higher log
1509 : * level and return EIO.
1510 : */
1511 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1512 : "LDAP_INAPPROPRIATE_MATCHING: %s\n",
1513 : errmsg ? errmsg : "no errmsg set");
1514 0 : ldap_memfree(errmsg);
1515 0 : tevent_req_error(req, EIO);
1516 0 : return;
1517 0 : } else if (result == LDAP_UNAVAILABLE_CRITICAL_EXTENSION) {
1518 0 : ldap_memfree(errmsg);
1519 0 : tevent_req_error(req, ENOTSUP);
1520 0 : return;
1521 0 : } else if (result == LDAP_REFERRAL) {
1522 0 : ret = sdap_get_generic_ext_add_references(state, refs);
1523 0 : if (ret != EOK) {
1524 0 : DEBUG(SSSDBG_OP_FAILURE,
1525 : "sdap_get_generic_ext_add_references failed: %s(%d)",
1526 : sss_strerror(ret), ret);
1527 0 : tevent_req_error(req, ret);
1528 : }
1529 : /* For referrals, we need to fall through as if it was LDAP_SUCCESS */
1530 0 : } else if (result != LDAP_SUCCESS && result != LDAP_NO_SUCH_OBJECT) {
1531 0 : DEBUG(SSSDBG_OP_FAILURE,
1532 : "Unexpected result from ldap: %s(%d), %s\n",
1533 : sss_ldap_err2string(result), result,
1534 : errmsg ? errmsg : "no errmsg set");
1535 0 : ldap_memfree(errmsg);
1536 0 : tevent_req_error(req, EIO);
1537 0 : return;
1538 : }
1539 0 : ldap_memfree(errmsg);
1540 :
1541 : /* Determine if there are more pages to retrieve */
1542 0 : page_control = ldap_control_find(LDAP_CONTROL_PAGEDRESULTS,
1543 : returned_controls, NULL );
1544 0 : if (!page_control) {
1545 : /* No paging support. We are done */
1546 0 : tevent_req_done(req);
1547 0 : return;
1548 : }
1549 :
1550 0 : lret = ldap_parse_pageresponse_control(state->sh->ldap, page_control,
1551 : &total_count, &cookie);
1552 0 : ldap_controls_free(returned_controls);
1553 0 : if (lret != LDAP_SUCCESS) {
1554 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not determine page control\n");
1555 0 : tevent_req_error(req, EIO);
1556 0 : return;
1557 : }
1558 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Total count [%d]\n", total_count);
1559 :
1560 0 : if (cookie.bv_val != NULL && cookie.bv_len > 0) {
1561 : /* Cookie contains data, which means there are more requests
1562 : * to be processed.
1563 : */
1564 0 : talloc_zfree(state->cookie.bv_val);
1565 0 : state->cookie.bv_len = cookie.bv_len;
1566 0 : state->cookie.bv_val = talloc_memdup(state,
1567 : cookie.bv_val,
1568 : cookie.bv_len);
1569 0 : if (!state->cookie.bv_val) {
1570 0 : tevent_req_error(req, ENOMEM);
1571 0 : return;
1572 : }
1573 0 : ber_memfree(cookie.bv_val);
1574 :
1575 0 : ret = sdap_get_generic_ext_step(req);
1576 0 : if (ret != EOK) {
1577 0 : tevent_req_error(req, ENOMEM);
1578 0 : return;
1579 : }
1580 :
1581 0 : return;
1582 : }
1583 : /* The cookie must be freed even if len == 0 */
1584 0 : ber_memfree(cookie.bv_val);
1585 :
1586 : /* This was the last page. We're done */
1587 :
1588 0 : tevent_req_done(req);
1589 0 : return;
1590 :
1591 : default:
1592 : /* what is going on here !? */
1593 0 : tevent_req_error(req, EIO);
1594 0 : return;
1595 : }
1596 : }
1597 :
1598 : static int
1599 0 : sdap_get_generic_ext_recv(struct tevent_req *req,
1600 : TALLOC_CTX *mem_ctx,
1601 : size_t *ref_count,
1602 : char ***refs)
1603 : {
1604 0 : struct sdap_get_generic_ext_state *state =
1605 0 : tevent_req_data(req, struct sdap_get_generic_ext_state);
1606 :
1607 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1608 :
1609 0 : if (ref_count) {
1610 0 : *ref_count = state->ref_count;
1611 : }
1612 :
1613 0 : if (refs) {
1614 0 : *refs = talloc_steal(mem_ctx, state->refs);
1615 : }
1616 :
1617 0 : return EOK;
1618 : }
1619 :
1620 : /* This search handler can be used by most calls */
1621 0 : static void generic_ext_search_handler(struct tevent_req *subreq,
1622 : struct sdap_options *opts)
1623 : {
1624 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1625 : struct tevent_req);
1626 : int ret;
1627 : size_t ref_count, i;
1628 : char **refs;
1629 :
1630 0 : ret = sdap_get_generic_ext_recv(subreq, req, &ref_count, &refs);
1631 0 : talloc_zfree(subreq);
1632 0 : if (ret != EOK) {
1633 0 : DEBUG(SSSDBG_OP_FAILURE,
1634 : "sdap_get_generic_ext_recv failed [%d]: %s\n",
1635 : ret, sss_strerror(ret));
1636 0 : tevent_req_error(req, ret);
1637 0 : return;
1638 : }
1639 :
1640 0 : if (ref_count > 0) {
1641 0 : if (dp_opt_get_bool(opts->basic, SDAP_REFERRALS)) {
1642 : /* We got back referrals here, but they should have
1643 : * been processed internally by openldap libs.
1644 : * This should never happen.
1645 : */
1646 0 : talloc_free(refs);
1647 0 : tevent_req_error(req, EINVAL);
1648 0 : return;
1649 : }
1650 :
1651 : /* We will ignore referrals in the generic handler */
1652 0 : DEBUG(SSSDBG_TRACE_ALL,
1653 : "Request included referrals which were ignored.\n");
1654 0 : if (debug_level & SSSDBG_TRACE_ALL) {
1655 0 : for(i = 0; i < ref_count; i++) {
1656 0 : DEBUG(SSSDBG_TRACE_ALL,
1657 : " Ref: %s\n", refs[i]);
1658 : }
1659 : }
1660 : }
1661 :
1662 0 : tevent_req_done(req);
1663 : }
1664 :
1665 : /* ==Generic Search exposing all options======================= */
1666 : struct sdap_get_and_parse_generic_state {
1667 : struct sdap_attr_map *map;
1668 : int map_num_attrs;
1669 :
1670 : struct sdap_reply sreply;
1671 : struct sdap_options *opts;
1672 : };
1673 :
1674 : static void sdap_get_and_parse_generic_done(struct tevent_req *subreq);
1675 : static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
1676 : struct sdap_msg *msg,
1677 : void *pvt);
1678 :
1679 0 : struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
1680 : struct tevent_context *ev,
1681 : struct sdap_options *opts,
1682 : struct sdap_handle *sh,
1683 : const char *search_base,
1684 : int scope,
1685 : const char *filter,
1686 : const char **attrs,
1687 : struct sdap_attr_map *map,
1688 : int map_num_attrs,
1689 : int attrsonly,
1690 : LDAPControl **serverctrls,
1691 : LDAPControl **clientctrls,
1692 : int sizelimit,
1693 : int timeout,
1694 : bool allow_paging)
1695 : {
1696 0 : struct tevent_req *req = NULL;
1697 0 : struct tevent_req *subreq = NULL;
1698 0 : struct sdap_get_and_parse_generic_state *state = NULL;
1699 :
1700 0 : req = tevent_req_create(memctx, &state,
1701 : struct sdap_get_and_parse_generic_state);
1702 0 : if (!req) return NULL;
1703 :
1704 0 : state->map = map;
1705 0 : state->map_num_attrs = map_num_attrs;
1706 0 : state->opts = opts;
1707 :
1708 0 : subreq = sdap_get_generic_ext_send(state, ev, opts, sh, search_base,
1709 : scope, filter, attrs, false, NULL,
1710 : NULL, sizelimit, timeout, allow_paging,
1711 : sdap_get_and_parse_generic_parse_entry, state);
1712 0 : if (!subreq) {
1713 0 : talloc_zfree(req);
1714 0 : return NULL;
1715 : }
1716 0 : tevent_req_set_callback(subreq, sdap_get_and_parse_generic_done, req);
1717 :
1718 0 : return req;
1719 : }
1720 :
1721 0 : static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
1722 : struct sdap_msg *msg,
1723 : void *pvt)
1724 : {
1725 : errno_t ret;
1726 : struct sysdb_attrs *attrs;
1727 0 : struct sdap_get_and_parse_generic_state *state =
1728 : talloc_get_type(pvt, struct sdap_get_and_parse_generic_state);
1729 :
1730 0 : bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
1731 : SDAP_DISABLE_RANGE_RETRIEVAL);
1732 :
1733 0 : ret = sdap_parse_entry(state, sh, msg,
1734 : state->map, state->map_num_attrs,
1735 : &attrs, disable_range_rtrvl);
1736 0 : if (ret != EOK) {
1737 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1738 : "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
1739 0 : return ret;
1740 : }
1741 :
1742 0 : ret = add_to_reply(state, &state->sreply, attrs);
1743 0 : if (ret != EOK) {
1744 0 : talloc_free(attrs);
1745 0 : DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
1746 0 : return ret;
1747 : }
1748 :
1749 : /* add_to_reply steals attrs, no need to free them here */
1750 0 : return EOK;
1751 : }
1752 :
1753 0 : static void sdap_get_and_parse_generic_done(struct tevent_req *subreq)
1754 : {
1755 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1756 : struct tevent_req);
1757 0 : struct sdap_get_and_parse_generic_state *state =
1758 0 : tevent_req_data(req, struct sdap_get_and_parse_generic_state);
1759 :
1760 0 : return generic_ext_search_handler(subreq, state->opts);
1761 : }
1762 :
1763 0 : int sdap_get_and_parse_generic_recv(struct tevent_req *req,
1764 : TALLOC_CTX *mem_ctx,
1765 : size_t *reply_count,
1766 : struct sysdb_attrs ***reply)
1767 : {
1768 0 : struct sdap_get_and_parse_generic_state *state = tevent_req_data(req,
1769 : struct sdap_get_and_parse_generic_state);
1770 :
1771 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1772 :
1773 0 : *reply_count = state->sreply.reply_count;
1774 0 : *reply = talloc_steal(mem_ctx, state->sreply.reply);
1775 :
1776 0 : return EOK;
1777 : }
1778 :
1779 :
1780 : /* ==Simple generic search============================================== */
1781 : struct sdap_get_generic_state {
1782 : size_t reply_count;
1783 : struct sysdb_attrs **reply;
1784 : };
1785 :
1786 : static void sdap_get_generic_done(struct tevent_req *subreq);
1787 :
1788 0 : struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
1789 : struct tevent_context *ev,
1790 : struct sdap_options *opts,
1791 : struct sdap_handle *sh,
1792 : const char *search_base,
1793 : int scope,
1794 : const char *filter,
1795 : const char **attrs,
1796 : struct sdap_attr_map *map,
1797 : int map_num_attrs,
1798 : int timeout,
1799 : bool allow_paging)
1800 : {
1801 0 : struct tevent_req *req = NULL;
1802 0 : struct tevent_req *subreq = NULL;
1803 0 : struct sdap_get_generic_state *state = NULL;
1804 :
1805 0 : req = tevent_req_create(memctx, &state, struct sdap_get_generic_state);
1806 0 : if (!req) return NULL;
1807 :
1808 0 : subreq = sdap_get_and_parse_generic_send(memctx, ev, opts, sh, search_base,
1809 : scope, filter, attrs,
1810 : map, map_num_attrs,
1811 : false, NULL, NULL, 0, timeout,
1812 : allow_paging);
1813 0 : if (subreq == NULL) {
1814 0 : return NULL;
1815 : }
1816 0 : tevent_req_set_callback(subreq, sdap_get_generic_done, req);
1817 :
1818 0 : return req;
1819 : }
1820 :
1821 0 : static void sdap_get_generic_done(struct tevent_req *subreq)
1822 : {
1823 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1824 : struct tevent_req);
1825 0 : struct sdap_get_generic_state *state =
1826 0 : tevent_req_data(req, struct sdap_get_generic_state);
1827 : errno_t ret;
1828 :
1829 0 : ret = sdap_get_and_parse_generic_recv(subreq, state,
1830 : &state->reply_count, &state->reply);
1831 0 : if (ret != EOK) {
1832 0 : tevent_req_error(req, ret);
1833 0 : return;
1834 : }
1835 0 : tevent_req_done(req);
1836 : }
1837 :
1838 0 : int sdap_get_generic_recv(struct tevent_req *req,
1839 : TALLOC_CTX *mem_ctx,
1840 : size_t *reply_count,
1841 : struct sysdb_attrs ***reply)
1842 : {
1843 0 : struct sdap_get_generic_state *state =
1844 0 : tevent_req_data(req, struct sdap_get_generic_state);
1845 :
1846 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1847 :
1848 0 : *reply_count = state->reply_count;
1849 0 : *reply = talloc_steal(mem_ctx, state->reply);
1850 :
1851 0 : return EOK;
1852 : }
1853 :
1854 : /* ==OpenLDAP deref search============================================== */
1855 : static int sdap_x_deref_create_control(struct sdap_handle *sh,
1856 : const char *deref_attr,
1857 : const char **attrs,
1858 : LDAPControl **ctrl);
1859 :
1860 : static void sdap_x_deref_search_done(struct tevent_req *subreq);
1861 : static int sdap_x_deref_search_ctrls_destructor(void *ptr);
1862 :
1863 : static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
1864 : struct sdap_msg *msg,
1865 : void *pvt);
1866 : struct sdap_x_deref_search_state {
1867 : struct sdap_handle *sh;
1868 : struct sdap_op *op;
1869 : struct sdap_attr_map_info *maps;
1870 : LDAPControl **ctrls;
1871 : struct sdap_options *opts;
1872 :
1873 : struct sdap_deref_reply dreply;
1874 : int num_maps;
1875 : };
1876 :
1877 : static struct tevent_req *
1878 0 : sdap_x_deref_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
1879 : struct sdap_options *opts, struct sdap_handle *sh,
1880 : const char *base_dn, const char *filter,
1881 : const char *deref_attr, const char **attrs,
1882 : struct sdap_attr_map_info *maps, int num_maps,
1883 : int timeout)
1884 : {
1885 0 : struct tevent_req *req = NULL;
1886 0 : struct tevent_req *subreq = NULL;
1887 : struct sdap_x_deref_search_state *state;
1888 : int ret;
1889 :
1890 0 : req = tevent_req_create(memctx, &state, struct sdap_x_deref_search_state);
1891 0 : if (!req) return NULL;
1892 :
1893 0 : state->sh = sh;
1894 0 : state->maps = maps;
1895 0 : state->op = NULL;
1896 0 : state->opts = opts;
1897 0 : state->num_maps = num_maps;
1898 0 : state->ctrls = talloc_zero_array(state, LDAPControl *, 2);
1899 0 : if (state->ctrls == NULL) {
1900 0 : talloc_zfree(req);
1901 0 : return NULL;
1902 : }
1903 0 : talloc_set_destructor((TALLOC_CTX *) state->ctrls,
1904 : sdap_x_deref_search_ctrls_destructor);
1905 :
1906 0 : ret = sdap_x_deref_create_control(sh, deref_attr,
1907 0 : attrs, &state->ctrls[0]);
1908 0 : if (ret != EOK) {
1909 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not create OpenLDAP deref control\n");
1910 0 : talloc_zfree(req);
1911 0 : return NULL;
1912 : }
1913 :
1914 0 : DEBUG(SSSDBG_TRACE_FUNC,
1915 : "Dereferencing entry [%s] using OpenLDAP deref\n", base_dn);
1916 0 : subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
1917 : filter == NULL ? LDAP_SCOPE_BASE
1918 : : LDAP_SCOPE_SUBTREE,
1919 : filter, attrs,
1920 0 : false, state->ctrls, NULL, 0, timeout,
1921 : true, sdap_x_deref_parse_entry,
1922 : state);
1923 0 : if (!subreq) {
1924 0 : talloc_zfree(req);
1925 0 : return NULL;
1926 : }
1927 0 : tevent_req_set_callback(subreq, sdap_x_deref_search_done, req);
1928 :
1929 0 : return req;
1930 : }
1931 :
1932 0 : static int sdap_x_deref_create_control(struct sdap_handle *sh,
1933 : const char *deref_attr,
1934 : const char **attrs,
1935 : LDAPControl **ctrl)
1936 : {
1937 : struct berval derefval;
1938 : int ret;
1939 : struct LDAPDerefSpec ds[2];
1940 :
1941 0 : ds[0].derefAttr = discard_const(deref_attr);
1942 0 : ds[0].attributes = discard_const(attrs);
1943 :
1944 0 : ds[1].derefAttr = NULL; /* sentinel */
1945 :
1946 0 : ret = ldap_create_deref_control_value(sh->ldap, ds, &derefval);
1947 0 : if (ret != LDAP_SUCCESS) {
1948 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldap_control_create failed: %s\n",
1949 : ldap_err2string(ret));
1950 0 : return ret;
1951 : }
1952 :
1953 0 : ret = sdap_control_create(sh, LDAP_CONTROL_X_DEREF,
1954 : 1, &derefval, 1, ctrl);
1955 0 : ldap_memfree(derefval.bv_val);
1956 0 : if (ret != EOK) {
1957 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldap_control_create failed\n");
1958 0 : return ret;
1959 : }
1960 :
1961 0 : return EOK;
1962 : }
1963 :
1964 0 : static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
1965 : struct sdap_msg *msg,
1966 : void *pvt)
1967 : {
1968 : errno_t ret;
1969 0 : LDAPControl **ctrls = NULL;
1970 0 : LDAPControl *derefctrl = NULL;
1971 0 : LDAPDerefRes *deref_res = NULL;
1972 : LDAPDerefRes *dref;
1973 : struct sdap_deref_attrs **res;
1974 : TALLOC_CTX *tmp_ctx;
1975 :
1976 0 : struct sdap_x_deref_search_state *state = talloc_get_type(pvt,
1977 : struct sdap_x_deref_search_state);
1978 :
1979 0 : tmp_ctx = talloc_new(NULL);
1980 0 : if (!tmp_ctx) return ENOMEM;
1981 :
1982 0 : ret = ldap_get_entry_controls(state->sh->ldap, msg->msg,
1983 : &ctrls);
1984 0 : if (ret != LDAP_SUCCESS) {
1985 0 : DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed\n");
1986 0 : goto done;
1987 : }
1988 :
1989 0 : if (!ctrls) {
1990 : /* When we attempt to request attributes that are not present in
1991 : * the dereferenced links, some serves might not send the dereference
1992 : * control back at all. Be permissive and treat the search as if
1993 : * it didn't find anything.
1994 : */
1995 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No controls found for entry\n");
1996 0 : ret = EOK;
1997 0 : goto done;
1998 : }
1999 :
2000 0 : res = NULL;
2001 :
2002 0 : derefctrl = ldap_control_find(LDAP_CONTROL_X_DEREF, ctrls, NULL);
2003 0 : if (!derefctrl) {
2004 0 : DEBUG(SSSDBG_FUNC_DATA, "No deref controls found\n");
2005 0 : ret = EOK;
2006 0 : goto done;
2007 : }
2008 :
2009 0 : DEBUG(SSSDBG_TRACE_FUNC, "Got deref control\n");
2010 :
2011 0 : ret = ldap_parse_derefresponse_control(state->sh->ldap,
2012 : derefctrl,
2013 : &deref_res);
2014 0 : if (ret != LDAP_SUCCESS) {
2015 0 : DEBUG(SSSDBG_OP_FAILURE,
2016 : "ldap_parse_derefresponse_control failed: %s\n",
2017 : ldap_err2string(ret));
2018 0 : goto done;
2019 : }
2020 :
2021 0 : for (dref = deref_res; dref; dref=dref->next) {
2022 0 : ret = sdap_parse_deref(tmp_ctx, state->maps, state->num_maps,
2023 : dref, &res);
2024 0 : if (ret) {
2025 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_parse_deref failed [%d]: %s\n",
2026 : ret, strerror(ret));
2027 0 : goto done;
2028 : }
2029 :
2030 0 : ret = add_to_deref_reply(state, state->num_maps,
2031 : &state->dreply, res);
2032 0 : if (ret != EOK) {
2033 0 : DEBUG(SSSDBG_OP_FAILURE, "add_to_deref_reply failed.\n");
2034 0 : goto done;
2035 : }
2036 : }
2037 :
2038 0 : DEBUG(SSSDBG_TRACE_FUNC,
2039 : "All deref results from a single control parsed\n");
2040 0 : ldap_derefresponse_free(deref_res);
2041 0 : deref_res = NULL;
2042 :
2043 0 : ret = EOK;
2044 : done:
2045 0 : talloc_zfree(tmp_ctx);
2046 0 : ldap_controls_free(ctrls);
2047 0 : ldap_derefresponse_free(deref_res);
2048 0 : return ret;
2049 : }
2050 :
2051 0 : static void sdap_x_deref_search_done(struct tevent_req *subreq)
2052 : {
2053 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2054 : struct tevent_req);
2055 0 : struct sdap_x_deref_search_state *state =
2056 0 : tevent_req_data(req, struct sdap_x_deref_search_state);
2057 :
2058 0 : return generic_ext_search_handler(subreq, state->opts);
2059 : }
2060 :
2061 0 : static int sdap_x_deref_search_ctrls_destructor(void *ptr)
2062 : {
2063 0 : LDAPControl **ctrls = talloc_get_type(ptr, LDAPControl *);;
2064 :
2065 0 : if (ctrls && ctrls[0]) {
2066 0 : ldap_control_free(ctrls[0]);
2067 : }
2068 :
2069 0 : return 0;
2070 : }
2071 :
2072 : static int
2073 0 : sdap_x_deref_search_recv(struct tevent_req *req,
2074 : TALLOC_CTX *mem_ctx,
2075 : size_t *reply_count,
2076 : struct sdap_deref_attrs ***reply)
2077 : {
2078 0 : struct sdap_x_deref_search_state *state = tevent_req_data(req,
2079 : struct sdap_x_deref_search_state);
2080 :
2081 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2082 :
2083 0 : *reply_count = state->dreply.reply_count;
2084 0 : *reply = talloc_steal(mem_ctx, state->dreply.reply);
2085 :
2086 0 : return EOK;
2087 : }
2088 :
2089 : /* ==Security Descriptor (ACL) search=================================== */
2090 : struct sdap_sd_search_state {
2091 : LDAPControl **ctrls;
2092 : struct sdap_options *opts;
2093 : size_t reply_count;
2094 : struct sysdb_attrs **reply;
2095 : struct sdap_reply sreply;
2096 :
2097 : /* Referrals returned by the search */
2098 : size_t ref_count;
2099 : char **refs;
2100 : };
2101 :
2102 : static int sdap_sd_search_create_control(struct sdap_handle *sh,
2103 : int val,
2104 : LDAPControl **ctrl);
2105 : static int sdap_sd_search_ctrls_destructor(void *ptr);
2106 : static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
2107 : struct sdap_msg *msg,
2108 : void *pvt);
2109 : static void sdap_sd_search_done(struct tevent_req *subreq);
2110 :
2111 : struct tevent_req *
2112 0 : sdap_sd_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
2113 : struct sdap_options *opts, struct sdap_handle *sh,
2114 : const char *base_dn, int sd_flags,
2115 : const char **attrs, int timeout)
2116 : {
2117 0 : struct tevent_req *req = NULL;
2118 0 : struct tevent_req *subreq = NULL;
2119 : struct sdap_sd_search_state *state;
2120 : int ret;
2121 :
2122 0 : req = tevent_req_create(memctx, &state, struct sdap_sd_search_state);
2123 0 : if (!req) return NULL;
2124 :
2125 0 : state->ctrls = talloc_zero_array(state, LDAPControl *, 2);
2126 0 : state->opts = opts;
2127 0 : if (state->ctrls == NULL) {
2128 0 : ret = EIO;
2129 0 : goto fail;
2130 : }
2131 0 : talloc_set_destructor((TALLOC_CTX *) state->ctrls,
2132 : sdap_sd_search_ctrls_destructor);
2133 :
2134 0 : ret = sdap_sd_search_create_control(sh, sd_flags, &state->ctrls[0]);
2135 0 : if (ret != EOK) {
2136 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not create SD control\n");
2137 0 : ret = EIO;
2138 0 : goto fail;
2139 : }
2140 :
2141 0 : DEBUG(SSSDBG_TRACE_FUNC, "Searching entry [%s] using SD\n", base_dn);
2142 0 : subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
2143 : LDAP_SCOPE_BASE, "(objectclass=*)", attrs,
2144 0 : false, state->ctrls, NULL, 0, timeout,
2145 : true, sdap_sd_search_parse_entry,
2146 : state);
2147 0 : if (!subreq) {
2148 0 : ret = EIO;
2149 0 : goto fail;
2150 : }
2151 0 : tevent_req_set_callback(subreq, sdap_sd_search_done, req);
2152 0 : return req;
2153 :
2154 : fail:
2155 0 : tevent_req_error(req, ret);
2156 0 : tevent_req_post(req, ev);
2157 0 : return req;
2158 : }
2159 :
2160 0 : static int sdap_sd_search_create_control(struct sdap_handle *sh,
2161 : int val,
2162 : LDAPControl **ctrl)
2163 : {
2164 : struct berval *sdval;
2165 : int ret;
2166 0 : BerElement *ber = NULL;
2167 0 : ber = ber_alloc_t(LBER_USE_DER);
2168 0 : if (ber == NULL) {
2169 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_alloc_t failed.\n");
2170 0 : return ENOMEM;
2171 : }
2172 :
2173 0 : ret = ber_printf(ber, "{i}", val);
2174 0 : if (ret == -1) {
2175 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_printf failed.\n");
2176 0 : ber_free(ber, 1);
2177 0 : return EIO;
2178 : }
2179 :
2180 0 : ret = ber_flatten(ber, &sdval);
2181 0 : ber_free(ber, 1);
2182 0 : if (ret == -1) {
2183 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ber_flatten failed.\n");
2184 0 : return EIO;
2185 : }
2186 :
2187 0 : ret = sdap_control_create(sh, LDAP_SERVER_SD_OID, 1, sdval, 1, ctrl);
2188 0 : ber_bvfree(sdval);
2189 0 : if (ret != EOK) {
2190 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_control_create failed\n");
2191 0 : return ret;
2192 : }
2193 :
2194 0 : return EOK;
2195 : }
2196 :
2197 0 : static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
2198 : struct sdap_msg *msg,
2199 : void *pvt)
2200 : {
2201 : errno_t ret;
2202 : struct sysdb_attrs *attrs;
2203 0 : struct sdap_sd_search_state *state =
2204 : talloc_get_type(pvt, struct sdap_sd_search_state);
2205 :
2206 0 : bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
2207 : SDAP_DISABLE_RANGE_RETRIEVAL);
2208 :
2209 0 : ret = sdap_parse_entry(state, sh, msg,
2210 : NULL, 0,
2211 : &attrs, disable_range_rtrvl);
2212 0 : if (ret != EOK) {
2213 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2214 : "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
2215 0 : return ret;
2216 : }
2217 :
2218 0 : ret = add_to_reply(state, &state->sreply, attrs);
2219 0 : if (ret != EOK) {
2220 0 : talloc_free(attrs);
2221 0 : DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
2222 0 : return ret;
2223 : }
2224 :
2225 : /* add_to_reply steals attrs, no need to free them here */
2226 0 : return EOK;
2227 : }
2228 :
2229 0 : static void sdap_sd_search_done(struct tevent_req *subreq)
2230 : {
2231 : int ret;
2232 :
2233 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2234 : struct tevent_req);
2235 0 : struct sdap_sd_search_state *state =
2236 0 : tevent_req_data(req, struct sdap_sd_search_state);
2237 :
2238 0 : ret = sdap_get_generic_ext_recv(subreq, state,
2239 : &state->ref_count,
2240 : &state->refs);
2241 0 : talloc_zfree(subreq);
2242 0 : if (ret != EOK) {
2243 0 : DEBUG(SSSDBG_OP_FAILURE,
2244 : "sdap_get_generic_ext_recv failed [%d]: %s\n",
2245 : ret, sss_strerror(ret));
2246 0 : tevent_req_error(req, ret);
2247 0 : return;
2248 : }
2249 :
2250 0 : tevent_req_done(req);
2251 : }
2252 :
2253 0 : static int sdap_sd_search_ctrls_destructor(void *ptr)
2254 : {
2255 0 : LDAPControl **ctrls = talloc_get_type(ptr, LDAPControl *);;
2256 0 : if (ctrls && ctrls[0]) {
2257 0 : ldap_control_free(ctrls[0]);
2258 : }
2259 :
2260 0 : return 0;
2261 : }
2262 :
2263 0 : int sdap_sd_search_recv(struct tevent_req *req,
2264 : TALLOC_CTX *mem_ctx,
2265 : size_t *_reply_count,
2266 : struct sysdb_attrs ***_reply,
2267 : size_t *_ref_count,
2268 : char ***_refs)
2269 : {
2270 0 : struct sdap_sd_search_state *state = tevent_req_data(req,
2271 : struct sdap_sd_search_state);
2272 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2273 :
2274 0 : *_reply_count = state->sreply.reply_count;
2275 0 : *_reply = talloc_steal(mem_ctx, state->sreply.reply);
2276 :
2277 0 : if(_ref_count) {
2278 0 : *_ref_count = state->ref_count;
2279 : }
2280 :
2281 0 : if (_refs) {
2282 0 : *_refs = talloc_steal(mem_ctx, state->refs);
2283 : }
2284 :
2285 0 : return EOK;
2286 : }
2287 :
2288 : /* ==Attribute scoped search============================================ */
2289 : struct sdap_asq_search_state {
2290 : struct sdap_attr_map_info *maps;
2291 : int num_maps;
2292 : LDAPControl **ctrls;
2293 : struct sdap_options *opts;
2294 :
2295 : struct sdap_deref_reply dreply;
2296 : };
2297 :
2298 : static int sdap_asq_search_create_control(struct sdap_handle *sh,
2299 : const char *attr,
2300 : LDAPControl **ctrl);
2301 : static int sdap_asq_search_ctrls_destructor(void *ptr);
2302 : static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
2303 : struct sdap_msg *msg,
2304 : void *pvt);
2305 : static void sdap_asq_search_done(struct tevent_req *subreq);
2306 :
2307 : static struct tevent_req *
2308 0 : sdap_asq_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
2309 : struct sdap_options *opts, struct sdap_handle *sh,
2310 : const char *base_dn, const char *deref_attr,
2311 : const char **attrs, struct sdap_attr_map_info *maps,
2312 : int num_maps, int timeout)
2313 : {
2314 0 : struct tevent_req *req = NULL;
2315 0 : struct tevent_req *subreq = NULL;
2316 : struct sdap_asq_search_state *state;
2317 : int ret;
2318 :
2319 0 : req = tevent_req_create(memctx, &state, struct sdap_asq_search_state);
2320 0 : if (!req) return NULL;
2321 :
2322 0 : state->maps = maps;
2323 0 : state->num_maps = num_maps;
2324 0 : state->ctrls = talloc_zero_array(state, LDAPControl *, 2);
2325 0 : state->opts = opts;
2326 0 : if (state->ctrls == NULL) {
2327 0 : talloc_zfree(req);
2328 0 : return NULL;
2329 : }
2330 0 : talloc_set_destructor((TALLOC_CTX *) state->ctrls,
2331 : sdap_asq_search_ctrls_destructor);
2332 :
2333 0 : ret = sdap_asq_search_create_control(sh, deref_attr, &state->ctrls[0]);
2334 0 : if (ret != EOK) {
2335 0 : talloc_zfree(req);
2336 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not create ASQ control\n");
2337 0 : return NULL;
2338 : }
2339 :
2340 0 : DEBUG(SSSDBG_TRACE_FUNC, "Dereferencing entry [%s] using ASQ\n", base_dn);
2341 0 : subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
2342 : LDAP_SCOPE_BASE, NULL, attrs,
2343 0 : false, state->ctrls, NULL, 0, timeout,
2344 : true, sdap_asq_search_parse_entry,
2345 : state);
2346 0 : if (!subreq) {
2347 0 : talloc_zfree(req);
2348 0 : return NULL;
2349 : }
2350 0 : tevent_req_set_callback(subreq, sdap_asq_search_done, req);
2351 :
2352 0 : return req;
2353 : }
2354 :
2355 :
2356 0 : static int sdap_asq_search_create_control(struct sdap_handle *sh,
2357 : const char *attr,
2358 : LDAPControl **ctrl)
2359 : {
2360 : struct berval *asqval;
2361 : int ret;
2362 0 : BerElement *ber = NULL;
2363 :
2364 0 : ber = ber_alloc_t(LBER_USE_DER);
2365 0 : if (ber == NULL) {
2366 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_alloc_t failed.\n");
2367 0 : return ENOMEM;
2368 : }
2369 :
2370 0 : ret = ber_printf(ber, "{s}", attr);
2371 0 : if (ret == -1) {
2372 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_printf failed.\n");
2373 0 : ber_free(ber, 1);
2374 0 : return EIO;
2375 : }
2376 :
2377 0 : ret = ber_flatten(ber, &asqval);
2378 0 : ber_free(ber, 1);
2379 0 : if (ret == -1) {
2380 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ber_flatten failed.\n");
2381 0 : return EIO;
2382 : }
2383 :
2384 0 : ret = sdap_control_create(sh, LDAP_SERVER_ASQ_OID, 1, asqval, 1, ctrl);
2385 0 : ber_bvfree(asqval);
2386 0 : if (ret != EOK) {
2387 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_control_create failed\n");
2388 0 : return ret;
2389 : }
2390 :
2391 0 : return EOK;
2392 : }
2393 :
2394 0 : static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
2395 : struct sdap_msg *msg,
2396 : void *pvt)
2397 : {
2398 : errno_t ret;
2399 0 : struct sdap_asq_search_state *state =
2400 : talloc_get_type(pvt, struct sdap_asq_search_state);
2401 : struct berval **vals;
2402 : int i, mi;
2403 : struct sdap_attr_map *map;
2404 : int num_attrs;
2405 : struct sdap_deref_attrs **res;
2406 : char *tmp;
2407 : char *dn;
2408 : TALLOC_CTX *tmp_ctx;
2409 : bool disable_range_rtrvl;
2410 :
2411 0 : tmp_ctx = talloc_new(NULL);
2412 0 : if (!tmp_ctx) return ENOMEM;
2413 :
2414 0 : res = talloc_array(tmp_ctx, struct sdap_deref_attrs *,
2415 : state->num_maps);
2416 0 : if (!res) {
2417 0 : ret = ENOMEM;
2418 0 : goto done;
2419 : }
2420 :
2421 0 : for (mi =0; mi < state->num_maps; mi++) {
2422 0 : res[mi] = talloc_zero(res, struct sdap_deref_attrs);
2423 0 : if (!res[mi]) {
2424 0 : ret = ENOMEM;
2425 0 : goto done;
2426 : }
2427 0 : res[mi]->map = state->maps[mi].map;
2428 0 : res[mi]->attrs = NULL;
2429 : }
2430 :
2431 :
2432 0 : tmp = ldap_get_dn(sh->ldap, msg->msg);
2433 0 : if (!tmp) {
2434 0 : ret = EINVAL;
2435 0 : goto done;
2436 : }
2437 :
2438 0 : dn = talloc_strdup(tmp_ctx, tmp);
2439 0 : ldap_memfree(tmp);
2440 0 : if (!dn) {
2441 0 : ret = ENOMEM;
2442 0 : goto done;
2443 : }
2444 :
2445 : /* Find all suitable maps in the list */
2446 0 : vals = ldap_get_values_len(sh->ldap, msg->msg, "objectClass");
2447 0 : if (!vals) {
2448 0 : DEBUG(SSSDBG_OP_FAILURE,
2449 : "Unknown entry type, no objectClass found for DN [%s]!\n", dn);
2450 0 : ret = EINVAL;
2451 0 : goto done;
2452 : }
2453 0 : for (mi =0; mi < state->num_maps; mi++) {
2454 0 : map = NULL;
2455 0 : for (i = 0; vals[i]; i++) {
2456 : /* the objectclass is always the first name in the map */
2457 0 : if (strncasecmp(state->maps[mi].map[0].name,
2458 0 : vals[i]->bv_val, vals[i]->bv_len) == 0) {
2459 : /* it's an entry of the right type */
2460 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
2461 : "Matched objectclass [%s] on DN [%s], will use associated map\n",
2462 : state->maps[mi].map[0].name, dn);
2463 0 : map = state->maps[mi].map;
2464 0 : num_attrs = state->maps[mi].num_attrs;
2465 0 : break;
2466 : }
2467 : }
2468 0 : if (!map) {
2469 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
2470 : "DN [%s] did not match the objectClass [%s]\n",
2471 : dn, state->maps[mi].map[0].name);
2472 0 : continue;
2473 : }
2474 :
2475 0 : disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
2476 : SDAP_DISABLE_RANGE_RETRIEVAL);
2477 :
2478 0 : ret = sdap_parse_entry(res[mi], sh, msg,
2479 : map, num_attrs,
2480 0 : &res[mi]->attrs, disable_range_rtrvl);
2481 0 : if (ret != EOK) {
2482 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2483 : "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
2484 0 : goto done;
2485 : }
2486 : }
2487 0 : ldap_value_free_len(vals);
2488 :
2489 0 : ret = add_to_deref_reply(state, state->num_maps,
2490 : &state->dreply, res);
2491 0 : if (ret != EOK) {
2492 0 : DEBUG(SSSDBG_CRIT_FAILURE, "add_to_deref_reply failed.\n");
2493 0 : goto done;
2494 : }
2495 :
2496 0 : ret = EOK;
2497 : done:
2498 0 : talloc_zfree(tmp_ctx);
2499 0 : return ret;
2500 : }
2501 :
2502 0 : static void sdap_asq_search_done(struct tevent_req *subreq)
2503 : {
2504 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2505 : struct tevent_req);
2506 0 : struct sdap_asq_search_state *state =
2507 0 : tevent_req_data(req, struct sdap_asq_search_state);
2508 :
2509 0 : return generic_ext_search_handler(subreq, state->opts);
2510 : }
2511 :
2512 0 : static int sdap_asq_search_ctrls_destructor(void *ptr)
2513 : {
2514 0 : LDAPControl **ctrls = talloc_get_type(ptr, LDAPControl *);;
2515 :
2516 0 : if (ctrls && ctrls[0]) {
2517 0 : ldap_control_free(ctrls[0]);
2518 : }
2519 :
2520 0 : return 0;
2521 : }
2522 :
2523 0 : int sdap_asq_search_recv(struct tevent_req *req,
2524 : TALLOC_CTX *mem_ctx,
2525 : size_t *reply_count,
2526 : struct sdap_deref_attrs ***reply)
2527 : {
2528 0 : struct sdap_asq_search_state *state = tevent_req_data(req,
2529 : struct sdap_asq_search_state);
2530 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2531 :
2532 0 : *reply_count = state->dreply.reply_count;
2533 0 : *reply = talloc_steal(mem_ctx, state->dreply.reply);
2534 :
2535 0 : return EOK;
2536 : }
2537 :
2538 : /* ==Posix attribute presence test================================= */
2539 : static errno_t sdap_posix_check_next(struct tevent_req *req);
2540 : static void sdap_posix_check_done(struct tevent_req *subreq);
2541 : static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
2542 : struct sdap_msg *msg,
2543 : void *pvt);
2544 :
2545 : struct sdap_posix_check_state {
2546 : struct tevent_context *ev;
2547 : struct sdap_options *opts;
2548 : struct sdap_handle *sh;
2549 : struct sdap_search_base **search_bases;
2550 : int timeout;
2551 :
2552 : const char **attrs;
2553 : const char *filter;
2554 : size_t base_iter;
2555 :
2556 : bool has_posix;
2557 : };
2558 :
2559 : struct tevent_req *
2560 0 : sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
2561 : struct sdap_options *opts, struct sdap_handle *sh,
2562 : struct sdap_search_base **search_bases,
2563 : int timeout)
2564 : {
2565 0 : struct tevent_req *req = NULL;
2566 : struct sdap_posix_check_state *state;
2567 : errno_t ret;
2568 :
2569 0 : req = tevent_req_create(memctx, &state, struct sdap_posix_check_state);
2570 0 : if (req == NULL) {
2571 0 : return NULL;
2572 : }
2573 0 : state->ev = ev;
2574 0 : state->sh = sh;
2575 0 : state->opts = opts;
2576 0 : state->search_bases = search_bases;
2577 0 : state->timeout = timeout;
2578 :
2579 0 : state->attrs = talloc_array(state, const char *, 4);
2580 0 : if (state->attrs == NULL) {
2581 0 : ret = ENOMEM;
2582 0 : goto fail;
2583 : }
2584 0 : state->attrs[0] = "objectclass";
2585 0 : state->attrs[1] = opts->user_map[SDAP_AT_USER_UID].name;
2586 0 : state->attrs[2] = opts->group_map[SDAP_AT_GROUP_GID].name;
2587 0 : state->attrs[3] = NULL;
2588 :
2589 0 : state->filter = talloc_asprintf(state,
2590 : "(|(&(%s=*)(objectclass=%s))(&(%s=*)(objectclass=%s)))",
2591 0 : opts->user_map[SDAP_AT_USER_UID].name,
2592 0 : opts->user_map[SDAP_OC_USER].name,
2593 0 : opts->group_map[SDAP_AT_GROUP_GID].name,
2594 0 : opts->group_map[SDAP_OC_GROUP].name);
2595 0 : if (state->filter == NULL) {
2596 0 : ret = ENOMEM;
2597 0 : goto fail;
2598 : }
2599 :
2600 0 : ret = sdap_posix_check_next(req);
2601 0 : if (ret != EOK) {
2602 0 : goto fail;
2603 : }
2604 :
2605 0 : return req;
2606 :
2607 : fail:
2608 0 : tevent_req_error(req, ret);
2609 0 : tevent_req_post(req, ev);
2610 0 : return req;
2611 : }
2612 :
2613 0 : static errno_t sdap_posix_check_next(struct tevent_req *req)
2614 : {
2615 0 : struct tevent_req *subreq = NULL;
2616 0 : struct sdap_posix_check_state *state =
2617 0 : tevent_req_data(req, struct sdap_posix_check_state);
2618 :
2619 0 : DEBUG(SSSDBG_TRACE_FUNC,
2620 : "Searching for POSIX attributes with base [%s]\n",
2621 : state->search_bases[state->base_iter]->basedn);
2622 :
2623 0 : subreq = sdap_get_generic_ext_send(state, state->ev, state->opts,
2624 : state->sh,
2625 0 : state->search_bases[state->base_iter]->basedn,
2626 : LDAP_SCOPE_SUBTREE, state->filter,
2627 : state->attrs, false,
2628 : NULL, NULL, 1, state->timeout,
2629 : false, sdap_posix_check_parse,
2630 : state);
2631 0 : if (subreq == NULL) {
2632 0 : return ENOMEM;
2633 : }
2634 0 : tevent_req_set_callback(subreq, sdap_posix_check_done, req);
2635 :
2636 0 : return EOK;
2637 : }
2638 :
2639 0 : static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
2640 : struct sdap_msg *msg,
2641 : void *pvt)
2642 : {
2643 0 : struct berval **vals = NULL;
2644 0 : struct sdap_posix_check_state *state =
2645 : talloc_get_type(pvt, struct sdap_posix_check_state);
2646 : char *dn;
2647 : char *endptr;
2648 :
2649 0 : dn = ldap_get_dn(sh->ldap, msg->msg);
2650 0 : if (dn == NULL) {
2651 0 : DEBUG(SSSDBG_TRACE_LIBS,
2652 : "Search did not find any entry with POSIX attributes\n");
2653 0 : goto done;
2654 : }
2655 0 : DEBUG(SSSDBG_TRACE_LIBS, "Found [%s] with POSIX attributes\n", dn);
2656 0 : ldap_memfree(dn);
2657 :
2658 0 : vals = ldap_get_values_len(sh->ldap, msg->msg,
2659 0 : state->opts->user_map[SDAP_AT_USER_UID].name);
2660 0 : if (vals == NULL) {
2661 0 : vals = ldap_get_values_len(sh->ldap, msg->msg,
2662 0 : state->opts->group_map[SDAP_AT_GROUP_GID].name);
2663 0 : if (vals == NULL) {
2664 0 : DEBUG(SSSDBG_TRACE_LIBS, "Entry does not have POSIX attrs?\n");
2665 0 : goto done;
2666 : }
2667 : }
2668 :
2669 0 : if (vals[0] == NULL) {
2670 0 : DEBUG(SSSDBG_TRACE_LIBS, "No value for POSIX attr\n");
2671 0 : goto done;
2672 : }
2673 :
2674 0 : errno = 0;
2675 0 : strtouint32(vals[0]->bv_val, &endptr, 10);
2676 0 : if (errno || *endptr || (vals[0]->bv_val == endptr)) {
2677 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2678 : "POSIX attribute is not a number: %s\n", vals[0]->bv_val);
2679 : }
2680 :
2681 0 : state->has_posix = true;
2682 : done:
2683 0 : ldap_value_free_len(vals);
2684 0 : return EOK;
2685 : }
2686 :
2687 0 : static void sdap_posix_check_done(struct tevent_req *subreq)
2688 : {
2689 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2690 : struct tevent_req);
2691 0 : struct sdap_posix_check_state *state =
2692 0 : tevent_req_data(req, struct sdap_posix_check_state);
2693 : errno_t ret;
2694 :
2695 0 : ret = sdap_get_generic_ext_recv(subreq, NULL, NULL, NULL);
2696 0 : talloc_zfree(subreq);
2697 0 : if (ret != EOK) {
2698 0 : DEBUG(SSSDBG_OP_FAILURE,
2699 : "sdap_get_generic_ext_recv failed [%d]: %s\n",
2700 : ret, strerror(ret));
2701 0 : tevent_req_error(req, ret);
2702 0 : return;
2703 : }
2704 :
2705 : /* Positive hit is definitve, no need to search other bases */
2706 0 : if (state->has_posix == true) {
2707 0 : DEBUG(SSSDBG_FUNC_DATA, "Server has POSIX attributes\n");
2708 0 : tevent_req_done(req);
2709 0 : return;
2710 : }
2711 :
2712 0 : state->base_iter++;
2713 0 : if (state->search_bases[state->base_iter]) {
2714 : /* There are more search bases to try */
2715 0 : ret = sdap_posix_check_next(req);
2716 0 : if (ret != EOK) {
2717 0 : tevent_req_error(req, ret);
2718 : }
2719 0 : return;
2720 : }
2721 :
2722 : /* All bases done! */
2723 0 : DEBUG(SSSDBG_TRACE_LIBS, "Cycled through all bases\n");
2724 0 : tevent_req_done(req);
2725 : }
2726 :
2727 0 : int sdap_posix_check_recv(struct tevent_req *req,
2728 : bool *_has_posix)
2729 : {
2730 0 : struct sdap_posix_check_state *state = tevent_req_data(req,
2731 : struct sdap_posix_check_state);
2732 :
2733 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2734 :
2735 0 : *_has_posix = state->has_posix;
2736 0 : return EOK;
2737 : }
2738 :
2739 : /* ==Generic Deref Search============================================ */
2740 : enum sdap_deref_type {
2741 : SDAP_DEREF_OPENLDAP,
2742 : SDAP_DEREF_ASQ
2743 : };
2744 :
2745 : struct sdap_deref_search_state {
2746 : struct sdap_handle *sh;
2747 : size_t reply_count;
2748 : struct sdap_deref_attrs **reply;
2749 : enum sdap_deref_type deref_type;
2750 : };
2751 :
2752 : static void sdap_deref_search_done(struct tevent_req *subreq);
2753 : static void sdap_deref_search_with_filter_done(struct tevent_req *subreq);
2754 :
2755 : struct tevent_req *
2756 0 : sdap_deref_search_with_filter_send(TALLOC_CTX *memctx,
2757 : struct tevent_context *ev,
2758 : struct sdap_options *opts,
2759 : struct sdap_handle *sh,
2760 : const char *search_base,
2761 : const char *filter,
2762 : const char *deref_attr,
2763 : const char **attrs,
2764 : int num_maps,
2765 : struct sdap_attr_map_info *maps,
2766 : int timeout)
2767 : {
2768 0 : struct tevent_req *req = NULL;
2769 0 : struct tevent_req *subreq = NULL;
2770 : struct sdap_deref_search_state *state;
2771 :
2772 0 : req = tevent_req_create(memctx, &state, struct sdap_deref_search_state);
2773 0 : if (!req) return NULL;
2774 :
2775 0 : state->sh = sh;
2776 0 : state->reply_count = 0;
2777 0 : state->reply = NULL;
2778 :
2779 0 : if (sdap_is_control_supported(sh, LDAP_CONTROL_X_DEREF)) {
2780 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports OpenLDAP deref\n");
2781 0 : state->deref_type = SDAP_DEREF_OPENLDAP;
2782 :
2783 0 : subreq = sdap_x_deref_search_send(state, ev, opts, sh, search_base,
2784 : filter, deref_attr, attrs, maps,
2785 : num_maps, timeout);
2786 0 : if (!subreq) {
2787 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot start OpenLDAP deref search\n");
2788 0 : goto fail;
2789 : }
2790 : } else {
2791 0 : DEBUG(SSSDBG_OP_FAILURE,
2792 : "Server does not support any known deref method!\n");
2793 0 : goto fail;
2794 : }
2795 :
2796 0 : tevent_req_set_callback(subreq, sdap_deref_search_with_filter_done, req);
2797 0 : return req;
2798 :
2799 : fail:
2800 0 : talloc_zfree(req);
2801 0 : return NULL;
2802 : }
2803 :
2804 0 : static void sdap_deref_search_with_filter_done(struct tevent_req *subreq)
2805 : {
2806 0 : sdap_deref_search_done(subreq);
2807 0 : }
2808 :
2809 0 : int sdap_deref_search_with_filter_recv(struct tevent_req *req,
2810 : TALLOC_CTX *mem_ctx,
2811 : size_t *reply_count,
2812 : struct sdap_deref_attrs ***reply)
2813 : {
2814 0 : return sdap_deref_search_recv(req, mem_ctx, reply_count, reply);
2815 : }
2816 :
2817 : struct tevent_req *
2818 0 : sdap_deref_search_send(TALLOC_CTX *memctx,
2819 : struct tevent_context *ev,
2820 : struct sdap_options *opts,
2821 : struct sdap_handle *sh,
2822 : const char *base_dn,
2823 : const char *deref_attr,
2824 : const char **attrs,
2825 : int num_maps,
2826 : struct sdap_attr_map_info *maps,
2827 : int timeout)
2828 : {
2829 0 : struct tevent_req *req = NULL;
2830 0 : struct tevent_req *subreq = NULL;
2831 : struct sdap_deref_search_state *state;
2832 :
2833 0 : req = tevent_req_create(memctx, &state, struct sdap_deref_search_state);
2834 0 : if (!req) return NULL;
2835 :
2836 0 : state->sh = sh;
2837 0 : state->reply_count = 0;
2838 0 : state->reply = NULL;
2839 :
2840 0 : if (sdap_is_control_supported(sh, LDAP_SERVER_ASQ_OID)) {
2841 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports ASQ\n");
2842 0 : state->deref_type = SDAP_DEREF_ASQ;
2843 :
2844 0 : subreq = sdap_asq_search_send(state, ev, opts, sh, base_dn,
2845 : deref_attr, attrs, maps, num_maps,
2846 : timeout);
2847 0 : if (!subreq) {
2848 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot start ASQ search\n");
2849 0 : goto fail;
2850 : }
2851 0 : } else if (sdap_is_control_supported(sh, LDAP_CONTROL_X_DEREF)) {
2852 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports OpenLDAP deref\n");
2853 0 : state->deref_type = SDAP_DEREF_OPENLDAP;
2854 :
2855 0 : subreq = sdap_x_deref_search_send(state, ev, opts, sh, base_dn, NULL,
2856 : deref_attr, attrs, maps, num_maps,
2857 : timeout);
2858 0 : if (!subreq) {
2859 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot start OpenLDAP deref search\n");
2860 0 : goto fail;
2861 : }
2862 : } else {
2863 0 : DEBUG(SSSDBG_OP_FAILURE,
2864 : "Server does not support any known deref method!\n");
2865 0 : goto fail;
2866 : }
2867 :
2868 0 : tevent_req_set_callback(subreq, sdap_deref_search_done, req);
2869 0 : return req;
2870 :
2871 : fail:
2872 0 : talloc_zfree(req);
2873 0 : return NULL;
2874 : }
2875 :
2876 0 : static void sdap_deref_search_done(struct tevent_req *subreq)
2877 : {
2878 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2879 : struct tevent_req);
2880 0 : struct sdap_deref_search_state *state = tevent_req_data(req,
2881 : struct sdap_deref_search_state);
2882 : int ret;
2883 :
2884 0 : switch (state->deref_type) {
2885 : case SDAP_DEREF_OPENLDAP:
2886 0 : ret = sdap_x_deref_search_recv(subreq, state,
2887 : &state->reply_count, &state->reply);
2888 0 : break;
2889 : case SDAP_DEREF_ASQ:
2890 0 : ret = sdap_asq_search_recv(subreq, state,
2891 : &state->reply_count, &state->reply);
2892 0 : break;
2893 : default:
2894 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown deref method\n");
2895 0 : tevent_req_error(req, EINVAL);
2896 0 : return;
2897 : }
2898 :
2899 0 : talloc_zfree(subreq);
2900 0 : if (ret != EOK) {
2901 0 : DEBUG(SSSDBG_OP_FAILURE,
2902 : "dereference processing failed [%d]: %s\n", ret, strerror(ret));
2903 0 : if (ret == ENOTSUP) {
2904 0 : sss_log(SSS_LOG_WARNING,
2905 : "LDAP server claims to support deref, but deref search failed. "
2906 : "Disabling deref for further requests. You can permanently "
2907 : "disable deref by setting ldap_deref_threshold to 0 in domain "
2908 : "configuration.");
2909 0 : state->sh->disable_deref = true;
2910 : } else {
2911 0 : sss_log(SSS_LOG_WARNING, "dereference processing failed : %s", strerror(ret));
2912 : }
2913 0 : tevent_req_error(req, ret);
2914 0 : return;
2915 : }
2916 :
2917 0 : tevent_req_done(req);
2918 : }
2919 :
2920 0 : int sdap_deref_search_recv(struct tevent_req *req,
2921 : TALLOC_CTX *mem_ctx,
2922 : size_t *reply_count,
2923 : struct sdap_deref_attrs ***reply)
2924 : {
2925 0 : struct sdap_deref_search_state *state = tevent_req_data(req,
2926 : struct sdap_deref_search_state);
2927 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2928 :
2929 0 : *reply_count = state->reply_count;
2930 0 : *reply = talloc_steal(mem_ctx, state->reply);
2931 :
2932 0 : return EOK;
2933 : }
2934 :
2935 0 : bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts)
2936 : {
2937 0 : const char *deref_oids[][2] = { { LDAP_SERVER_ASQ_OID, "ASQ" },
2938 : { LDAP_CONTROL_X_DEREF, "OpenLDAP" },
2939 : { NULL, NULL }
2940 : };
2941 : int i;
2942 : int deref_threshold;
2943 :
2944 0 : if (sh->disable_deref) {
2945 0 : return false;
2946 : }
2947 :
2948 0 : deref_threshold = dp_opt_get_int(opts->basic, SDAP_DEREF_THRESHOLD);
2949 0 : if (deref_threshold == 0) {
2950 0 : return false;
2951 : }
2952 :
2953 0 : for (i=0; deref_oids[i][0]; i++) {
2954 0 : if (sdap_is_control_supported(sh, deref_oids[i][0])) {
2955 0 : DEBUG(SSSDBG_TRACE_FUNC, "The server supports deref method %s\n",
2956 : deref_oids[i][1]);
2957 0 : return true;
2958 : }
2959 : }
2960 :
2961 0 : return false;
2962 : }
|