>From c15fa1d52b8b3f2e854530ac54761e3ed2135ae3 Mon Sep 17 00:00:00 2001 From: eindenbom Date: Wed, 14 Apr 2010 10:30:33 +0400 Subject: [PATCH] Fixed recursive sdap_handle disconnect sequence from sdap_process_result: 1. sdap_process_result calls on communication error sdap_handle_release 2. sdap_handle_release calls active sdap_op callback 3. callback deletes sdap_handle 4. sdap_release_handle segfaults or asserts on access to deallocated memory --- src/providers/ldap/sdap.c | 30 +++--- src/providers/ldap/sdap.h | 13 +-- src/providers/ldap/sdap_async.c | 155 ++++++++++++++++++---------- src/providers/ldap/sdap_async_connection.c | 90 +++++++++------- src/providers/ldap/sdap_async_private.h | 43 ++++++++ 5 files changed, 213 insertions(+), 118 deletions(-) diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c index 39c67cc..1b02807 100644 --- a/src/providers/ldap/sdap.c +++ b/src/providers/ldap/sdap.c @@ -22,7 +22,7 @@ #define LDAP_DEPRECATED 1 #include "util/util.h" #include "confdb/confdb.h" -#include "providers/ldap/sdap.h" +#include "providers/ldap/sdap_async_private.h" /* =Retrieve-Options====================================================== */ @@ -73,6 +73,7 @@ int sdap_parse_entry(TALLOC_CTX *memctx, struct sdap_attr_map *map, int attrs_num, struct sysdb_attrs **_attrs, char **_dn) { + LDAP* ldap = sh->private->ldap; struct sysdb_attrs *attrs; BerElement *ber = NULL; struct berval **vals; @@ -84,14 +85,14 @@ int sdap_parse_entry(TALLOC_CTX *memctx, bool store; lerrno = 0; - ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + ldap_set_option(ldap, LDAP_OPT_RESULT_CODE, &lerrno); attrs = sysdb_new_attrs(memctx); if (!attrs) return ENOMEM; - str = ldap_get_dn(sh->ldap, sm->msg); + str = ldap_get_dn(ldap, sm->msg); if (!str) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + ldap_get_option(ldap, LDAP_OPT_RESULT_CODE, &lerrno); DEBUG(1, ("ldap_get_dn failed: %d(%s)\n", lerrno, ldap_err2string(lerrno))); ret = EIO; @@ -112,7 +113,7 @@ int sdap_parse_entry(TALLOC_CTX *memctx, ldap_memfree(str); if (map) { - vals = ldap_get_values_len(sh->ldap, sm->msg, "objectClass"); + vals = ldap_get_values_len(ldap, sm->msg, "objectClass"); if (!vals) { DEBUG(1, ("Unknown entry type, no objectClasses found!\n")); ret = EINVAL; @@ -137,9 +138,9 @@ int sdap_parse_entry(TALLOC_CTX *memctx, ldap_value_free_len(vals); } - str = ldap_first_attribute(sh->ldap, sm->msg, &ber); + str = ldap_first_attribute(ldap, sm->msg, &ber); if (!str) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + ldap_get_option(ldap, LDAP_OPT_RESULT_CODE, &lerrno); DEBUG(1, ("Entry has no attributes [%d(%s)]!?\n", lerrno, ldap_err2string(lerrno))); if (map) { @@ -168,9 +169,9 @@ int sdap_parse_entry(TALLOC_CTX *memctx, } if (store) { - vals = ldap_get_values_len(sh->ldap, sm->msg, str); + vals = ldap_get_values_len(ldap, sm->msg, str); if (!vals) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + ldap_get_option(ldap, LDAP_OPT_RESULT_CODE, &lerrno); DEBUG(1, ("LDAP Library error: %d(%s)", lerrno, ldap_err2string(lerrno))); ret = EIO; @@ -192,11 +193,11 @@ int sdap_parse_entry(TALLOC_CTX *memctx, } ldap_memfree(str); - str = ldap_next_attribute(sh->ldap, sm->msg, ber); + str = ldap_next_attribute(ldap, sm->msg, ber); } ber_free(ber, 0); - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + ldap_get_option(ldap, LDAP_OPT_RESULT_CODE, &lerrno); if (lerrno) { DEBUG(1, ("LDAP Library error: %d(%s)", lerrno, ldap_err2string(lerrno))); @@ -246,15 +247,16 @@ int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts, int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh, struct sdap_msg *sm, char **_dn) { + LDAP* ldap = sh->private->ldap; char *str; int lerrno; lerrno = 0; - ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + ldap_set_option(ldap, LDAP_OPT_RESULT_CODE, &lerrno); - str = ldap_get_dn(sh->ldap, sm->msg); + str = ldap_get_dn(ldap, sm->msg); if (!str) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + ldap_get_option(ldap, LDAP_OPT_RESULT_CODE, &lerrno); DEBUG(1, ("ldap_get_dn failed: %d(%s)\n", lerrno, ldap_err2string(lerrno))); return EIO; diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index 007185f..779c7e4 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -37,10 +37,11 @@ typedef void (sdap_op_callback_t)(struct sdap_op *op, struct sdap_msg *, int, void *); struct sdap_handle; +struct sdap_handle_data; struct sdap_op { struct sdap_op *prev, *next; - struct sdap_handle *sh; + struct sdap_handle_data *shd; int msgid; bool done; @@ -68,16 +69,8 @@ struct ldap_cb_data { }; struct sdap_handle { - LDAP *ldap; + struct sdap_handle_data *private; bool connected; - -#ifdef HAVE_LDAP_CONNCB - struct ldap_conncb *conncb; -#else - struct tevent_fd *fde; -#endif - - struct sdap_op *ops; }; struct sdap_service { diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index 15f3048..4c9b6b9 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -65,8 +65,9 @@ static int sdap_msg_attach(TALLOC_CTX *memctx, LDAPMessage *msg) /* ==sdap-hanlde-utility-functions======================================== */ -static inline void sdap_handle_release(struct sdap_handle *sh); -static int sdap_handle_destructor(void *mem); +static void sdap_handle_release(struct sdap_handle *sh, bool final); +static int sdap_handle_destructor(struct sdap_handle *sh); +static int sdap_op_destructor(struct sdap_op *op); struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx) { @@ -75,53 +76,85 @@ struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx) sh = talloc_zero(memctx, struct sdap_handle); if (!sh) return NULL; - talloc_set_destructor((TALLOC_CTX *)sh, sdap_handle_destructor); + talloc_set_destructor(sh, sdap_handle_destructor); + /* private data is allocated as top-level talloc context as + * it may need to survive for a while after main handle destruction, + * see sdap_handle_data_lock/sdap_handle_data_release */ + sh->private = talloc_zero(NULL, struct sdap_handle_data); + if (!sh->private) { + goto fail; + } + + sh->private->sh = sh; return sh; + +fail: + talloc_zfree(sh); + return NULL; } -static int sdap_handle_destructor(void *mem) +static int sdap_handle_destructor(struct sdap_handle *sh) { - struct sdap_handle *sh = talloc_get_type(mem, struct sdap_handle); - - sdap_handle_release(sh); + sdap_handle_release(sh, true); return 0; } -static void sdap_handle_release(struct sdap_handle *sh) +static void sdap_handle_release(struct sdap_handle *sh, bool final) { + struct sdap_handle_data *shd = sh->private; + DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->ldap)); + sh, (int)sh->connected, shd->ops, shd->ldap)); + sdap_handle_data_lock(shd); 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 + /* mark as disconnected at once to prevent further activity on connection */ sh->connected = false; - sh->ldap = NULL; - sh->ops = NULL; + + if (shd->ldap) { +#ifdef HAVE_LDAP_CONNCB + if (shd->conncb) { + /* remove callback first */ + ldap_get_option(shd->ldap, LDAP_OPT_CONNECT_CB, shd->conncb); + + /* no free its data and remove all related fd events from the event loop */ + talloc_zfree(shd->conncb); + } +#else + talloc_zfree(shd->fde); +#endif + } } + + /* and notify remaining ops on failure */ + while (shd->ops) { + struct sdap_op *op = shd->ops; + + /* call destructor now to detach from sdap_handle and + * avoid repeated notify in nested sdap_handle_release */ + sdap_op_destructor(op); + + /* and now notify about broken connection */ + op->callback(op, NULL, EIO, op->data); + } + + /* we destroy LDAP handle after destroying all operations + * to free using ldap_abandon_ext all msgids stored in sdap_op */ + if (shd->ldap) { + LDAP* ldap = shd->ldap; + shd->ldap = NULL; + + ldap_unbind_ext(ldap, NULL, NULL); + } + + if (final) { + shd->sh = NULL; + sh->private = NULL; + } + + sdap_handle_data_release(shd); } /* ==Parse-Results-And-Handle-Disconnections============================== */ @@ -149,20 +182,21 @@ static void sdap_ldap_next_result(struct tevent_context *ev, static void sdap_process_result(struct tevent_context *ev, void *pvt) { struct sdap_handle *sh = talloc_get_type(pvt, struct sdap_handle); + LDAP *ldap = sh->private->ldap; 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)); + sh, (int)sh->connected, sh->private->ops, ldap)); - if (!sh->connected || !sh->ldap) { + if (!sh->connected || !ldap) { DEBUG(2, ("ERROR: LDAP connection is not connected!\n")); return; } - ret = ldap_result(sh->ldap, LDAP_RES_ANY, 0, &no_timeout, &msg); + ret = ldap_result(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 */ @@ -171,8 +205,8 @@ static void sdap_process_result(struct tevent_context *ev, void *pvt) } if (ret == -1) { - DEBUG(4, ("ldap_result gave -1, something bad happend!\n")); - sdap_handle_release(sh); + DEBUG(4, ("ldap_result gave -1, something bad happened!\n")); + sdap_handle_release(sh, false); return; } @@ -201,6 +235,7 @@ static void sdap_process_result(struct tevent_context *ev, void *pvt) static void sdap_process_message(struct tevent_context *ev, struct sdap_handle *sh, LDAPMessage *msg) { + struct sdap_handle_data *shd = sh->private; struct sdap_msg *reply; struct sdap_op *op; int msgid; @@ -216,7 +251,7 @@ static void sdap_process_message(struct tevent_context *ev, msgtype = ldap_msgtype(msg); - for (op = sh->ops; op; op = op->next) { + for (op = shd->ops; op; op = op->next) { if (op->msgid == msgid) break; } @@ -430,17 +465,18 @@ static int get_fd_from_ldap(LDAP *ldap, int *fd) int sdap_install_ldap_callbacks(struct sdap_handle *sh, struct tevent_context *ev) { + LDAP* ldap = sh->private->ldap; int fd; int ret; - ret = get_fd_from_ldap(sh->ldap, &fd); + ret = get_fd_from_ldap(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)); + sh, (int)sh->connected, sh->private->ops, sh->private->fde, ldap)); return EOK; } @@ -450,11 +486,17 @@ int sdap_install_ldap_callbacks(struct sdap_handle *sh, /* ==LDAP-Operations-Helpers============================================== */ -static int sdap_op_destructor(void *mem) +static int sdap_op_destructor(struct sdap_op *op) { - struct sdap_op *op = (struct sdap_op *)mem; + struct sdap_handle_data *shd = op->shd; - DLIST_REMOVE(op->sh->ops, op); + if (!shd) { + /* we are already detached */ + return 0; + } + + DLIST_REMOVE(shd->ops, op); + op->shd = NULL; if (op->done) return 0; @@ -462,7 +504,7 @@ static int sdap_op_destructor(void *mem) * 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); + ldap_abandon_ext(shd->ldap, op->msgid, NULL, NULL); return 0; } @@ -486,12 +528,12 @@ int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev, sdap_op_callback_t *callback, void *data, int timeout, struct sdap_op **_op) { + struct sdap_handle_data *shd = sh->private; 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; @@ -514,9 +556,10 @@ int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev, tevent_req_set_callback(req, sdap_op_timeout, op); } - DLIST_ADD(sh->ops, op); + talloc_set_destructor(op, sdap_op_destructor); - talloc_set_destructor((TALLOC_CTX *)op, sdap_op_destructor); + DLIST_ADD(shd->ops, op); + op->shd = shd; *_op = op; return EOK; @@ -544,6 +587,7 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, char *password, char *new_password) { + LDAP *ldap = sh->private->ldap; struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; int ret; @@ -595,7 +639,7 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing extended operation\n")); - ret = ldap_extended_operation(state->sh->ldap, LDAP_EXOP_MODIFY_PASSWD, + ret = ldap_extended_operation(ldap, LDAP_EXOP_MODIFY_PASSWD, bv, request_controls, NULL, &msgid); ber_bvfree(bv); ldap_control_free(request_controls[0]); @@ -628,6 +672,7 @@ static void sdap_exop_modify_passwd_done(struct sdap_op *op, 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); + LDAP* ldap = state->sh->private->ldap; char *errmsg = NULL; int ret; LDAPControl **response_controls = NULL; @@ -641,7 +686,7 @@ static void sdap_exop_modify_passwd_done(struct sdap_op *op, return; } - ret = ldap_parse_result(state->sh->ldap, reply->msg, + ret = ldap_parse_result(ldap, reply->msg, &state->result, NULL, &errmsg, NULL, &response_controls, 0); if (ret != LDAP_SUCCESS) { @@ -658,7 +703,7 @@ static void sdap_exop_modify_passwd_done(struct sdap_op *op, response_controls[c]->ldctl_oid)); if (strcmp(response_controls[c]->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) { - ret = ldap_parse_passwordpolicy_control(state->sh->ldap, + ret = ldap_parse_passwordpolicy_control(ldap, response_controls[c], &pp_expire, &pp_grace, &pp_error); @@ -848,6 +893,7 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, struct sdap_attr_map *map, int map_num_attrs) { + LDAP *ldap = sh->private->ldap; struct tevent_req *req = NULL; struct sdap_get_generic_state *state = NULL; int lret; @@ -883,7 +929,7 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, } } - lret = ldap_search_ext(state->sh->ldap, state->search_base, + lret = ldap_search_ext(ldap, state->search_base, state->scope, state->filter, discard_const(state->attrs), false, NULL, NULL, NULL, 0, &msgid); @@ -920,6 +966,7 @@ static void sdap_get_generic_done(struct sdap_op *op, 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); + LDAP* ldap = state->sh->private->ldap; struct sysdb_attrs *attrs; char *errmsg; int result; @@ -960,7 +1007,7 @@ static void sdap_get_generic_done(struct sdap_op *op, break; case LDAP_RES_SEARCH_RESULT: - ret = ldap_parse_result(state->sh->ldap, reply->msg, + ret = ldap_parse_result(ldap, reply->msg, &result, NULL, &errmsg, NULL, NULL, 0); if (ret != LDAP_SUCCESS) { DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index ad3d241..a1a918b 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -51,6 +51,7 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, { struct tevent_req *req; struct sdap_connect_state *state; + LDAP *ldap; struct timeval tv; int ver; int lret; @@ -74,16 +75,18 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, talloc_zfree(req); return NULL; } + /* Initialize LDAP handler */ - lret = ldap_initialize(&state->sh->ldap, uri); + lret = ldap_initialize(&ldap, uri); if (lret != LDAP_SUCCESS) { DEBUG(1, ("ldap_initialize failed: %s\n", ldap_err2string(lret))); goto fail; } + state->sh->private->ldap = ldap; /* Force ldap version to 3 */ ver = LDAP_VERSION3; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_PROTOCOL_VERSION, &ver); + lret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ver); if (lret != LDAP_OPT_SUCCESS) { DEBUG(1, ("Failed to set ldap version to 3\n")); goto fail; @@ -92,7 +95,7 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, /* Set Network Timeout */ tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT); tv.tv_usec = 0; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_NETWORK_TIMEOUT, &tv); + lret = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &tv); if (lret != LDAP_OPT_SUCCESS) { DEBUG(1, ("Failed to set network timeout to %d\n", dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT))); @@ -102,7 +105,7 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, /* Set Default Timeout */ tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT); tv.tv_usec = 0; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_TIMEOUT, &tv); + lret = ldap_set_option(ldap, LDAP_OPT_TIMEOUT, &tv); if (lret != LDAP_OPT_SUCCESS) { DEBUG(1, ("Failed to set default timeout to %d\n", dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT))); @@ -111,7 +114,7 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, /* Set Referral chasing */ ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS); - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_REFERRALS, + lret = ldap_set_option(ldap, LDAP_OPT_REFERRALS, (ldap_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF)); if (lret != LDAP_OPT_SUCCESS) { DEBUG(1, ("Failed to set referral chasing to %s\n", @@ -120,35 +123,38 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, } #ifdef HAVE_LDAP_CONNCB - struct ldap_cb_data *cb_data; + do { + struct ldap_conncb *conncb; + struct ldap_cb_data *cb_data; - /* add connection callback */ - state->sh->conncb = talloc_zero(state->sh, struct ldap_conncb); - if (state->sh->conncb == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - ret = ENOMEM; - goto fail; - } + /* add connection callback */ + conncb = talloc_zero(state->sh->private, struct ldap_conncb); + if (conncb == NULL) { + DEBUG(1, ("talloc_zero failed.\n")); + ret = ENOMEM; + goto fail; + } + state->sh->private->conncb = conncb; - cb_data = talloc_zero(state->sh->conncb, struct ldap_cb_data); - if (cb_data == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - ret = ENOMEM; - goto fail; - } - cb_data->sh = state->sh; - cb_data->ev = state->ev; + cb_data = talloc_zero(conncb, struct ldap_cb_data); + if (cb_data == NULL) { + DEBUG(1, ("talloc_zero failed.\n")); + ret = ENOMEM; + goto fail; + } + cb_data->sh = state->sh; + cb_data->ev = state->ev; - state->sh->conncb->lc_add = sdap_ldap_connect_callback_add; - state->sh->conncb->lc_del = sdap_ldap_connect_callback_del; - state->sh->conncb->lc_arg = cb_data; + conncb->lc_add = sdap_ldap_connect_callback_add; + conncb->lc_del = sdap_ldap_connect_callback_del; + conncb->lc_arg = cb_data; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_CONNECT_CB, - state->sh->conncb); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set connection callback\n")); - goto fail; - } + lret = ldap_set_option(ldap, LDAP_OPT_CONNECT_CB, conncb); + if (lret != LDAP_OPT_SUCCESS) { + DEBUG(1, ("Failed to set connection callback\n")); + goto fail; + } + } while(0); #endif /* if we do not use start_tls the connection is not really connected yet @@ -160,7 +166,7 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing START TLS\n")); - lret = ldap_start_tls(state->sh->ldap, NULL, NULL, &msgid); + lret = ldap_start_tls(ldap, NULL, NULL, &msgid); if (lret != LDAP_SUCCESS) { DEBUG(3, ("ldap_start_tls failed: [%s]\n", ldap_err2string(lret))); goto fail; @@ -203,6 +209,7 @@ static void sdap_connect_done(struct sdap_op *op, struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); struct sdap_connect_state *state = tevent_req_data(req, struct sdap_connect_state); + LDAP* ldap = state->sh->private->ldap; char *errmsg; int ret; @@ -213,7 +220,7 @@ static void sdap_connect_done(struct sdap_op *op, state->reply = talloc_steal(state, reply); - ret = ldap_parse_result(state->sh->ldap, state->reply->msg, + ret = ldap_parse_result(ldap, state->reply->msg, &state->result, NULL, &errmsg, NULL, NULL, 0); if (ret != LDAP_SUCCESS) { DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); @@ -224,14 +231,14 @@ static void sdap_connect_done(struct sdap_op *op, DEBUG(3, ("START TLS result: %s(%d), %s\n", ldap_err2string(state->result), state->result, errmsg)); - if (ldap_tls_inplace(state->sh->ldap)) { + if (ldap_tls_inplace(ldap)) { DEBUG(9, ("SSL/TLS handler already in place.\n")); tevent_req_done(req); return; } /* FIXME: take care that ldap_install_tls might block */ - ret = ldap_install_tls(state->sh->ldap); + ret = ldap_install_tls(ldap); if (ret != LDAP_SUCCESS) { DEBUG(1, ("ldap_install_tls failed: [%d][%s]\n", ret, ldap_err2string(ret))); @@ -293,6 +300,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, { struct tevent_req *req; struct simple_bind_state *state; + LDAP* ldap = sh->private->ldap; int ret = EOK; int msgid; int ldap_err; @@ -322,11 +330,11 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn)); - ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, + ret = ldap_sasl_bind(ldap, state->user_dn, LDAP_SASL_SIMPLE, state->pw, request_controls, NULL, &msgid); ldap_control_free(request_controls[0]); if (ret == -1 || msgid == -1) { - ret = ldap_get_option(state->sh->ldap, + ret = ldap_get_option(ldap, LDAP_OPT_RESULT_CODE, &ldap_err); if (ret != LDAP_OPT_SUCCESS) { DEBUG(1, ("ldap_bind failed (couldn't get ldap error)\n")); @@ -375,6 +383,7 @@ static void simple_bind_done(struct sdap_op *op, struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); struct simple_bind_state *state = tevent_req_data(req, struct simple_bind_state); + LDAP *ldap = state->sh->private->ldap; char *errmsg; int ret; LDAPControl **response_controls; @@ -390,7 +399,7 @@ static void simple_bind_done(struct sdap_op *op, state->reply = talloc_steal(state, reply); - ret = ldap_parse_result(state->sh->ldap, state->reply->msg, + ret = ldap_parse_result(ldap, state->reply->msg, &state->result, NULL, &errmsg, NULL, &response_controls, 0); if (ret != LDAP_SUCCESS) { @@ -407,7 +416,7 @@ static void simple_bind_done(struct sdap_op *op, response_controls[c]->ldctl_oid)); if (strcmp(response_controls[c]->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) { - ret = ldap_parse_passwordpolicy_control(state->sh->ldap, + ret = ldap_parse_passwordpolicy_control(ldap, response_controls[c], &pp_expire, &pp_grace, &pp_error); @@ -483,6 +492,7 @@ static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx, { struct tevent_req *req; struct sasl_bind_state *state; + LDAP* ldap = sh->private->ldap; int ret = EOK; req = tevent_req_create(memctx, &state, struct sasl_bind_state); @@ -499,7 +509,7 @@ static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx, /* Until ldap_sasl_interactive_bind_s() is async we may want to set * LDAP_OPT_RESTART to handle EINTR during poll(). */ - ret = ldap_set_option(state->sh->ldap, LDAP_OPT_RESTART, LDAP_OPT_ON); + ret = ldap_set_option(ldap, LDAP_OPT_RESTART, LDAP_OPT_ON); if (ret != LDAP_OPT_SUCCESS) { DEBUG(1, ("Failed to set restart option.\n")); } @@ -507,7 +517,7 @@ static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx, /* FIXME: Warning, this is a sync call! * No async variant exist in openldap libraries yet */ - ret = ldap_sasl_interactive_bind_s(state->sh->ldap, NULL, + ret = ldap_sasl_interactive_bind_s(ldap, NULL, sasl_mech, NULL, NULL, LDAP_SASL_QUIET, (*sdap_sasl_interact), state); diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h index 55f76ed..006af5c 100644 --- a/src/providers/ldap/sdap_async_private.h +++ b/src/providers/ldap/sdap_async_private.h @@ -25,9 +25,52 @@ #include "config.h" #include "providers/ldap/sdap_async.h" +/* private opaque data of SDAP handle */ +struct sdap_handle_data { + /* owner of the data */ + struct sdap_handle *sh; + + /* LDAP object */ + LDAP *ldap; + + /* connection callback */ +#ifdef HAVE_LDAP_CONNCB + struct ldap_conncb *conncb; +#else + struct tevent_fd *fde; +#endif + + /* list of active ops */ + struct sdap_op *ops; + + /* lock to prevent deletion in notify recursion */ + int destroy_lock; +}; + void make_realm_upper_case(const char *upn); struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx); +/* enter destruction protected section */ +static inline void sdap_handle_data_lock(struct sdap_handle_data *shd) +{ + shd->destroy_lock++; +} + +/* leave destruction protected section */ +static inline void sdap_handle_data_release(struct sdap_handle_data *shd) +{ + if (shd->destroy_lock > 0 && --shd->destroy_lock > 0) { + return; + } + + if (shd->sh) { + return; + } + + /* destroying orphan, unused private data */ + talloc_free(shd); +} + #ifdef HAVE_LDAP_CONNCB int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, struct sockaddr *addr, struct ldap_conncb *ctx); -- 1.6.6.1