diff options
-rw-r--r-- | source4/rpc_server/drsuapi/drsuapi_cracknames.c | 634 | ||||
-rw-r--r-- | source4/torture/rpc/drsuapi.c | 139 |
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); |