s3-smbldap: Add API for external callback to perform LDAP bind in smbldap
authorAlexander Bokovoy <ab@samba.org>
Thu, 24 May 2012 12:38:41 +0000 (15:38 +0300)
committerAlexander Bokovoy <ab@samba.org>
Thu, 24 May 2012 14:21:26 +0000 (16:21 +0200)
In order to support other bind methods, introduce a generic bind callback.
When smbldap_state.bind_callback is set, it means there is an alternative
way to perform LDAP bind to ldap_simple_bind_s() so call it instead.
The call is wrapped in become_root()/unbecome_root() to allow proper permissions
in smbd to access needed resources in the callback, for example, credential caches.
When run outside smbd, become_root()/unbecome_root() are no-op.

The API expectation is similar to ldap_simple_bind_s().

A caller of smbldap API can pass additional information to the callback by setting
smbldap_state.bind_callback_data pointer.

Both callback and the data pointer elements of smbldap_state structure get
cleaned up if someone sets proper credentials on smbldap_state with
smbldap_set_creds() so if you are interested in using smbldap_state.bind_dn
with the callback, make sure to set callback after credentials are set.

source3/include/smbldap.h
source3/lib/smbldap.c

index df9df766b3aef6aab7dd8dfc6860379ea5168733..5051fcf333734aa587d474ea4aa639f43287ea4d 100644 (file)
@@ -44,6 +44,8 @@ struct smbldap_state {
        bool anonymous;
        char *bind_dn;
        char *bind_secret;
+       int (*bind_callback)(LDAP *ldap_struct, struct smbldap_state *ldap_state, void *data);
+       void *bind_callback_data;
 
        bool paged_results;
 
index c01d3fdc6921070318c7129ba06862564801f77b..43ddaff53a67c5d5fc81f2cddb5160283bd8709c 100644 (file)
@@ -976,7 +976,20 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state)
 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
 #endif
 
-       rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+       /* When there is an alternative bind callback is set,
+          attempt to use it to perform the bind */
+       if (ldap_state->bind_callback != NULL) {
+               /* We have to allow bind callback to be run under become_root/unbecome_root
+                  to make sure within smbd the callback has proper write access to its resources,
+                  like credential cache. This is similar to passdb case where this callback is supposed
+                  to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
+               */
+               become_root();
+               rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
+               unbecome_root();
+       } else {
+               rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+       }
 
        if (rc != LDAP_SUCCESS) {
                char *ld_error = NULL;
@@ -1667,6 +1680,8 @@ void smbldap_free_struct(struct smbldap_state **ldap_state)
 
        SAFE_FREE((*ldap_state)->bind_dn);
        SAFE_FREE((*ldap_state)->bind_secret);
+       (*ldap_state)->bind_callback = NULL;
+       (*ldap_state)->bind_callback_data = NULL;
 
        TALLOC_FREE(*ldap_state);
 
@@ -1846,6 +1861,9 @@ bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *
        /* free any previously set credential */
 
        SAFE_FREE(ldap_state->bind_dn);
+       ldap_state->bind_callback = NULL;
+       ldap_state->bind_callback_data = NULL;
+
        if (ldap_state->bind_secret) {
                /* make sure secrets are zeroed out of memory */
                memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));