diff options
-rw-r--r-- | source4/auth/gensec/gensec.c | 77 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_gssapi.c | 1 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 1 | ||||
-rw-r--r-- | source4/libcli/ldap/ldap_bind.c | 57 |
4 files changed, 129 insertions, 7 deletions
diff --git a/source4/auth/gensec/gensec.c b/source4/auth/gensec/gensec.c index 375c55e3ba..3818965a6f 100644 --- a/source4/auth/gensec/gensec.c +++ b/source4/auth/gensec/gensec.c @@ -98,6 +98,71 @@ const struct gensec_security_ops **gensec_security_all(int *num_backends_out) * The list is in the exact order of the OIDs asked for, where available. */ +const struct gensec_security_ops **gensec_security_by_sasl(TALLOC_CTX *mem_ctx, + const char **sasl_names) +{ + const struct gensec_security_ops **backends_out; + const struct gensec_security_ops **backends; + int i, k, sasl_idx; + int num_backends_out = 0; + int num_backends; + + if (!sasl_names) { + return NULL; + } + + backends = gensec_security_all(&num_backends); + + backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1); + if (!backends_out) { + return NULL; + } + backends_out[0] = NULL; + + /* Find backends in our preferred order, by walking our list, + * then looking in the supplied list */ + for (i=0; i < num_backends; i++) { + for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) { + if (!backends[i]->sasl_name || + !(strcmp(backends[i]->sasl_name, + sasl_names[sasl_idx]) == 0)) { + continue; + } + + for (k=0; backends_out[k]; k++) { + if (backends_out[k] == backends[i]) { + break; + } + } + + if (k < num_backends_out) { + /* already in there */ + continue; + } + + backends_out = talloc_realloc(mem_ctx, backends_out, + const struct gensec_security_ops *, + num_backends_out + 2); + if (!backends_out) { + return NULL; + } + + backends_out[num_backends_out] = backends[i]; + num_backends_out++; + backends_out[num_backends_out] = NULL; + } + } + return backends_out; +} + +/** + * Return a unique list of security subsystems from those specified in + * the OID list. That is, where two OIDs refer to the same module, + * return that module only once + * + * The list is in the exact order of the OIDs asked for, where available. + */ + const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(TALLOC_CTX *mem_ctx, const char **oid_strings, const char *skip) @@ -121,15 +186,17 @@ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(TALLOC_CTX backends_out[0].op = NULL; backends_out[0].oid = NULL; - for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) { - if (strcmp(oid_strings[oid_idx], skip) == 0) { + /* Find backends in our preferred order, by walking our list, + * then looking in the supplied list */ + for (i=0; i < num_backends; i++) { + if (!backends[i]->oid) { continue; } - - for (i=0; i < num_backends; i++) { - if (!backends[i]->oid) { + for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) { + if (strcmp(oid_strings[oid_idx], skip) == 0) { continue; } + for (j=0; backends[i]->oid[j]; j++) { if (!backends[i]->oid[j] || !(strcmp(backends[i]->oid[j], diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 745191e693..08e2298c1a 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -965,6 +965,7 @@ static const char *gensec_gssapi_krb5_oids[] = { /* As a server, this could in theory accept any GSSAPI mech */ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = { .name = "gssapi_krb5", + .sasl_name = "GSSAPI", .auth_type = DCERPC_AUTH_TYPE_KRB5, .oid = gensec_gssapi_krb5_oids, .client_start = gensec_gssapi_client_start, diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index 43187939bb..d5a2fd9a8f 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -667,6 +667,7 @@ static const char *gensec_krb5_oids[] = { static const struct gensec_security_ops gensec_fake_gssapi_krb5_security_ops = { .name = "fake_gssapi_krb5", + .sasl_name = "GSSAPI", .auth_type = DCERPC_AUTH_TYPE_KRB5, .oid = gensec_krb5_oids, .client_start = gensec_fake_gssapi_krb5_client_start, diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c index c08ffabc22..81e0c8b4e6 100644 --- a/source4/libcli/ldap/ldap_bind.c +++ b/source4/libcli/ldap/ldap_bind.c @@ -145,6 +145,18 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr DATA_BLOB input = data_blob(NULL, 0); DATA_BLOB output = data_blob(NULL, 0); + struct ldap_message **sasl_mechs_msgs; + struct ldap_SearchResEntry *search; + int count, i; + + const char **sasl_names; + const struct gensec_security_ops **mechs; + + static const char *supported_sasl_mech_attrs[] = { + "supportedSASLMechanisms", + NULL + }; + status = gensec_client_start(conn, &conn->gensec, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status))); @@ -174,16 +186,57 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr goto failed; } - status = gensec_start_mech_by_sasl_name(conn->gensec, "NTLM"); + status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs, + False, &sasl_mechs_msgs); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to set GENSEC client SPNEGO mechanism: %s\n", + DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n", nt_errstr(status))); goto failed; } + + count = ildap_count_entries(conn, sasl_mechs_msgs); + if (count != 1) { + DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n", + count)); + goto failed; + } tmp_ctx = talloc_new(conn); if (tmp_ctx == NULL) goto failed; + search = &sasl_mechs_msgs[0]->r.SearchResultEntry; + if (search->num_attributes != 1) { + DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d\n", + search->num_attributes)); + goto failed; + } + + sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1); + if (!sasl_names) { + DEBUG(1, ("talloc_arry(char *, %d) failed\n", + count)); + goto failed; + } + + for (i=0; i<search->attributes[0].num_values; i++) { + sasl_names[i] = (const char *)search->attributes[0].values[i].data; + } + sasl_names[i] = NULL; + + mechs = gensec_security_by_sasl(tmp_ctx, sasl_names); + if (!mechs || !mechs[0]) { + DEBUG(1, ("None of the %d proposed SASL mechs were acceptable\n", + count)); + goto failed; + } + + status = gensec_start_mech_by_ops(conn->gensec, mechs[0]); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to set GENSEC client mechanism: %s/%s %s\n", + mechs[0]->name, mechs[0]->sasl_name, nt_errstr(status))); + goto failed; + } + while (1) { NTSTATUS gensec_status; struct ldap_message *response; |