summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-09-02 03:19:27 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:36:24 -0500
commitb3c0dacd20c1d8002b02eceb21036dc74a684d36 (patch)
tree2a411b4dda6df02281c554bee27dc22b8778e45c
parent9319cace3bb5320e943ec75348efefe199323499 (diff)
downloadsamba-b3c0dacd20c1d8002b02eceb21036dc74a684d36.tar.gz
samba-b3c0dacd20c1d8002b02eceb21036dc74a684d36.tar.bz2
samba-b3c0dacd20c1d8002b02eceb21036dc74a684d36.zip
r9941: Update the CrackNames test, and provide a much improved server-side
DRSUAPI CrackNames. We can't pass the full cracknames test until the initial provision is updated, the seperate DomainControllerInfo and canonical names support is added. Andrew Bartlett (This used to be commit ed24d88f0e8c6371acf6638a1c5f2112bc0bf285)
-rw-r--r--source4/rpc_server/drsuapi/drsuapi_cracknames.c634
-rw-r--r--source4/torture/rpc/drsuapi.c139
2 files changed, 613 insertions, 160 deletions
diff --git a/source4/rpc_server/drsuapi/drsuapi_cracknames.c b/source4/rpc_server/drsuapi/drsuapi_cracknames.c
index b6a9105be5..35955a71b2 100644
--- a/source4/rpc_server/drsuapi/drsuapi_cracknames.c
+++ b/source4/rpc_server/drsuapi/drsuapi_cracknames.c
@@ -5,6 +5,7 @@
DsCrackNames()
Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,19 +28,232 @@
#include "rpc_server/common/common.h"
#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
#include "lib/ldb/include/ldb.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+
+static WERROR DsCrackNameOneFilter(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
+ const struct ldb_dn *name_dn, const char *name,
+ const char *domain_filter, const char *result_filter,
+ struct drsuapi_DsNameInfo1 *info1);
+static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
+ uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
+ const char *name, struct drsuapi_DsNameInfo1 *info1);
+
+static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_dn *base_dn,
+ const char *alias_from,
+ char **alias_to)
+{
+ int i;
+ int count;
+ struct ldb_message **msg;
+ struct ldb_message_element *spnmappings;
+ struct ldb_dn *service_dn = ldb_dn_string_compose(mem_ctx, base_dn,
+ "CN=Directory Service,CN=Windows NT"
+ ",CN=Services,CN=Configuration");
+ char *service_dn_str = ldb_dn_linearize(mem_ctx, service_dn);
+ const char *directory_attrs[] = {
+ "sPNMappings",
+ NULL
+ };
+
+ count = ldb_search(ldb_ctx, service_dn, LDB_SCOPE_BASE, "(objectClass=nTDSService)",
+ directory_attrs, &msg);
+ talloc_steal(mem_ctx, msg);
+
+ if (count < 1) {
+ DEBUG(1, ("ldb_search: dn: %s not found: %d", service_dn_str, count));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ } else if (count > 1) {
+ DEBUG(1, ("ldb_search: dn: %s found %d times!", service_dn_str, count));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+
+ spnmappings = ldb_msg_find_element(msg[0], "sPNMappings");
+ if (!spnmappings || spnmappings->num_values == 0) {
+ DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute", service_dn_str));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+
+ for (i = 0; i < spnmappings->num_values; i++) {
+ char *mapping, *p, *str;
+ mapping = talloc_strdup(mem_ctx,
+ (const char *)spnmappings->values[i].data);
+ if (!mapping) {
+ DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping", service_dn_str));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+
+ /* C string manipulation sucks */
+
+ p = strchr(mapping, '=');
+ if (!p) {
+ DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s",
+ service_dn_str, mapping));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+ p[0] = '\0';
+ p++;
+ do {
+ str = p;
+ p = strchr(p, ',');
+ if (p) {
+ p[0] = '\0';
+ p++;
+ }
+ if (strcasecmp(str, alias_from) == 0) {
+ *alias_to = mapping;
+ return 0;
+ }
+ } while (p);
+ }
+ DEBUG(1, ("LDB_lookup_spn_alias: no alias for service %s applicable", alias_from));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+}
+
+static WERROR DsCrackNameSPNAlias(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
+ const struct ldb_dn *result_basedn,
+ const char *name, struct drsuapi_DsNameInfo1 *info1)
+{
+ WERROR wret;
+ krb5_error_code ret;
+ krb5_principal principal;
+ const char *service;
+ char *new_service;
+ char *new_princ;
+ enum drsuapi_DsNameStatus namestatus;
+
+ /* parse principal */
+ ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context,
+ name, &principal);
+ if (ret) {
+ DEBUG(2, ("Could not parse principal: %s: %s",
+ name, smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+ return WERR_NOMEM;
+ }
+
+ /* grab cifs/, http/ etc */
+ if (principal->name.name_string.len < 2) {
+ DEBUG(5, ("could not find principal in DB, alias not applicable"));
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ service = principal->name.name_string.val[0];
+
+ /* MAP it */
+ namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context,
+ b_state->sam_ctx, mem_ctx,
+ result_basedn,
+ service, &new_service);
+
+ if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
+ info1->status = namestatus;
+ return WERR_OK;
+ }
+
+ if (ret != 0) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ }
+
+ /* ooh, very nasty playing around in the Principal... */
+ free(principal->name.name_string.val[0]);
+ principal->name.name_string.val[0] = strdup(new_service);
+ if (!principal->name.name_string.val[0]) {
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ return WERR_NOMEM;
+ }
+
+ ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &new_princ);
+
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+
+ if (ret) {
+ return WERR_NOMEM;
+ }
+
+ /* reform principal */
+ wret = DsCrackNameOneName(b_state, mem_ctx, format_flags, format_offered, format_desired,
+ new_princ, info1);
+ free(new_princ);
+ return wret;
+}
+
+static WERROR DsCrackNameUPN(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
+ const char *name, struct drsuapi_DsNameInfo1 *info1)
+{
+ WERROR status;
+ const char *domain_filter = NULL;
+ const char *result_filter = NULL;
+ krb5_error_code ret;
+ krb5_principal principal;
+ char **realm;
+ char *unparsed_name_short;
+
+ /* Prevent recursion */
+ if (!name) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
+ if (ret) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ domain_filter = NULL;
+ realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
+ domain_filter = talloc_asprintf(mem_ctx,
+ "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
+ *realm, *realm);
+ ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+
+ if (ret) {
+ free(unparsed_name_short);
+ return WERR_NOMEM;
+ }
+
+ /* This may need to be extended for more userPrincipalName variations */
+ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))",
+ unparsed_name_short);
+ if (!result_filter || !domain_filter) {
+ free(unparsed_name_short);
+ return WERR_NOMEM;
+ }
+ status = DsCrackNameOneFilter(b_state, mem_ctx,
+ smb_krb5_context,
+ format_flags, format_offered, format_desired,
+ NULL, unparsed_name_short, domain_filter, result_filter,
+ info1);
+ free(unparsed_name_short);
+ return status;
+}
static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
- uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
- const char *name, struct drsuapi_DsNameInfo1 *info1)
+ uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
+ const char *name, struct drsuapi_DsNameInfo1 *info1)
{
- int ret;
+ krb5_error_code ret;
const char *domain_filter = NULL;
- const char * const *domain_attrs;
- struct ldb_message **domain_res = NULL;
- const struct ldb_dn *result_basedn = NULL;
const char *result_filter = NULL;
- const char * const *result_attrs;
- struct ldb_message **result_res = NULL;
+ struct ldb_dn *name_dn;
+
+ struct smb_krb5_context *smb_krb5_context;
+ ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
+
+ if (ret) {
+ return WERR_NOMEM;
+ }
info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
info1->dns_domain_name = NULL;
@@ -55,64 +269,186 @@ static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX
/* here we need to set the domain_filter and/or the result_filter */
switch (format_offered) {
- case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
- char *str;
-
- str = talloc_strdup(mem_ctx, name);
- WERR_TALLOC_CHECK(str);
-
- if (strlen(str) == 0 || str[strlen(str)-1] != '/') {
- info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
- return WERR_OK;
- }
+ case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
+ char *str;
+
+ str = talloc_strdup(mem_ctx, name);
+ WERR_TALLOC_CHECK(str);
+
+ if (strlen(str) == 0 || str[strlen(str)-1] != '/') {
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ }
+
+ str[strlen(str)-1] = '\0';
+
+ domain_filter = talloc_asprintf(mem_ctx,
+ "(&(&(&(dnsRoot=%s)(objectclass=crossRef)))(nETBIOSName=*)(ncName=*))",
+ str);
+ WERR_TALLOC_CHECK(domain_filter);
+
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
+ char *p;
+ char *domain;
+ const char *account = NULL;
+
+ domain = talloc_strdup(mem_ctx, name);
+ WERR_TALLOC_CHECK(domain);
+
+ p = strchr(domain, '\\');
+ if (!p) {
+ /* invalid input format */
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ p[0] = '\0';
+
+ if (p[1]) {
+ account = &p[1];
+ }
+
+ domain_filter = talloc_asprintf(mem_ctx,
+ "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
+ domain);
+ WERR_TALLOC_CHECK(domain_filter);
+ if (account) {
+ result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
+ account);
+ WERR_TALLOC_CHECK(result_filter);
+ }
+
+ talloc_free(domain);
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
+ name_dn = ldb_dn_explode(mem_ctx, name);
+ domain_filter = NULL;
+ if (!name_dn) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_GUID: {
+ struct GUID guid;
+ char *ldap_guid;
+ NTSTATUS nt_status;
+ domain_filter = NULL;
+
+ nt_status = GUID_from_string(name, &guid);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
- str[strlen(str)-1] = '\0';
-
- domain_filter = talloc_asprintf(mem_ctx,
- "(&(&(&(dnsRoot=%s)(objectclass=crossRef)))(nETBIOSName=*)(ncName=*))",
- str);
- WERR_TALLOC_CHECK(domain_filter);
-
- break;
+ ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
+ if (!ldap_guid) {
+ return WERR_NOMEM;
}
- case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
- char *p;
- char *domain;
- const char *account = NULL;
-
- domain = talloc_strdup(mem_ctx, name);
- WERR_TALLOC_CHECK(domain);
-
- p = strchr(domain, '\\');
- if (!p) {
- /* invalid input format */
- info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
- return WERR_OK;
- }
- p[0] = '\0';
-
- if (p[1]) {
- account = &p[1];
- }
-
- domain_filter = talloc_asprintf(mem_ctx,
- "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
- domain);
- WERR_TALLOC_CHECK(domain_filter);
- if (account) {
- result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
- account);
- WERR_TALLOC_CHECK(result_filter);
- }
-
- talloc_free(domain);
- break;
+ result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
+ ldap_guid);
+ WERR_TALLOC_CHECK(result_filter);
+ break;
+ }
+
+ case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
+ struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
+ char *ldap_sid;
+
+ domain_filter = NULL;
+ if (!sid) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx,
+ sid);
+ if (!ldap_sid) {
+ return WERR_NOMEM;
+ }
+ result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
+ ldap_sid);
+ WERR_TALLOC_CHECK(result_filter);
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
+ krb5_principal principal;
+ char *unparsed_name;
+ ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
+ if (ret) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
}
- default: {
+
+ domain_filter = NULL;
+
+ ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
+ if (ret) {
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ return WERR_NOMEM;
+ }
+
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))",
+ unparsed_name);
+
+ free(unparsed_name);
+ WERR_TALLOC_CHECK(result_filter);
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
+ krb5_principal principal;
+ char *unparsed_name_short;
+ ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, name, &principal);
+ if (ret) {
info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
return WERR_OK;
}
+
+ domain_filter = NULL;
+
+ ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ if (ret) {
+ return WERR_NOMEM;
+ }
+
+ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(servicePrincipalName=%s))",
+ unparsed_name_short);
+ free(unparsed_name_short);
+ WERR_TALLOC_CHECK(result_filter);
+
+ break;
}
+ default: {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ }
+
+ return DsCrackNameOneFilter(b_state, mem_ctx,
+ smb_krb5_context,
+ format_flags, format_offered, format_desired,
+ name_dn, name,
+ domain_filter, result_filter,
+ info1);
+}
+
+static WERROR DsCrackNameOneFilter(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
+ const struct ldb_dn *name_dn, const char *name,
+ const char *domain_filter, const char *result_filter,
+ struct drsuapi_DsNameInfo1 *info1)
+{
+ int ldb_ret;
+ struct ldb_message **domain_res = NULL;
+ const char * const *domain_attrs;
+ const char * const *result_attrs;
+ struct ldb_message **result_res = NULL;
+ const struct ldb_dn *result_basedn;
/* here we need to set the attrs lists for domain and result lookups */
switch (format_desired) {
@@ -126,7 +462,7 @@ static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX
}
case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
const char * const _domain_attrs[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
- const char * const _result_attrs[] = { "sAMAccountName", NULL};
+ const char * const _result_attrs[] = { "sAMAccountName", "objectSid", NULL};
domain_attrs = _domain_attrs;
result_attrs = _result_attrs;
@@ -144,21 +480,27 @@ static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX
return WERR_OK;
}
- /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
- ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
- "%s", domain_filter);
- switch (ret) {
- case 1:
- break;
- case 0:
- info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
- return WERR_OK;
- case -1:
- info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
- return WERR_OK;
- default:
- info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
- return WERR_OK;
+ if (domain_filter) {
+ /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
+ ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
+ "%s", domain_filter);
+ } else {
+ ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
+ "(ncName=%s)", ldb_dn_linearize(mem_ctx, samdb_base_dn(mem_ctx)));
+ }
+
+ switch (ldb_ret) {
+ case 1:
+ break;
+ case 0:
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ case -1:
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ default:
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+ return WERR_OK;
}
info1->dns_domain_name = samdb_result_string(domain_res[0], "dnsRoot", NULL);
@@ -167,67 +509,121 @@ static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX
if (result_filter) {
result_basedn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
+
+ ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, result_basedn, &result_res,
+ result_attrs, "%s", result_filter);
+ } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
+ ldb_ret = gendb_search_dn(b_state->sam_ctx, mem_ctx, name_dn, &result_res,
+ result_attrs);
+ } else {
+ name_dn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
+ ldb_ret = gendb_search_dn(b_state->sam_ctx, mem_ctx, name_dn, &result_res,
+ result_attrs);
+ }
- ret = gendb_search(b_state->sam_ctx, mem_ctx, result_basedn, &result_res,
- result_attrs, "%s", result_filter);
- switch (ret) {
- case 1:
- break;
- case 0:
- return WERR_OK;
- case -1:
- info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
- return WERR_OK;
- default:
- info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
- return WERR_OK;
+ switch (ldb_ret) {
+ case 1:
+ break;
+ case 0:
+ switch (format_offered) {
+ case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
+ return DsCrackNameSPNAlias(b_state, mem_ctx,
+ smb_krb5_context,
+ format_flags, format_offered, format_desired,
+ result_basedn, name, info1);
+
+ case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
+ return DsCrackNameUPN(b_state, mem_ctx, smb_krb5_context,
+ format_flags, format_offered, format_desired,
+ name, info1);
}
- } else {
- result_res = domain_res;
+ break;
+ case -1:
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ default:
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+ return WERR_OK;
}
/* here we can use result_res[0] and domain_res[0] */
switch (format_desired) {
- case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
- info1->result_name = ldb_dn_linearize(mem_ctx, result_res[0]->dn);
- WERR_TALLOC_CHECK(info1->result_name);
+ case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
+ info1->result_name = ldb_dn_linearize(mem_ctx, result_res[0]->dn);
+ WERR_TALLOC_CHECK(info1->result_name);
- info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ return WERR_OK;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
+ const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result_res[0], "objectSid");
+ const char *_dom;
+ const char *_acc = "";
+
+ if ((sid->num_auths < 4) || (sid->num_auths > 5)) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
return WERR_OK;
}
- case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
- const char *_dom;
- const char *_acc = "";
+ if (sid->num_auths == 4) {
+ ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
+ "(ncName=%s)", ldb_dn_linearize(mem_ctx, result_res[0]->dn));
+ if (ldb_ret != 1) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
_dom = samdb_result_string(domain_res[0], "nETBIOSName", NULL);
WERR_TALLOC_CHECK(_dom);
-
- if (result_filter) {
- _acc = samdb_result_string(result_res[0], "sAMAccountName", NULL);
- WERR_TALLOC_CHECK(_acc);
+
+ } else if (sid->num_auths == 5) {
+ const char *attrs[] = { NULL };
+ struct ldb_message **domain_res2;
+ struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
+ if (!dom_sid) {
+ return WERR_OK;
}
+ dom_sid->num_auths--;
+ ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res2, attrs,
+ "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
+ if (ldb_ret != 1) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
+ "(ncName=%s)", ldb_dn_linearize(mem_ctx, domain_res2[0]->dn));
+ if (ldb_ret != 1) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ _dom = samdb_result_string(domain_res2[0], "nETBIOSName", NULL);
+ WERR_TALLOC_CHECK(_dom);
- info1->result_name = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
- WERR_TALLOC_CHECK(info1->result_name);
-
- info1->status = DRSUAPI_DS_NAME_STATUS_OK;
- return WERR_OK;
+ _acc = samdb_result_string(result_res[0], "sAMAccountName", NULL);
+ WERR_TALLOC_CHECK(_acc);
}
- case DRSUAPI_DS_NAME_FORMAT_GUID: {
- struct GUID guid;
-
- guid = samdb_result_guid(result_res[0], "objectGUID");
- info1->result_name = GUID_string2(mem_ctx, &guid);
- WERR_TALLOC_CHECK(info1->result_name);
-
- info1->status = DRSUAPI_DS_NAME_STATUS_OK;
- return WERR_OK;
- }
- default:
- return WERR_OK;
+ info1->result_name = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
+ WERR_TALLOC_CHECK(info1->result_name);
+
+ info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ return WERR_OK;
}
-
+ case DRSUAPI_DS_NAME_FORMAT_GUID: {
+ struct GUID guid;
+
+ guid = samdb_result_guid(result_res[0], "objectGUID");
+
+ info1->result_name = GUID_string2(mem_ctx, &guid);
+ WERR_TALLOC_CHECK(info1->result_name);
+
+ info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ return WERR_OK;
+ }
+ default:
+ return WERR_OK;
+ }
+
return WERR_INVALID_PARAM;
}
diff --git a/source4/torture/rpc/drsuapi.c b/source4/torture/rpc/drsuapi.c
index 197157b2b2..078b03710a 100644
--- a/source4/torture/rpc/drsuapi.c
+++ b/source4/torture/rpc/drsuapi.c
@@ -238,7 +238,7 @@ static BOOL test_DsCrackNamesMatrix(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
}
static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct DsPrivate *priv)
+ struct DsPrivate *priv, const char *test_dc)
{
NTSTATUS status;
struct drsuapi_DsCrackNames r;
@@ -323,7 +323,7 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
names[0].str = priv->domain_guid_str;
- printf("testing DsCrackNames with name '%s' desired format:%d\n",
+ printf("testing DsCrackNames with GUID '%s' desired format:%d\n",
names[0].str, r.in.req.req1.format_desired);
status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r);
@@ -377,7 +377,7 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = talloc_asprintf(mem_ctx, "%s%s$", nt4_domain, priv->dcinfo.netbios_name);
+ names[0].str = talloc_asprintf(mem_ctx, "%s%s$", nt4_domain, test_dc);
printf("testing DsCrackNames with name '%s' desired format:%d\n",
names[0].str, r.in.req.req1.format_desired);
@@ -406,7 +406,7 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = talloc_asprintf(mem_ctx, "%s$@%s", priv->dcinfo.netbios_name, dns_domain);
+ names[0].str = talloc_asprintf(mem_ctx, "%s$@%s", test_dc, dns_domain);
user_principal_name = names[0].str;
printf("testing DsCrackNames with name '%s' desired format:%d\n",
@@ -439,7 +439,7 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = talloc_asprintf(mem_ctx, "HOST/%s", priv->dcinfo.netbios_name);
+ names[0].str = talloc_asprintf(mem_ctx, "HOST/%s", test_dc);
service_principal_name = names[0].str;
printf("testing DsCrackNames with name '%s' desired format:%d\n",
@@ -472,7 +472,7 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = talloc_asprintf(mem_ctx, "cifs/%s.%s", priv->dcinfo.netbios_name, dns_domain);
+ names[0].str = talloc_asprintf(mem_ctx, "cifs/%s.%s", test_dc, dns_domain);
printf("testing DsCrackNames with name '%s' desired format:%d\n",
names[0].str, r.in.req.req1.format_desired);
@@ -520,6 +520,9 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
} else if (!W_ERROR_IS_OK(r.out.result)) {
printf("DsCrackNames failed - %s\n", win_errstr(r.out.result));
ret = False;
+ } else if (r.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ printf("DsCrackNames failed on name - %d\n", r.out.ctr.ctr1->array[0].status);
+ ret = False;
}
if (!ret) {
@@ -711,39 +714,11 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
}
- r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
- r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = SID_BUILTIN_ADMINISTRATORS;
-
- printf("testing DsCrackNames with SID '%s' desired format:%d\n",
- names[0].str, r.in.req.req1.format_desired);
-
- status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r);
- if (!NT_STATUS_IS_OK(status)) {
- const char *errstr = nt_errstr(status);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
- errstr = dcerpc_errstr(mem_ctx, p->last_fault_code);
- }
- printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr);
- ret = False;
- } else if (!W_ERROR_IS_OK(r.out.result)) {
- printf("DsCrackNames failed - %s\n", win_errstr(r.out.result));
- ret = False;
- } else if (r.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
- printf("DsCrackNames failed on name - %d\n", r.out.ctr.ctr1->array[0].status);
- ret = False;
- }
-
- if (!ret) {
- return ret;
- }
-
-
/* NEGATIVE tests. This should parse, but not succeed */
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
names[0].str = talloc_asprintf(mem_ctx, "cifs/%s.%s@%s",
- priv->dcinfo.netbios_name, dns_domain,
+ test_dc, dns_domain,
dns_domain);
printf("testing DsCrackNames with Service Principal '%s' desired format:%d\n",
@@ -964,7 +939,7 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
/* NEGATIVE tests. This should parse, but not succeed */
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = talloc_asprintf(mem_ctx, "%s$", priv->dcinfo.netbios_name);
+ names[0].str = talloc_asprintf(mem_ctx, "%s$", test_dc);
printf("testing DsCrackNames with user principal name '%s' desired format:%d\n",
names[0].str, r.in.req.req1.format_desired);
@@ -988,7 +963,7 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
/* NEGATIVE tests. This should parse, but not succeed */
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
- names[0].str = talloc_asprintf(mem_ctx, "%s$", priv->dcinfo.netbios_name);
+ names[0].str = talloc_asprintf(mem_ctx, "%s$", test_dc);
printf("testing DsCrackNames with service principal name '%s' desired format:%d\n",
names[0].str, r.in.req.req1.format_desired);
@@ -1042,6 +1017,90 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
return ret;
}
+ r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
+ r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+ names[0].str = SID_BUILTIN;
+
+ printf("testing DsCrackNames with SID '%s' desired format:%d\n",
+ names[0].str, r.in.req.req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+ errstr = dcerpc_errstr(mem_ctx, p->last_fault_code);
+ }
+ printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr);
+ ret = False;
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ printf("DsCrackNames failed - %s\n", win_errstr(r.out.result));
+ ret = False;
+ } else if (r.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ printf("DsCrackNames failed on name - %d\n", r.out.ctr.ctr1->array[0].status);
+ ret = False;
+ }
+
+ if (!ret) {
+ return ret;
+ }
+
+
+ r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
+ r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+ names[0].str = SID_BUILTIN_ADMINISTRATORS;
+
+ printf("testing DsCrackNames with SID '%s' desired format:%d\n",
+ names[0].str, r.in.req.req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+ errstr = dcerpc_errstr(mem_ctx, p->last_fault_code);
+ }
+ printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr);
+ ret = False;
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ printf("DsCrackNames failed - %s\n", win_errstr(r.out.result));
+ ret = False;
+ } else if (r.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_NO_MAPPING) {
+ printf("DsCrackNames incorrect error on name - %d\n", r.out.ctr.ctr1->array[0].status);
+ ret = False;
+ }
+
+ if (!ret) {
+ return ret;
+ }
+
+
+ r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
+ r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+ names[0].str = SID_BUILTIN_ADMINISTRATORS;
+
+ printf("testing DsCrackNames with SID '%s' desired format:%d\n",
+ names[0].str, r.in.req.req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+ errstr = dcerpc_errstr(mem_ctx, p->last_fault_code);
+ }
+ printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr);
+ ret = False;
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ printf("DsCrackNames failed - %s\n", win_errstr(r.out.result));
+ ret = False;
+ } else if (r.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_NO_MAPPING) {
+ printf("DsCrackNames incorrect error on name - %d\n", r.out.ctr.ctr1->array[0].status);
+ ret = False;
+ }
+
+ if (!ret) {
+ return ret;
+ }
+
+
/* NEGATIVE tests. This should parse, but not succeed */
r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL;
r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
@@ -1662,7 +1721,7 @@ BOOL torture_rpc_drsuapi(void)
ret &= test_DsGetDCInfo(p, mem_ctx, &priv);
- ret &= test_DsCrackNames(p, mem_ctx, &priv);
+ ret &= test_DsCrackNames(p, mem_ctx, &priv, priv.dcinfo.netbios_name);
ret &= test_DsWriteAccountSpn(p, mem_ctx, &priv);
@@ -1707,9 +1766,7 @@ BOOL torture_rpc_drsuapi_cracknames(void)
ret &= test_DsBind(p, mem_ctx, &priv);
- ret &= test_DsGetDCInfo(p, mem_ctx, &priv);
-
- ret &= test_DsCrackNames(p, mem_ctx, &priv);
+ ret &= test_DsCrackNames(p, mem_ctx, &priv, lp_parm_string(-1, "torture", "host"));
ret &= test_DsUnbind(p, mem_ctx, &priv);