On Tue, Jan 26, 2010 at 01:21:31PM -0500, Stephen Gallagher wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On 01/20/2010 06:48 AM, Sumit Bose wrote: > > Hi, > > > > these two patches are a first step to handle LDAP referrals. The first > > patch changes the way we add a file descriptor event to the event loop. > > Currently it was extracted from the LDAP handle. But here only the fd to > > the 'primary' LDAP server is stored. If a referral is found and > > LDAP_OPT_REFERRALS is set to LDAP_OPT_ON the openLDAP library will open > > new connections to the new LDAP servers automatically. To keep track of > > the activity on these connection we need to add the new fds to the event > > loop, too. > > > > To get the fds this patch introduces a connection callback where the fd > > is extracted from the provided data and added to the event loop. There > > is another callback which removes the fd from the event loop when > > ldap_unbind is called. > > > > The second patch adds the config option ldap_referrals to switch the > > referral chasing on and off. > > > > Authentication with referrals currently work under the following > > conditions: > > - the DN of the user is the same on both LDAP servers > > - the LDAP server is RHDS/FDS/389, openLDAP does not return the > > 'Referral' error code when binding to a referral object > > > > bye, > > Sumit > > > > Nack. > > Patch 0001: > Please use talloc_get_type() instead of casting lc_arg to (struct > ldap_cb_data *). This is safer, as talloc_get_type() will return NULL if > it is not in fact of type "struct ldap_cb_data". I'd rather see an > easy-to-track segfault than have us potentially clobbering data. > > Patch 0002: > You need to add the new option to the SSSDConfig API as well, please. > > - -- > Stephen Gallagher > RHCE 804006346421761 >
New versions attached. bye, Sumit
From 281180c78490b28d87d07c2dd148d510e6ccd1c7 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Tue, 19 Jan 2010 12:32:02 +0100 Subject: [PATCH 1/2] Use ldap connection callbacks to get file descriptors --- server/providers/ldap/sdap.h | 16 ++++- server/providers/ldap/sdap_async.c | 101 ++++++++++++++++++------- server/providers/ldap/sdap_async_connection.c | 40 +++++++--- server/providers/ldap/sdap_async_private.h | 7 +- 4 files changed, 121 insertions(+), 43 deletions(-) diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h index 2909f41..a5b9e83 100644 --- a/server/providers/ldap/sdap.h +++ b/server/providers/ldap/sdap.h @@ -53,11 +53,25 @@ struct sdap_op { struct sdap_msg *last; }; +struct fd_event_item { + struct fd_event_item *prev; + struct fd_event_item *next; + + int fd; + struct tevent_fd *fde; +}; + +struct ldap_cb_data { + struct sdap_handle *sh; + struct tevent_context *ev; + struct fd_event_item *fd_list; +}; + struct sdap_handle { LDAP *ldap; bool connected; - struct tevent_fd *fde; + struct ldap_conncb *conncb; struct sdap_op *ops; }; diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c index 706101b..fd8c11e 100644 --- a/server/providers/ldap/sdap_async.c +++ b/server/providers/ldap/sdap_async.c @@ -91,13 +91,14 @@ static int sdap_handle_destructor(void *mem) static void sdap_handle_release(struct sdap_handle *sh) { - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], fde[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->fde, sh->ldap)); + 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; - talloc_zfree(sh->fde); + /* remove all related fd events from the event loop */ + talloc_zfree(sh->conncb->lc_arg); while (sh->ops) { op = sh->ops; @@ -110,26 +111,13 @@ static void sdap_handle_release(struct sdap_handle *sh) if (sh->ldap) { ldap_unbind_ext(sh->ldap, NULL, NULL); } + talloc_zfree(sh->conncb); sh->connected = false; sh->ldap = NULL; sh->ops = NULL; } } -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; -} - /* ==Parse-Results-And-Handle-Disconnections============================== */ static void sdap_process_message(struct tevent_context *ev, struct sdap_handle *sh, LDAPMessage *msg); @@ -160,8 +148,8 @@ static void sdap_process_result(struct tevent_context *ev, void *pvt) LDAPMessage *msg; int ret; - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], fde[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->fde, sh->ldap)); + 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")); @@ -342,24 +330,79 @@ static void sdap_process_next_reply(struct tevent_context *ev, op->callback(op, op->list, EOK, op->data); } -int sdap_install_ldap_callbacks(struct sdap_handle *sh, - struct tevent_context *ev) +int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, + struct sockaddr *addr, struct ldap_conncb *ctx) { - int fd; 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 = get_fd_from_ldap(sh->ldap, &fd); - if (ret) return ret; + 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; + } - sh->fde = tevent_add_fd(ev, sh, fd, TEVENT_FD_READ, sdap_ldap_result, sh); - if (!sh->fde) 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; - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], fde[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->fde, sh->ldap)); + DLIST_ADD(cb_data->fd_list, fd_event_item); - return EOK; + 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; +} /* ==LDAP-Operations-Helpers============================================== */ diff --git a/server/providers/ldap/sdap_async_connection.c b/server/providers/ldap/sdap_async_connection.c index 7ccb301..99cb375 100644 --- a/server/providers/ldap/sdap_async_connection.c +++ b/server/providers/ldap/sdap_async_connection.c @@ -56,6 +56,7 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, int lret; int ret = EOK; int msgid; + struct ldap_cb_data *cb_data; req = tevent_req_create(memctx, &state, struct sdap_connect_state); if (!req) return NULL; @@ -108,6 +109,34 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, goto fail; } + /* 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; + } + + 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; + + 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; + + 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; + } + /* if we do not use start_tls the connection is not really connected yet * just fake an async procedure and leave connection to the bind call */ if (!use_start_tls) { @@ -124,8 +153,6 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, } state->sh->connected = true; - ret = sdap_install_ldap_callbacks(state->sh, state->ev); - if (ret) goto fail; /* FIXME: get timeouts from configuration, for now 5 secs. */ ret = sdap_op_add(state, ev, state->sh, msgid, @@ -297,8 +324,6 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, if (!sh->connected) { sh->connected = true; - ret = sdap_install_ldap_callbacks(sh, ev); - if (ret) goto fail; } /* FIXME: get timeouts from configuration, for now 5 secs. */ @@ -464,8 +489,6 @@ static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx, if (!sh->connected) { sh->connected = true; - ret = sdap_install_ldap_callbacks(sh, ev); - if (ret) goto fail; } tevent_req_post(req, ev); @@ -889,7 +912,6 @@ static void sdap_cli_rootdse_step(struct tevent_req *req) struct sdap_cli_connect_state *state = tevent_req_data(req, struct sdap_cli_connect_state); struct tevent_req *subreq; - int ret; subreq = sdap_get_rootdse_send(state, state->ev, state->opts, state->sh); if (!subreq) { @@ -903,10 +925,6 @@ static void sdap_cli_rootdse_step(struct tevent_req *req) * so we need to set up the callbacks or we will never get notified * of a reply */ state->sh->connected = true; - ret = sdap_install_ldap_callbacks(state->sh, state->ev); - if (ret) { - tevent_req_error(req, ret); - } } } diff --git a/server/providers/ldap/sdap_async_private.h b/server/providers/ldap/sdap_async_private.h index 9237f15..5549626 100644 --- a/server/providers/ldap/sdap_async_private.h +++ b/server/providers/ldap/sdap_async_private.h @@ -26,8 +26,11 @@ void make_realm_upper_case(const char *upn); struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx); -int sdap_install_ldap_callbacks(struct sdap_handle *sh, - struct tevent_context *ev); + +int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, + struct sockaddr *addr, struct ldap_conncb *ctx); +void sdap_ldap_connect_callback_del(LDAP *ld, Sockbuf *sb, + struct ldap_conncb *ctx); int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, int msgid, -- 1.6.6
From efd0b84017c16537738522477af7d21ffa89d4a1 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Wed, 20 Jan 2010 11:21:50 +0100 Subject: [PATCH 2/2] Add new option ldap_referrals --- server/config/SSSDConfig.py | 1 + server/config/etc/sssd.api.d/sssd-ipa.conf | 1 + server/config/etc/sssd.api.d/sssd-ldap.conf | 1 + server/man/sssd-ldap.5.xml | 13 +++++++++++++ server/providers/ldap/ldap_common.c | 3 ++- server/providers/ldap/sdap.h | 1 + server/providers/ldap/sdap_async_connection.c | 11 +++++++++++ 7 files changed, 30 insertions(+), 1 deletions(-) diff --git a/server/config/SSSDConfig.py b/server/config/SSSDConfig.py index d31fbe2..b08e9f4 100644 --- a/server/config/SSSDConfig.py +++ b/server/config/SSSDConfig.py @@ -115,6 +115,7 @@ option_strings = { 'krb5_realm' : _('Kerberos realm'), 'ldap_krb5_keytab' : _('Kerberos service keytab'), 'ldap_krb5_init_creds' : _('Use Kerberos auth for LDAP connection'), + 'ldap_referrals' : _('Follow LDAP referrals'), # [provider/ldap/id] 'ldap_search_timeout' : _('Length of time to wait for a search request'), diff --git a/server/config/etc/sssd.api.d/sssd-ipa.conf b/server/config/etc/sssd.api.d/sssd-ipa.conf index 7a6cd87..7c1a827 100644 --- a/server/config/etc/sssd.api.d/sssd-ipa.conf +++ b/server/config/etc/sssd.api.d/sssd-ipa.conf @@ -22,6 +22,7 @@ ldap_krb5_keytab = str, None ldap_krb5_init_creds = bool, None ldap_entry_usn = str, None ldap_rootdse_last_usn = str, None +ldap_referrals = bool, None [provider/ipa/id] ldap_search_timeout = int, None diff --git a/server/config/etc/sssd.api.d/sssd-ldap.conf b/server/config/etc/sssd.api.d/sssd-ldap.conf index 314f57f..e6418ec 100644 --- a/server/config/etc/sssd.api.d/sssd-ldap.conf +++ b/server/config/etc/sssd.api.d/sssd-ldap.conf @@ -18,6 +18,7 @@ ldap_krb5_keytab = str, None ldap_krb5_init_creds = bool, None ldap_entry_usn = str, None ldap_rootdse_last_usn = str, None +ldap_referrals = bool, None [provider/ldap/id] ldap_search_timeout = int, None diff --git a/server/man/sssd-ldap.5.xml b/server/man/sssd-ldap.5.xml index affa2d1..2737c24 100644 --- a/server/man/sssd-ldap.5.xml +++ b/server/man/sssd-ldap.5.xml @@ -614,6 +614,19 @@ </listitem> </varlistentry> + <varlistentry> + <term>ldap_referrals (boolean)</term> + <listitem> + <para> + Specifies whether automatic referral chasing should + be enabled. + </para> + <para> + Default: true + </para> + </listitem> + </varlistentry> + </variablelist> </para> </refsect1> diff --git a/server/providers/ldap/ldap_common.c b/server/providers/ldap/ldap_common.c index 74b478c..15d44dc 100644 --- a/server/providers/ldap/ldap_common.c +++ b/server/providers/ldap/ldap_common.c @@ -61,7 +61,8 @@ struct dp_option default_basic_opts[] = { { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, /* use the same parm name as the krb5 module so we set it only once */ { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING } + { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING }, + { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE } }; struct sdap_attr_map generic_attr_map[] = { diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h index a5b9e83..f32ce05 100644 --- a/server/providers/ldap/sdap.h +++ b/server/providers/ldap/sdap.h @@ -137,6 +137,7 @@ enum sdap_basic_opt { SDAP_KRB5_KINIT, SDAP_KRB5_REALM, SDAP_PWD_POLICY, + SDAP_REFERRALS, SDAP_OPTS_BASIC /* opts counter */ }; diff --git a/server/providers/ldap/sdap_async_connection.c b/server/providers/ldap/sdap_async_connection.c index 99cb375..1ed6b3f 100644 --- a/server/providers/ldap/sdap_async_connection.c +++ b/server/providers/ldap/sdap_async_connection.c @@ -57,6 +57,7 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, int ret = EOK; int msgid; struct ldap_cb_data *cb_data; + bool ldap_referrals; req = tevent_req_create(memctx, &state, struct sdap_connect_state); if (!req) return NULL; @@ -109,6 +110,16 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, goto fail; } + /* Set Referral chasing */ + ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS); + lret = ldap_set_option(state->sh->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", + (ldap_referrals ? "LDAP_OPT_ON" : "LDAP_OPT_OFF"))); + goto fail; + } + /* add connection callback */ state->sh->conncb = talloc_zero(state->sh, struct ldap_conncb); if (state->sh->conncb == NULL) { -- 1.6.6
_______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/sssd-devel