summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/ldap/ldap.c169
-rw-r--r--source4/libcli/ldap/ldap.h15
-rw-r--r--source4/torture/ldap/basic.c51
-rw-r--r--source4/torture/ldap/common.c28
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;
}