diff options
-rw-r--r-- | source4/libcli/ldap/ldap.c | 169 | ||||
-rw-r--r-- | source4/libcli/ldap/ldap.h | 15 | ||||
-rw-r--r-- | source4/torture/ldap/basic.c | 51 | ||||
-rw-r--r-- | source4/torture/ldap/common.c | 28 |
4 files changed, 230 insertions, 33 deletions
diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c index 16f775a451..3048c94114 100644 --- a/source4/libcli/ldap/ldap.c +++ b/source4/libcli/ldap/ldap.c @@ -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) { diff --git a/source4/libcli/ldap/ldap.h b/source4/libcli/ldap/ldap.h index 96c1b82ca3..fcd660f841 100644 --- a/source4/libcli/ldap/ldap.h +++ b/source4/libcli/ldap/ldap.h @@ -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 diff --git a/source4/torture/ldap/basic.c b/source4/torture/ldap/basic.c index a9ab023d9d..ac11a3342a 100644 --- a/source4/torture/ldap/basic.c +++ b/source4/torture/ldap/basic.c @@ -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; } diff --git a/source4/torture/ldap/common.c b/source4/torture/ldap/common.c index 7a3d8e48be..ee3199bccd 100644 --- a/source4/torture/ldap/common.c +++ b/source4/torture/ldap/common.c @@ -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; } |