diff options
Diffstat (limited to 'server/providers/ldap/sdap_async.c')
-rw-r--r-- | server/providers/ldap/sdap_async.c | 1018 |
1 files changed, 0 insertions, 1018 deletions
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c deleted file mode 100644 index 959c08a6..00000000 --- a/server/providers/ldap/sdap_async.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - SSSD - - Async LDAP Helper routines - - Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <ctype.h> -#include "util/util.h" -#include "providers/ldap/sdap_async_private.h" - -#define REALM_SEPARATOR '@' -#define REPLY_REALLOC_INCREMENT 10 - -void make_realm_upper_case(const char *upn) -{ - char *c; - - c = strchr(upn, REALM_SEPARATOR); - if (c == NULL) { - DEBUG(9, ("No realm delimiter found in upn [%s].\n", upn)); - return; - } - - while(*(++c) != '\0') { - c[0] = toupper(*c); - } - - return; -} - -/* ==LDAP-Memory-Handling================================================= */ - -static int lmsg_destructor(void *mem) -{ - ldap_msgfree((LDAPMessage *)mem); - return 0; -} - -static int sdap_msg_attach(TALLOC_CTX *memctx, LDAPMessage *msg) -{ - void *h; - - if (!msg) return EINVAL; - - h = sss_mem_attach(memctx, msg, lmsg_destructor); - if (!h) return ENOMEM; - - return EOK; -} - -/* ==sdap-hanlde-utility-functions======================================== */ - -static inline void sdap_handle_release(struct sdap_handle *sh); -static int sdap_handle_destructor(void *mem); - -struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx) -{ - struct sdap_handle *sh; - - sh = talloc_zero(memctx, struct sdap_handle); - if (!sh) return NULL; - - talloc_set_destructor((TALLOC_CTX *)sh, sdap_handle_destructor); - - return sh; -} - -static int sdap_handle_destructor(void *mem) -{ - struct sdap_handle *sh = talloc_get_type(mem, struct sdap_handle); - - sdap_handle_release(sh); - - return 0; -} - -static void sdap_handle_release(struct sdap_handle *sh) -{ - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->ldap)); - - if (sh->connected) { - struct sdap_op *op; - -#ifdef HAVE_LDAP_CONNCB - /* remove all related fd events from the event loop */ - talloc_zfree(sh->conncb->lc_arg); -#else - talloc_zfree(sh->fde); -#endif - - while (sh->ops) { - op = sh->ops; - op->callback(op, NULL, EIO, op->data); - /* calling the callback may result in freeing the op */ - /* check if it is still the same or avoid freeing */ - if (op == sh->ops) talloc_free(op); - } - - if (sh->ldap) { - ldap_unbind_ext(sh->ldap, NULL, NULL); - } -#ifdef HAVE_LDAP_CONNCB - talloc_zfree(sh->conncb); -#endif - sh->connected = false; - sh->ldap = NULL; - sh->ops = NULL; - } -} - -/* ==Parse-Results-And-Handle-Disconnections============================== */ -static void sdap_process_message(struct tevent_context *ev, - struct sdap_handle *sh, LDAPMessage *msg); -static void sdap_process_result(struct tevent_context *ev, void *pvt); -static void sdap_process_next_reply(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt); - -static void sdap_ldap_result(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *pvt) -{ - sdap_process_result(ev, pvt); -} - -static void sdap_ldap_next_result(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - sdap_process_result(ev, pvt); -} - -static void sdap_process_result(struct tevent_context *ev, void *pvt) -{ - struct sdap_handle *sh = talloc_get_type(pvt, struct sdap_handle); - struct timeval no_timeout = {0, 0}; - struct tevent_timer *te; - LDAPMessage *msg; - int ret; - - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->ldap)); - - if (!sh->connected || !sh->ldap) { - DEBUG(2, ("ERROR: LDAP connection is not connected!\n")); - return; - } - - ret = ldap_result(sh->ldap, LDAP_RES_ANY, 0, &no_timeout, &msg); - if (ret == 0) { - /* this almost always means we have reached the end of - * the list of received messages */ - DEBUG(8, ("Trace: ldap_result found nothing!\n")); - return; - } - - if (ret == -1) { - DEBUG(4, ("ldap_result gave -1, something bad happend!\n")); - sdap_handle_release(sh); - return; - } - - /* We don't know if this will be the last result. - * - * important: we must do this before actually processing the message - * because the message processing might even free the sdap_handler - * so it must be the last operation. - * FIXME: use tevent_immediate/tevent_queues, when avilable */ - memset(&no_timeout, 0, sizeof(struct timeval)); - - te = tevent_add_timer(ev, sh, no_timeout, sdap_ldap_next_result, sh); - if (!te) { - DEBUG(1, ("Failed to add critical timer to fetch next result!\n")); - } - - /* now process this message */ - sdap_process_message(ev, sh, msg); -} - -/* process a messgae calling the right operation callback. - * msg is completely taken care of (including freeeing it) - * NOTE: this function may even end up freeing the sdap_handle - * so sdap_hanbdle must not be used after this function is called - */ -static void sdap_process_message(struct tevent_context *ev, - struct sdap_handle *sh, LDAPMessage *msg) -{ - struct sdap_msg *reply; - struct sdap_op *op; - int msgid; - int msgtype; - int ret; - - msgid = ldap_msgid(msg); - if (msgid == -1) { - DEBUG(2, ("can't fire callback, message id invalid!\n")); - ldap_msgfree(msg); - return; - } - - msgtype = ldap_msgtype(msg); - - for (op = sh->ops; op; op = op->next) { - if (op->msgid == msgid) break; - } - - if (op == NULL) { - DEBUG(2, ("Unmatched msgid, discarding message (type: %0x)\n", - msgtype)); - ldap_msgfree(msg); - return; - } - - /* shouldn't happen */ - if (op->done) { - DEBUG(2, ("Operation [%p] already handled (type: %0x)\n", op, msgtype)); - ldap_msgfree(msg); - return; - } - - switch (msgtype) { - case LDAP_RES_SEARCH_ENTRY: - /* go and process entry */ - break; - - case LDAP_RES_SEARCH_REFERENCE: - /* more ops to come with this msgid */ - /* just ignore */ - ldap_msgfree(msg); - return; - - case LDAP_RES_BIND: - case LDAP_RES_SEARCH_RESULT: - case LDAP_RES_MODIFY: - case LDAP_RES_ADD: - case LDAP_RES_DELETE: - case LDAP_RES_MODDN: - case LDAP_RES_COMPARE: - case LDAP_RES_EXTENDED: - case LDAP_RES_INTERMEDIATE: - /* no more results expected with this msgid */ - op->done = true; - break; - - default: - /* unkwon msg type ?? */ - DEBUG(1, ("Couldn't figure out the msg type! [%0x]\n", msgtype)); - ldap_msgfree(msg); - return; - } - - reply = talloc_zero(op, struct sdap_msg); - if (!reply) { - ldap_msgfree(msg); - ret = ENOMEM; - } else { - reply->msg = msg; - ret = sdap_msg_attach(reply, msg); - if (ret != EOK) { - ldap_msgfree(msg); - talloc_zfree(reply); - } - } - - if (op->list) { - /* list exist, queue it */ - - op->last->next = reply; - op->last = reply; - - } else { - /* create list, then call callback */ - op->list = op->last = reply; - - /* must be the last operation as it may end up freeing all memory - * including all ops handlers */ - op->callback(op, reply, ret, op->data); - } -} - -static void sdap_unlock_next_reply(struct sdap_op *op) -{ - struct timeval tv; - struct tevent_timer *te; - struct sdap_msg *next_reply; - - if (op->list) { - next_reply = op->list->next; - /* get rid of the previous reply, it has been processed already */ - talloc_zfree(op->list); - op->list = next_reply; - } - - /* if there are still replies to parse, queue a new operation */ - if (op->list) { - /* use a very small timeout, so that fd operations have a chance to be - * served while processing a long reply */ - tv = tevent_timeval_current(); - - /* wait 5 microsecond */ - tv.tv_usec += 5; - tv.tv_sec += tv.tv_usec / 1000000; - tv.tv_usec = tv.tv_usec % 1000000; - - te = tevent_add_timer(op->ev, op, tv, - sdap_process_next_reply, op); - if (!te) { - DEBUG(1, ("Failed to add critical timer for next reply!\n")); - op->callback(op, NULL, EFAULT, op->data); - } - } -} - -static void sdap_process_next_reply(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct sdap_op *op = talloc_get_type(pvt, struct sdap_op); - - op->callback(op, op->list, EOK, op->data); -} - -#ifdef HAVE_LDAP_CONNCB -int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, - struct sockaddr *addr, struct ldap_conncb *ctx) -{ - int ret; - ber_socket_t ber_fd; - struct fd_event_item *fd_event_item; - struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg, - struct ldap_cb_data); - - ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd); - if (ret == -1) { - DEBUG(1, ("ber_sockbuf_ctrl failed.\n")); - return EINVAL; - } - DEBUG(9, ("New LDAP connection to [%s] with fd [%d].\n", - ldap_url_desc2str(srv), ber_fd)); - - fd_event_item = talloc_zero(cb_data, struct fd_event_item); - if (fd_event_item == NULL) { - DEBUG(1, ("talloc failed.\n")); - return ENOMEM; - } - - fd_event_item->fde = tevent_add_fd(cb_data->ev, fd_event_item, ber_fd, - TEVENT_FD_READ, sdap_ldap_result, - cb_data->sh); - if (fd_event_item->fde == NULL) { - DEBUG(1, ("tevent_add_fd failed.\n")); - talloc_free(fd_event_item); - return ENOMEM; - } - fd_event_item->fd = ber_fd; - - DLIST_ADD(cb_data->fd_list, fd_event_item); - - return LDAP_SUCCESS; -} - -void sdap_ldap_connect_callback_del(LDAP *ld, Sockbuf *sb, - struct ldap_conncb *ctx) -{ - int ret; - ber_socket_t ber_fd; - struct fd_event_item *fd_event_item; - struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg, - struct ldap_cb_data); - - if (sb == NULL || cb_data == NULL) { - return; - } - - ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd); - if (ret == -1) { - DEBUG(1, ("ber_sockbuf_ctrl failed.\n")); - return; - } - DEBUG(9, ("Closing LDAP connection with fd [%d].\n", ber_fd)); - - DLIST_FOR_EACH(fd_event_item, cb_data->fd_list) { - if (fd_event_item->fd == ber_fd) { - break; - } - } - if (fd_event_item == NULL) { - DEBUG(1, ("No event for fd [%d] found.\n", ber_fd)); - return; - } - - DLIST_REMOVE(cb_data->fd_list, fd_event_item); - talloc_zfree(fd_event_item); - - return; -} - -#else - -static int get_fd_from_ldap(LDAP *ldap, int *fd) -{ - int ret; - - ret = ldap_get_option(ldap, LDAP_OPT_DESC, fd); - if (ret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to get fd from ldap!!\n")); - *fd = -1; - return EIO; - } - - return EOK; -} - -int sdap_install_ldap_callbacks(struct sdap_handle *sh, - struct tevent_context *ev) -{ - int fd; - int ret; - - ret = get_fd_from_ldap(sh->ldap, &fd); - if (ret) return ret; - - sh->fde = tevent_add_fd(ev, sh, fd, TEVENT_FD_READ, sdap_ldap_result, sh); - if (!sh->fde) return ENOMEM; - - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], fde[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->fde, sh->ldap)); - - return EOK; -} - -#endif - - -/* ==LDAP-Operations-Helpers============================================== */ - -static int sdap_op_destructor(void *mem) -{ - struct sdap_op *op = (struct sdap_op *)mem; - - DLIST_REMOVE(op->sh->ops, op); - - if (op->done) return 0; - - /* we don't check the result here, if a message was really abandoned, - * hopefully the server will get an abandon. - * If the operation was already fully completed, this is going to be - * just a noop */ - ldap_abandon_ext(op->sh->ldap, op->msgid, NULL, NULL); - - return 0; -} - -static void sdap_op_timeout(struct tevent_req *req) -{ - struct sdap_op *op = tevent_req_callback_data(req, struct sdap_op); - - /* should never happen, but just in case */ - if (op->done) { - DEBUG(2, ("Timeout happened after op was finished !?\n")); - return; - } - - /* signal the caller that we have a timeout */ - op->callback(op, NULL, ETIMEDOUT, op->data); -} - -int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev, - struct sdap_handle *sh, int msgid, - sdap_op_callback_t *callback, void *data, - int timeout, struct sdap_op **_op) -{ - struct sdap_op *op; - - op = talloc_zero(memctx, struct sdap_op); - if (!op) return ENOMEM; - - op->sh = sh; - op->msgid = msgid; - op->callback = callback; - op->data = data; - op->ev = ev; - - /* check if we need to set a timeout */ - if (timeout) { - struct tevent_req *req; - struct timeval tv; - - tv = tevent_timeval_current(); - tv = tevent_timeval_add(&tv, timeout, 0); - - /* allocate on op, so when it get freed the timeout is removed */ - req = tevent_wakeup_send(op, ev, tv); - if (!req) { - talloc_zfree(op); - return ENOMEM; - } - tevent_req_set_callback(req, sdap_op_timeout, op); - } - - DLIST_ADD(sh->ops, op); - - talloc_set_destructor((TALLOC_CTX *)op, sdap_op_destructor); - - *_op = op; - return EOK; -} - -/* ==Modify-Password====================================================== */ - -struct sdap_exop_modify_passwd_state { - struct sdap_handle *sh; - - struct sdap_op *op; - - int result; - char *user_error_message; -}; - -static void sdap_exop_modify_passwd_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - char *user_dn, - char *password, - char *new_password) -{ - struct tevent_req *req = NULL; - struct sdap_exop_modify_passwd_state *state; - int ret; - BerElement *ber = NULL; - struct berval *bv = NULL; - int msgid; - LDAPControl *request_controls[2]; - - req = tevent_req_create(memctx, &state, - struct sdap_exop_modify_passwd_state); - if (!req) return NULL; - - state->sh = sh; - state->user_error_message = NULL; - - ber = ber_alloc_t( LBER_USE_DER ); - if (ber == NULL) { - DEBUG(7, ("ber_alloc_t failed.\n")); - talloc_zfree(req); - return NULL; - } - - ret = ber_printf( ber, "{tststs}", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, - user_dn, - LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, password, - LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, new_password); - if (ret == -1) { - DEBUG(1, ("ber_printf failed.\n")); - ber_free(ber, 1); - talloc_zfree(req); - return NULL; - } - - ret = ber_flatten(ber, &bv); - ber_free(ber, 1); - if (ret == -1) { - DEBUG(1, ("ber_flatten failed.\n")); - talloc_zfree(req); - return NULL; - } - - ret = sss_ldap_control_create(LDAP_CONTROL_PASSWORDPOLICYREQUEST, - 0, NULL, 0, &request_controls[0]); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("sss_ldap_control_create failed.\n")); - goto fail; - } - request_controls[1] = NULL; - - DEBUG(4, ("Executing extended operation\n")); - - ret = ldap_extended_operation(state->sh->ldap, LDAP_EXOP_MODIFY_PASSWD, - bv, request_controls, NULL, &msgid); - ber_bvfree(bv); - ldap_control_free(request_controls[0]); - if (ret == -1 || msgid == -1) { - DEBUG(1, ("ldap_extended_operation failed\n")); - goto fail; - } - DEBUG(8, ("ldap_extended_operation sent, msgid = %d\n", msgid)); - - /* FIXME: get timeouts from configuration, for now 5 secs. */ - ret = sdap_op_add(state, ev, state->sh, msgid, - sdap_exop_modify_passwd_done, req, 5, &state->op); - if (ret) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - tevent_req_error(req, EIO); - tevent_req_post(req, ev); - return req; -} - -static void sdap_exop_modify_passwd_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_exop_modify_passwd_state *state = tevent_req_data(req, - struct sdap_exop_modify_passwd_state); - char *errmsg = NULL; - int ret; - LDAPControl **response_controls = NULL; - int c; - ber_int_t pp_grace; - ber_int_t pp_expire; - LDAPPasswordPolicyError pp_error; - - if (error) { - tevent_req_error(req, error); - return; - } - - ret = ldap_parse_result(state->sh->ldap, reply->msg, - &state->result, NULL, &errmsg, NULL, - &response_controls, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - ret = EIO; - goto done; - } - - if (response_controls == NULL) { - DEBUG(5, ("Server returned no controls.\n")); - } else { - for (c = 0; response_controls[c] != NULL; c++) { - DEBUG(9, ("Server returned control [%s].\n", - response_controls[c]->ldctl_oid)); - if (strcmp(response_controls[c]->ldctl_oid, - LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) { - ret = ldap_parse_passwordpolicy_control(state->sh->ldap, - response_controls[c], - &pp_expire, &pp_grace, - &pp_error); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_parse_passwordpolicy_control failed.\n")); - ret = EIO; - goto done; - } - - DEBUG(7, ("Password Policy Response: expire [%d] grace [%d] " - "error [%s].\n", pp_expire, pp_grace, - ldap_passwordpolicy_err2txt(pp_error))); - } - } - } - - if (state->result != LDAP_SUCCESS) { - state->user_error_message = talloc_strdup(state, errmsg); - if (state->user_error_message == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - } - } - - DEBUG(3, ("ldap_extended_operation result: %s(%d), %s\n", - ldap_err2string(state->result), state->result, errmsg)); - - ret = LDAP_SUCCESS; -done: - ldap_controls_free(response_controls); - ldap_memfree(errmsg); - - if (ret == LDAP_SUCCESS) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } -} - -int sdap_exop_modify_passwd_recv(struct tevent_req *req, - TALLOC_CTX * mem_ctx, - enum sdap_result *result, - char **user_error_message) -{ - struct sdap_exop_modify_passwd_state *state = tevent_req_data(req, - struct sdap_exop_modify_passwd_state); - - *result = SDAP_ERROR; - *user_error_message = talloc_steal(mem_ctx, state->user_error_message); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (state->result == LDAP_SUCCESS) { - *result = SDAP_SUCCESS; - } - - return EOK; -} - -/* ==Fetch-RootDSE============================================= */ - -struct sdap_get_rootdse_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - - struct sysdb_attrs *rootdse; -}; - -static void sdap_get_rootdse_done(struct tevent_req *subreq); - -struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sdap_handle *sh) -{ - struct tevent_req *req, *subreq; - struct sdap_get_rootdse_state *state; - - DEBUG(9, ("Getting rootdse\n")); - - req = tevent_req_create(memctx, &state, struct sdap_get_rootdse_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sh = sh; - state->rootdse = NULL; - - subreq = sdap_get_generic_send(state, ev, opts, sh, - "", LDAP_SCOPE_BASE, - "(objectclass=*)", NULL, NULL, 0); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_get_rootdse_done, req); - - return req; -} - -static void sdap_get_rootdse_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_rootdse_state *state = tevent_req_data(req, - struct sdap_get_rootdse_state); - struct sysdb_attrs **results; - size_t num_results; - int ret; - - ret = sdap_get_generic_recv(subreq, state, &num_results, &results); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (num_results == 0 || !results) { - DEBUG(2, ("No RootDSE for server ?!\n")); - tevent_req_error(req, ENOENT); - return; - } - - if (num_results > 1) { - DEBUG(2, ("Multiple replies when searching for RootDSE ??\n")); - tevent_req_error(req, EIO); - return; - } - - state->rootdse = talloc_steal(state, results[0]); - talloc_zfree(results); - - DEBUG(9, ("Got rootdse\n")); - - tevent_req_done(req); -} - -int sdap_get_rootdse_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sysdb_attrs **rootdse) -{ - struct sdap_get_rootdse_state *state = tevent_req_data(req, - struct sdap_get_rootdse_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *rootdse = talloc_steal(memctx, state->rootdse); - - return EOK; -} - -/* ==Generic Search============================================ */ - -struct sdap_get_generic_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - const char *search_base; - int scope; - const char *filter; - const char **attrs; - struct sdap_attr_map *map; - int map_num_attrs; - - struct sdap_op *op; - - size_t reply_max; - size_t reply_count; - struct sysdb_attrs **reply; -}; - -static errno_t add_to_reply(struct sdap_get_generic_state *state, - struct sysdb_attrs *msg); - -static void sdap_get_generic_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sdap_handle *sh, - const char *search_base, - int scope, - const char *filter, - const char **attrs, - struct sdap_attr_map *map, - int map_num_attrs) -{ - struct tevent_req *req = NULL; - struct sdap_get_generic_state *state = NULL; - int lret; - int ret; - int msgid; - - req = tevent_req_create(memctx, &state, struct sdap_get_generic_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sh = sh; - state->search_base = search_base; - state->scope = scope; - state->filter = filter; - state->attrs = attrs; - state->map = map; - state->map_num_attrs = map_num_attrs; - state->op = NULL; - state->reply_max = 0; - state->reply_count = 0; - state->reply = NULL; - - DEBUG(6, ("calling ldap_search_ext with [%s][%s].\n", state->filter, - state->search_base)); - if (debug_level >= 7) { - int i; - - if (state->attrs) { - for (i = 0; state->attrs[i]; i++) { - DEBUG(7, ("Requesting attrs: [%s]\n", state->attrs[i])); - } - } - } - - lret = ldap_search_ext(state->sh->ldap, state->search_base, - state->scope, state->filter, - discard_const(state->attrs), - false, NULL, NULL, NULL, 0, &msgid); - if (lret != LDAP_SUCCESS) { - DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(lret))); - ret = EIO; - goto fail; - } - DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid)); - - ret = sdap_op_add(state, state->ev, state->sh, msgid, - sdap_get_generic_done, req, - dp_opt_get_int(state->opts->basic, - SDAP_SEARCH_TIMEOUT), - &state->op); - if (ret != EOK) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - - -static void sdap_get_generic_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_get_generic_state *state = tevent_req_data(req, - struct sdap_get_generic_state); - struct sysdb_attrs *attrs; - char *errmsg; - int result; - int ret; - - if (error) { - tevent_req_error(req, error); - return; - } - - switch (ldap_msgtype(reply->msg)) { - case LDAP_RES_SEARCH_REFERENCE: - /* ignore references for now */ - talloc_free(reply); - - /* unlock the operation so that we can proceed with the next result */ - sdap_unlock_next_reply(state->op); - break; - - case LDAP_RES_SEARCH_ENTRY: - ret = sdap_parse_entry(state, state->sh, reply, - state->map, state->map_num_attrs, - &attrs, NULL); - if (ret != EOK) { - DEBUG(1, ("sdap_parse_generic_entry failed.\n")); - tevent_req_error(req, ENOMEM); - return; - } - - ret = add_to_reply(state, attrs); - if (ret != EOK) { - DEBUG(1, ("add_to_reply failed.\n")); - tevent_req_error(req, ret); - return; - } - - sdap_unlock_next_reply(state->op); - break; - - case LDAP_RES_SEARCH_RESULT: - ret = ldap_parse_result(state->sh->ldap, reply->msg, - &result, NULL, &errmsg, NULL, NULL, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - tevent_req_error(req, EIO); - return; - } - - DEBUG(6, ("Search result: %s(%d), %s\n", - ldap_err2string(result), result, errmsg)); - - tevent_req_done(req); - return; - - default: - /* what is going on here !? */ - tevent_req_error(req, EIO); - return; - } -} - -static errno_t add_to_reply(struct sdap_get_generic_state *state, - struct sysdb_attrs *msg) -{ - if (state->reply == NULL || state->reply_max == state->reply_count) { - state->reply_max += REPLY_REALLOC_INCREMENT; - state->reply = talloc_realloc(state, state->reply, - struct sysdb_attrs *, - state->reply_max); - if (state->reply == NULL) { - DEBUG(1, ("talloc_realloc failed.\n")); - return ENOMEM; - } - } - - state->reply[state->reply_count++] = talloc_steal(state->reply, msg); - - return EOK; -} - -int sdap_get_generic_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - size_t *reply_count, - struct sysdb_attrs ***reply) -{ - struct sdap_get_generic_state *state = tevent_req_data(req, - struct sdap_get_generic_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *reply_count = state->reply_count; - *reply = talloc_steal(mem_ctx, state->reply); - - return EOK; -} - |