r9941: Update the CrackNames test, and provide a much improved server-side
authorAndrew Bartlett <abartlet@samba.org>
Fri, 2 Sep 2005 03:19:27 +0000 (03:19 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:36:24 +0000 (13:36 -0500)
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)

source4/rpc_server/drsuapi/drsuapi_cracknames.c
source4/torture/rpc/drsuapi.c

index b6a9105be523239bd55ae6198e92634033836f28..35955a71b243b517211ac013bb0d8847ed9a1efd 100644 (file)
@@ -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
 #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;
 }
 
index 197157b2b2ce51a34e9b78d1f87106b084aa0bb7..078b03710adb9d375bc8dce1af9bb1a5b7527963 100644 (file)
@@ -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);