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

Reply via email to