r1802: start to support SASL in our ldap libraries
authorSimo Sorce <idra@samba.org>
Fri, 13 Aug 2004 05:26:38 +0000 (05:26 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:57:58 +0000 (12:57 -0500)
does not work yet but we are close currently we send the right data
on wire and fail to decode the answer
(This used to be commit 10baf585821bf1f10a3786045a0965000cdffd12)

source4/libcli/ldap/ldap.c
source4/libcli/ldap/ldap.h
source4/torture/ldap/basic.c
source4/torture/ldap/common.c

index 16f775a4511008c6193465c4a1a30926e54c861b..3048c9411479cb0560ffcaf04c44916ff46ce33b 100644 (file)
@@ -790,8 +790,8 @@ BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
                        asn1_push_tag(&data, r->mechanism | 0xa0);
                        asn1_write_OctetString(&data, r->creds.SASL.mechanism,
                                               strlen(r->creds.SASL.mechanism));
-                       asn1_write_OctetString(&data, r->creds.SASL.creds.data,
-                                              r->creds.SASL.creds.length);
+                       asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
+                                              r->creds.SASL.secblob.length);
                        asn1_pop_tag(&data);
                        break;
                default:
@@ -1537,6 +1537,7 @@ struct ldap_connection *new_ldap_connection(void)
        result->search_entries = NULL;
        result->auth_dn = NULL;
        result->simple_pw = NULL;
+       result->gensec = NULL;
 
        return result;
 }
@@ -1740,14 +1741,15 @@ struct ldap_message *ldap_transaction(struct ldap_connection *conn,
        return ldap_receive(conn, request->messageid, NULL);
 }
 
-struct ldap_message *ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
+int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
 {
        struct ldap_message *response;
        struct ldap_message *msg;
        const char *dn, *pw;
+       int result = LDAP_OTHER;
 
-       if (conn == NULL || msg == NULL)
-               return False;
+       if (conn == NULL)
+               return result;
 
        if (userdn) {
                dn = userdn;
@@ -1771,33 +1773,152 @@ struct ldap_message *ldap_bind_simple(struct ldap_connection *conn, const char *
 
        msg =  new_ldap_simple_bind_msg(dn, pw);
        if (!msg)
-               return False;
+               return result;
 
        response = ldap_transaction(conn, msg);
+       if (!response) {
+               destroy_ldap_message(msg);
+               return result;
+       }
+               
+       result = response->r.BindResponse.response.resultcode;
 
        destroy_ldap_message(msg);
-       return response;
+       destroy_ldap_message(response);
+
+       return result;
+}
+
+int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
+{
+       NTSTATUS status;
+       TALLOC_CTX *mem_ctx = NULL;
+       struct ldap_message *response;
+       struct ldap_message *msg;
+       DATA_BLOB input = data_blob(NULL, 0);
+       DATA_BLOB output = data_blob(NULL, 0);
+       int result = LDAP_OTHER;
+
+       if (conn == NULL)
+               return result;
+
+       status = gensec_client_start(&conn->gensec);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
+               return result;
+       }
+
+       status = gensec_set_domain(conn->gensec, domain);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", 
+                         domain, nt_errstr(status)));
+               goto done;
+       }
+
+       status = gensec_set_username(conn->gensec, username);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", 
+                         username, nt_errstr(status)));
+               goto done;
+       }
+
+       status = gensec_set_password(conn->gensec, password);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC client password: %s\n", 
+                         nt_errstr(status)));
+               goto done;
+       }
+
+       status = gensec_set_target_hostname(conn->gensec, conn->host);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
+                         nt_errstr(status)));
+               goto done;
+       }
+
+       status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
+                         nt_errstr(status)));
+               goto done;
+       }
+
+       mem_ctx = talloc_init("ldap_bind_sasl");
+       if (!mem_ctx)
+               goto done;
+
+       status = gensec_update(conn->gensec, mem_ctx,
+                              input,
+                              &output);
+
+       while(1) {
+               if (NT_STATUS_IS_OK(status) && output.length == 0) {
+                       break;
+               }
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
+                       break;
+               }
+
+               msg =  new_ldap_sasl_bind_msg("GSS-SPNEGO", &output);
+               if (!msg)
+                       goto done;
+
+               response = ldap_transaction(conn, msg);
+               destroy_ldap_message(msg);
+
+               result = response->r.BindResponse.response.resultcode;
+
+               if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
+                       break;
+               }
+
+               status = gensec_update(conn->gensec, mem_ctx,
+                                      response->r.BindResponse.SASL.creds,
+                                      &output);
+
+               destroy_ldap_message(response);
+       }
+
+done:
+       if (conn->gensec)
+               gensec_end(&conn->gensec);
+       if (mem_ctx)
+               talloc_destroy(mem_ctx);
+
+       return result;
 }
 
 BOOL ldap_setup_connection(struct ldap_connection *conn,
                           const char *url, const char *userdn, const char *password)
 {
-       struct ldap_message *response;
-       BOOL result;
+       int result;
 
        if (!ldap_connect(conn, url)) {
                return False;
        }
 
-       response = ldap_bind_simple(conn, userdn, password);
-       if (response == NULL) {
-               result = False;
-       } else {
-               result = (response->r.BindResponse.response.resultcode == 0);
+       result = ldap_bind_simple(conn, userdn, password);
+       if (result == LDAP_SUCCESS) {
+               return True;
        }
 
-       destroy_ldap_message(response);
-       return result;
+       return False;
+}
+
+BOOL ldap_setup_connection_with_sasl(struct ldap_connection *conn, const char *url, const char *username, const char *domain, const char *password)
+{
+       int result;
+
+       if (!ldap_connect(conn, url)) {
+               return False;
+       }
+
+       result = ldap_bind_sasl(conn, username, domain, password);
+       if (result == LDAP_SUCCESS) {
+               return True;
+       }
+
+       return False;
 }
 
 static BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
@@ -1856,6 +1977,22 @@ struct ldap_message *new_ldap_simple_bind_msg(const char *dn, const char *pw)
        return res;
 }
 
+struct ldap_message *new_ldap_sasl_bind_msg(const char *sasl_mechanism, DATA_BLOB *secblob)
+{
+       struct ldap_message *res = new_ldap_message();
+
+       if (res == NULL)
+               return NULL;
+
+       res->type = LDAP_TAG_BindRequest;
+       res->r.BindRequest.version = 3;
+       res->r.BindRequest.dn = "";
+       res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
+       res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
+       res->r.BindRequest.creds.SASL.secblob = *secblob;
+       return res;
+}
+
 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
                       const struct timeval *endtime)
 {
index 96c1b82ca3cef17333ba2b44b3409d625619361d..fcd660f84189b337a112afbb08f09ecf699ffc17 100644 (file)
@@ -50,6 +50,12 @@ enum ldap_auth_mechanism {
        LDAP_AUTH_MECH_SASL = 3
 };
 
+enum ldap_result_code {
+       LDAP_SUCCESS = 0,
+       LDAP_SASL_BIND_IN_PROGRESS = 0x0e,
+       LDAP_OTHER = 0x50
+};
+
 struct ldap_Result {
        int resultcode;
        const char *dn;
@@ -71,7 +77,7 @@ struct ldap_BindRequest {
                const char *password;
                struct {
                        const char *mechanism;
-                       DATA_BLOB creds;
+                       DATA_BLOB secblob;
                } SASL;
        } creds;
 };
@@ -79,8 +85,8 @@ struct ldap_BindRequest {
 struct ldap_BindResponse {
        struct ldap_Result response;
        union {
-               DATA_BLOB credentials;
-       } SASL_Credentials;
+               DATA_BLOB creds;
+       } SASL;
 };
 
 struct ldap_UnbindRequest {
@@ -241,6 +247,9 @@ struct ldap_connection {
 
        /* Outstanding LDAP requests that have not yet been replied to */
        struct ldap_queue_entry *outstanding;
+
+       /* Let's support SASL */
+       struct gensec_security *gensec;
 };
 
 #endif
index a9ab023d9d81a814095470b6549f2014e515fa83..ac11a3342af1913a1f019dad4a6eef8cfec28c49 100644 (file)
@@ -1,23 +1,47 @@
 
 #include "includes.h"
 
-BOOL test_multibind(struct ldap_connection *conn, TALLOC_CTX *mem_ctx, const char *userdn, const char *password)
+BOOL test_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
 {
        NTSTATUS status;
        BOOL ret = True;
 
-       printf("\nTesting multiple binds on a single connnection as anonymous and user\n");
-
        status = torture_ldap_bind(conn, userdn, password);
        if (!NT_STATUS_IS_OK(status)) {
-               printf("1st bind as user over an anonymous bind failed\n");
-               return False;
+               ret = False;
        }
 
-       status = torture_ldap_bind(conn, NULL, NULL);
+       return ret;
+}
+
+BOOL test_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
+{
+       NTSTATUS status;
+       BOOL ret = True;
+
+       status = torture_ldap_bind_sasl(conn, username, domain, password);
        if (!NT_STATUS_IS_OK(status)) {
-               printf("2nd bind as anonymous over an authenticated bind failed\n");
-               return False;
+               ret = False;
+       }
+
+       return ret;
+}
+
+BOOL test_multibind(struct ldap_connection *conn, const char *userdn, const char *password)
+{
+       BOOL ret = True;
+
+       printf("\nTesting multiple binds on a single connnection as anonymous and user\n");
+
+       ret = test_bind_simple(conn, NULL, NULL);
+       if (!ret) {
+               printf("1st bind as anonymous failed\n");
+               return ret;
+       }
+
+       ret = test_bind_simple(conn, userdn, password);
+       if (!ret) {
+               printf("2nd bind as authenticated user failed\n");
        }
 
        return ret;
@@ -30,6 +54,9 @@ BOOL torture_ldap_basic(int dummy)
        TALLOC_CTX *mem_ctx;
        BOOL ret = True;
        const char *host = lp_parm_string(-1, "torture", "host");
+       const char *username = lp_parm_string(-1, "torture", "username");
+       const char *domain = lp_workgroup();
+       const char *password = lp_parm_string(-1, "torture", "password");
        const char *userdn = lp_parm_string(-1, "torture", "ldap_userdn");
        const char *basedn = lp_parm_string(-1, "torture", "ldap_basedn");
        const char *secret = lp_parm_string(-1, "torture", "ldap_secret");
@@ -39,14 +66,18 @@ BOOL torture_ldap_basic(int dummy)
 
        url = talloc_asprintf(mem_ctx, "ldap://%s/", host);
 
-       status = torture_ldap_connection(&conn, url, NULL, NULL);
+       status = torture_ldap_connection(&conn, url, userdn, secret);
        if (!NT_STATUS_IS_OK(status)) {
                return False;
        }
 
        /* other basic tests here */
 
-       if (!test_multibind(conn, mem_ctx, userdn, secret)) {
+       if (!test_multibind(conn, userdn, secret)) {
+               ret = False;
+       }
+
+       if (!test_bind_sasl(conn, username, domain, password)) {
                ret = False;
        }
 
index 7a3d8e48bed8ddeee867791e509ef9c40d3f7623..ee3199bccd62c3db93010cda298659c1a3aa1f65 100644 (file)
@@ -3,19 +3,39 @@
 NTSTATUS torture_ldap_bind(struct ldap_connection *conn, const char *userdn, const char *password)
 {
         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       struct ldap_message *response;
+       int result;
 
        if (!conn) {
                printf("We need a valid ldap_connection structure and be connected\n");
                return status;
        }
 
-       response = ldap_bind_simple(conn, userdn, password);
-       if (!response || (response->r.BindResponse.response.resultcode != 0)) {
+       result = ldap_bind_simple(conn, userdn, password);
+       if (result != LDAP_SUCCESS) {
                printf("Failed to bind with provided credentials\n");
                /* FIXME: what abut actually implementing an ldap_connection_free() function ?
                          :-) sss */
-               destroy_ldap_message(response);
+               return status;
+       }
+       return NT_STATUS_OK;
+}
+
+NTSTATUS torture_ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
+{
+        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       int result;
+
+       if (!conn) {
+               printf("We need a valid ldap_connection structure and be connected\n");
+               return status;
+       }
+
+       result = ldap_bind_sasl(conn, username, domain, password);
+       if (result != LDAP_SUCCESS) {
+               printf("Failed to bind with provided credentialsi and SASL mechanism\n");
+               /* FIXME: what abut actually implementing an ldap_connection_free() function ?
+                         :-) sss */
                return status;
        }