LCOV - code coverage report
Current view: top level - source4/dsdb/samdb - cracknames.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 586 869 67.4 %
Date: 2024-06-13 04:01:37 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    crachnames implementation for the drsuapi pipe
       5             :    DsCrackNames()
       6             : 
       7             :    Copyright (C) Stefan Metzmacher 2004
       8             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
       9             :    Copyright (C) Matthieu Patou <mat@matws.net> 2012
      10             :    Copyright (C) Catalyst .Net Ltd 2017
      11             : 
      12             :    This program is free software; you can redistribute it and/or modify
      13             :    it under the terms of the GNU General Public License as published by
      14             :    the Free Software Foundation; either version 3 of the License, or
      15             :    (at your option) any later version.
      16             : 
      17             :    This program is distributed in the hope that it will be useful,
      18             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :    GNU General Public License for more details.
      21             : 
      22             :    You should have received a copy of the GNU General Public License
      23             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : 
      26             : #include "includes.h"
      27             : #include "librpc/gen_ndr/drsuapi.h"
      28             : #include "lib/events/events.h"
      29             : #include <ldb.h>
      30             : #include <ldb_errors.h>
      31             : #include "auth/kerberos/kerberos.h"
      32             : #include "libcli/ldap/ldap_ndr.h"
      33             : #include "libcli/security/security.h"
      34             : #include "auth/auth.h"
      35             : #include "../lib/util/util_ldb.h"
      36             : #include "dsdb/samdb/samdb.h"
      37             : #include "dsdb/common/util.h"
      38             : #include "param/param.h"
      39             : 
      40             : #undef strcasecmp
      41             : 
      42             : static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
      43             :                                    struct smb_krb5_context *smb_krb5_context,
      44             :                                    uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
      45             :                                    enum drsuapi_DsNameFormat format_desired,
      46             :                                    struct ldb_dn *name_dn, const char *name, 
      47             :                                    const char *domain_filter, const char *result_filter, 
      48             :                                    struct drsuapi_DsNameInfo1 *info1, int scope, struct ldb_dn *search_dn);
      49             : static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
      50             :                                         enum drsuapi_DsNameFormat format_offered,
      51             :                                         enum drsuapi_DsNameFormat format_desired,
      52             :                                         struct ldb_dn *name_dn, const char *name, 
      53             :                                         struct drsuapi_DsNameInfo1 *info1);
      54             : 
      55          99 : static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, 
      56             :                                         const char *name, 
      57             :                                         struct drsuapi_DsNameInfo1 *info1) 
      58             : {
      59             :         krb5_error_code ret;
      60             :         krb5_principal principal;
      61             :         /* perhaps it's a principal with a realm, so return the right 'domain only' response */
      62          99 :         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
      63             :                                     KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
      64          99 :         if (ret) {
      65           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
      66           0 :                 return WERR_OK;
      67             :         }
      68             : 
      69          99 :         info1->dns_domain_name = smb_krb5_principal_get_realm(
      70             :                 mem_ctx, smb_krb5_context->krb5_context, principal);
      71          99 :         krb5_free_principal(smb_krb5_context->krb5_context, principal);
      72             : 
      73          99 :         W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
      74             : 
      75          99 :         info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
      76          99 :         return WERR_OK;
      77             : }
      78             : 
      79        3158 : static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(struct ldb_context *ldb_ctx,
      80             :                                                       TALLOC_CTX *mem_ctx,
      81             :                                                       const char *alias_from,
      82             :                                                       char **alias_to)
      83             : {
      84             :         /*
      85             :          * Some of the logic of this function is mirrored in find_spn_alias()
      86             :          * in source4/dsdb.samdb/ldb_modules/samldb.c. If you change this to
      87             :          * not return the first matched alias, you will need to rethink that
      88             :          * function too.
      89             :          */
      90             :         unsigned int i;
      91             :         int ret;
      92             :         struct ldb_result *res;
      93             :         struct ldb_message_element *spnmappings;
      94             :         TALLOC_CTX *tmp_ctx;
      95             :         struct ldb_dn *service_dn;
      96             :         char *service_dn_str;
      97             : 
      98        3158 :         const char *directory_attrs[] = {
      99             :                 "sPNMappings", 
     100             :                 NULL
     101             :         };
     102             : 
     103        3158 :         tmp_ctx = talloc_new(mem_ctx);
     104        3158 :         if (!tmp_ctx) {
     105           0 :                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     106             :         }
     107             : 
     108        3158 :         service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services");
     109        3158 :         if ( ! ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb_ctx))) {
     110           0 :                 talloc_free(tmp_ctx);
     111           0 :                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     112             :         }
     113        3158 :         service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn);
     114        3158 :         if ( ! service_dn_str) {
     115           0 :                 talloc_free(tmp_ctx);
     116           0 :                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     117             :         }
     118             : 
     119        3158 :         ret = ldb_search(ldb_ctx, tmp_ctx, &res, service_dn, LDB_SCOPE_BASE,
     120             :                          directory_attrs, "(objectClass=nTDSService)");
     121             : 
     122        3158 :         if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
     123           0 :                 DEBUG(1, ("ldb_search: dn: %s not found: %s\n", service_dn_str, ldb_errstring(ldb_ctx)));
     124           0 :                 talloc_free(tmp_ctx);
     125           0 :                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     126        3158 :         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     127           0 :                 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
     128           0 :                 talloc_free(tmp_ctx);
     129           0 :                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     130        3158 :         } else if (res->count != 1) {
     131           0 :                 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
     132           0 :                 talloc_free(tmp_ctx);
     133           0 :                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     134             :         }
     135             : 
     136        3158 :         spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings");
     137        3158 :         if (!spnmappings || spnmappings->num_values == 0) {
     138           0 :                 DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute\n", service_dn_str));
     139           0 :                 talloc_free(tmp_ctx);
     140           0 :                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     141             :         }
     142             : 
     143        3394 :         for (i = 0; i < spnmappings->num_values; i++) {
     144             :                 char *mapping, *p, *str;
     145        3158 :                 mapping = talloc_strdup(tmp_ctx, 
     146        3158 :                                         (const char *)spnmappings->values[i].data);
     147        3158 :                 if (!mapping) {
     148           0 :                         DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));
     149           0 :                         talloc_free(tmp_ctx);
     150           0 :                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     151             :                 }
     152             : 
     153             :                 /* C string manipulation sucks */
     154             : 
     155        3158 :                 p = strchr(mapping, '=');
     156        3158 :                 if (!p) {
     157           0 :                         DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n", 
     158             :                                   service_dn_str, mapping));
     159           0 :                         talloc_free(tmp_ctx);
     160           0 :                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     161             :                 }
     162        3158 :                 p[0] = '\0';
     163        3158 :                 p++;
     164             :                 do {
     165      125437 :                         str = p;
     166      125437 :                         p = strchr(p, ',');
     167      125437 :                         if (p) {
     168      125201 :                                 p[0] = '\0';
     169      125201 :                                 p++;
     170             :                         }
     171      125437 :                         if (strcasecmp(str, alias_from) == 0) {
     172        2922 :                                 *alias_to = mapping;
     173        2922 :                                 talloc_steal(mem_ctx, mapping);
     174        2922 :                                 talloc_free(tmp_ctx);
     175        2922 :                                 return DRSUAPI_DS_NAME_STATUS_OK;
     176             :                         }
     177      122515 :                 } while (p);
     178             :         }
     179         236 :         DEBUG(4, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
     180         236 :         talloc_free(tmp_ctx);
     181         236 :         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     182             : }
     183             : 
     184             : /* When cracking a ServicePrincipalName, many services may be served
     185             :  * by the host/ servicePrincipalName.  The incoming query is for cifs/
     186             :  * but we translate it here, and search on host/.  This is done after
     187             :  * the cifs/ entry has been searched for, making this a fallback */
     188             : 
     189        3158 : static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
     190             :                                   struct smb_krb5_context *smb_krb5_context,
     191             :                                   uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
     192             :                                   enum drsuapi_DsNameFormat format_desired,
     193             :                                   const char *name, struct drsuapi_DsNameInfo1 *info1)
     194             : {
     195             :         WERROR wret;
     196             :         krb5_error_code ret;
     197             :         krb5_principal principal;
     198             :         const krb5_data *component;
     199             :         const char *service, *dns_name;
     200             :         char *new_service;
     201             :         char *new_princ;
     202             :         enum drsuapi_DsNameStatus namestatus;
     203             : 
     204             :         /* parse principal */
     205        3158 :         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
     206             :                                     name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
     207        3158 :         if (ret) {
     208           0 :                 DEBUG(2, ("Could not parse principal: %s: %s\n",
     209             :                           name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
     210             :                                                            ret, mem_ctx)));
     211           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     212             :         }
     213             : 
     214             :         /* grab cifs/, http/ etc */
     215             : 
     216             :         /* This is checked for in callers, but be safe */
     217        3158 :         if (krb5_princ_size(smb_krb5_context->krb5_context, principal) < 2) {
     218           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     219           0 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     220           0 :                 return WERR_OK;
     221             :         }
     222        3158 :         component = krb5_princ_component(smb_krb5_context->krb5_context,
     223             :                                          principal, 0);
     224        3158 :         service = (const char *)component->data;
     225        3158 :         component = krb5_princ_component(smb_krb5_context->krb5_context,
     226             :                                          principal, 1);
     227        3158 :         dns_name = (const char *)component->data;
     228             : 
     229             :         /* MAP it */
     230        3158 :         namestatus = LDB_lookup_spn_alias(sam_ctx, mem_ctx,
     231             :                                           service, &new_service);
     232             : 
     233        3158 :         if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
     234         236 :                 wret = WERR_OK;
     235         236 :                 info1->status                = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
     236         236 :                 info1->dns_domain_name       = talloc_strdup(mem_ctx, dns_name);
     237         236 :                 if (!info1->dns_domain_name) {
     238           0 :                         wret = WERR_NOT_ENOUGH_MEMORY;
     239             :                 }
     240         236 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     241         236 :                 return wret;
     242        2922 :         } else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
     243           0 :                 info1->status = namestatus;
     244           0 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     245           0 :                 return WERR_OK;
     246             :         }
     247             : 
     248             :         /* reform principal */
     249        2922 :         new_princ = talloc_asprintf(mem_ctx, "%s/%s", new_service, dns_name);
     250        2922 :         if (!new_princ) {
     251           0 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     252           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     253             :         }
     254             : 
     255        2922 :         wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
     256             :                                   new_princ, info1);
     257        2922 :         talloc_free(new_princ);
     258        2922 :         if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) {
     259           0 :                 info1->status                = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
     260           0 :                 info1->dns_domain_name       = talloc_strdup(mem_ctx, dns_name);
     261           0 :                 if (!info1->dns_domain_name) {
     262           0 :                         wret = WERR_NOT_ENOUGH_MEMORY;
     263             :                 }
     264             :         }
     265        2922 :         krb5_free_principal(smb_krb5_context->krb5_context, principal);
     266        2922 :         return wret;
     267             : }
     268             : 
     269             : /* Subcase of CrackNames, for the userPrincipalName */
     270             : 
     271       77473 : static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
     272             :                              struct smb_krb5_context *smb_krb5_context,
     273             :                              uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
     274             :                              enum drsuapi_DsNameFormat format_desired,
     275             :                              const char *name, struct drsuapi_DsNameInfo1 *info1)
     276             : {
     277             :         int ldb_ret;
     278             :         WERROR status;
     279       77473 :         const char *domain_filter = NULL;
     280       77473 :         const char *result_filter = NULL;
     281             :         krb5_error_code ret;
     282             :         krb5_principal principal;
     283             :         char *realm;
     284             :         char *unparsed_name_short;
     285       77473 :         const char *domain_attrs[] = { NULL };
     286       77473 :         struct ldb_result *domain_res = NULL;
     287             : 
     288             :         /* Prevent recursion */
     289       77473 :         if (!name) {
     290           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     291           0 :                 return WERR_OK;
     292             :         }
     293             : 
     294       77473 :         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
     295             :                                     KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
     296       77473 :         if (ret) {
     297        2341 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     298        2341 :                 return WERR_OK;
     299             :         }
     300             : 
     301       75132 :         realm = smb_krb5_principal_get_realm(
     302             :                 mem_ctx, smb_krb5_context->krb5_context, principal);
     303             : 
     304       75132 :         ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
     305             :                              samdb_partitions_dn(sam_ctx, mem_ctx),
     306             :                              LDB_SCOPE_ONELEVEL,
     307             :                              domain_attrs,
     308             :                              "(&(objectClass=crossRef)(|(dnsRoot=%s)(netbiosName=%s))(systemFlags:%s:=%u))",
     309             :                              ldb_binary_encode_string(mem_ctx, realm),
     310             :                              ldb_binary_encode_string(mem_ctx, realm),
     311             :                              LDB_OID_COMPARATOR_AND,
     312             :                              SYSTEM_FLAG_CR_NTDS_DOMAIN);
     313       75132 :         TALLOC_FREE(realm);
     314             : 
     315       75132 :         if (ldb_ret != LDB_SUCCESS) {
     316           0 :                 DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
     317           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     318           0 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     319           0 :                 return WERR_OK;
     320             :         }
     321             : 
     322       75132 :         switch (domain_res->count) {
     323       75039 :         case 1:
     324       75039 :                 break;
     325          93 :         case 0:
     326          93 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     327          93 :                 return dns_domain_from_principal(mem_ctx, smb_krb5_context, 
     328             :                                                  name, info1);
     329           0 :         default:
     330           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
     331           0 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     332           0 :                 return WERR_OK;
     333             :         }
     334             : 
     335             :         /*
     336             :          * The important thing here is that a samAccountName may have
     337             :          * a space in it, and this must not be kerberos escaped to
     338             :          * match this filter, so we specify
     339             :          * KRB5_PRINCIPAL_UNPARSE_DISPLAY
     340             :          */
     341       75039 :         ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
     342             :                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM |
     343             :                                       KRB5_PRINCIPAL_UNPARSE_DISPLAY,
     344             :                                       &unparsed_name_short);
     345       75039 :         krb5_free_principal(smb_krb5_context->krb5_context, principal);
     346             : 
     347       75039 :         if (ret) {
     348           0 :                 free(unparsed_name_short);
     349           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     350             :         }
     351             : 
     352             :         /* This may need to be extended for more userPrincipalName variations */
     353       75039 :         result_filter = talloc_asprintf(mem_ctx, "(&(samAccountName=%s)(objectClass=user))",
     354             :                                         ldb_binary_encode_string(mem_ctx, unparsed_name_short));
     355             : 
     356       75039 :         domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
     357             : 
     358       75039 :         if (!result_filter || !domain_filter) {
     359           0 :                 free(unparsed_name_short);
     360           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     361             :         }
     362       75039 :         status = DsCrackNameOneFilter(sam_ctx, mem_ctx, 
     363             :                                       smb_krb5_context, 
     364             :                                       format_flags, format_offered, format_desired, 
     365             :                                       NULL, unparsed_name_short, domain_filter, result_filter, 
     366             :                                       info1, LDB_SCOPE_SUBTREE, NULL);
     367       75039 :         free(unparsed_name_short);
     368             : 
     369       75039 :         return status;
     370             : }
     371             : 
     372             : /*
     373             :  * This function will workout the filtering parameter in order to be able to do
     374             :  * the adapted search when the incomming format is format_functional.
     375             :  * This boils down to defining the search_dn (passed as pointer to ldb_dn *) and the
     376             :  * ldap filter request.
     377             :  * Main input parameters are:
     378             :  * * name, which is the portion of the functional name after the
     379             :  * first '/'.
     380             :  * * domain_filter, which is a ldap search filter used to find the NC DN given the
     381             :  * function name to crack.
     382             :  */
     383          50 : static WERROR get_format_functional_filtering_param(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
     384             :                         char *name, struct drsuapi_DsNameInfo1 *info1,
     385             :                         struct ldb_dn **psearch_dn, const char *domain_filter, const char **presult_filter)
     386             : {
     387          50 :         struct ldb_result *domain_res = NULL;
     388          50 :         const char * const domain_attrs[] = {"ncName", NULL};
     389          50 :         struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
     390             :         int ldb_ret;
     391          50 :         char *account,  *s, *result_filter = NULL;
     392          50 :         struct ldb_dn *search_dn = NULL;
     393             : 
     394          50 :         *psearch_dn = NULL;
     395          50 :         *presult_filter = NULL;
     396             : 
     397          50 :         ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
     398             :                                 partitions_basedn,
     399             :                                 LDB_SCOPE_ONELEVEL,
     400             :                                 domain_attrs,
     401             :                                 "%s", domain_filter);
     402             : 
     403          50 :         if (ldb_ret != LDB_SUCCESS) {
     404           0 :                 DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
     405           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     406           0 :                 return WERR_FOOBAR;
     407             :         }
     408             : 
     409          50 :         if (domain_res->count == 1) {
     410          50 :                 struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
     411          50 :                 const char * const name_attrs[] = {"name", NULL};
     412             : 
     413          50 :                 account = name;
     414          50 :                 s = strchr(account, '/');
     415          50 :                 talloc_free(domain_res);
     416         148 :                 while(s) {
     417          50 :                         s[0] = '\0';
     418          50 :                         s++;
     419             : 
     420          50 :                         ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
     421             :                                                 tmp_dn,
     422             :                                                 LDB_SCOPE_ONELEVEL,
     423             :                                                 name_attrs,
     424             :                                                 "name=%s", account);
     425             : 
     426          50 :                         if (ldb_ret != LDB_SUCCESS) {
     427           0 :                                 DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
     428           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     429           0 :                                 return WERR_OK;
     430             :                         }
     431          50 :                         talloc_free(tmp_dn);
     432          50 :                         switch (domain_res->count) {
     433          50 :                         case 1:
     434          50 :                                 break;
     435           0 :                         case 0:
     436           0 :                                 talloc_free(domain_res);
     437           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     438           0 :                                 return WERR_OK;
     439           0 :                         default:
     440           0 :                                 talloc_free(domain_res);
     441           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
     442           0 :                                 return WERR_OK;
     443             :                         }
     444             : 
     445          50 :                         tmp_dn = talloc_steal(mem_ctx, domain_res->msgs[0]->dn);
     446          50 :                         talloc_free(domain_res);
     447          50 :                         search_dn = tmp_dn;
     448          50 :                         account = s;
     449          50 :                         s = strchr(account, '/');
     450             :                 }
     451          50 :                 account = ldb_binary_encode_string(mem_ctx, account);
     452          50 :                 W_ERROR_HAVE_NO_MEMORY(account);
     453          50 :                 result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
     454             :                                                 account);
     455          50 :                 W_ERROR_HAVE_NO_MEMORY(result_filter);
     456             :         }
     457          50 :         *psearch_dn = search_dn;
     458          50 :         *presult_filter = result_filter;
     459          50 :         return WERR_OK;
     460             : }
     461             : 
     462             : /* Crack a single 'name', from format_offered into format_desired, returning the result in info1 */
     463             : 
     464      183051 : WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
     465             :                           uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
     466             :                           enum drsuapi_DsNameFormat format_desired,
     467             :                           const char *name, struct drsuapi_DsNameInfo1 *info1)
     468             : {
     469             :         krb5_error_code ret;
     470      183051 :         const char *domain_filter = NULL;
     471      183051 :         const char *result_filter = NULL;
     472      183051 :         struct ldb_dn *name_dn = NULL;
     473      183051 :         struct ldb_dn *search_dn = NULL;
     474             : 
     475      183051 :         struct smb_krb5_context *smb_krb5_context = NULL;
     476      183051 :         int scope = LDB_SCOPE_SUBTREE;
     477             : 
     478      183051 :         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     479      183051 :         info1->dns_domain_name = NULL;
     480      183051 :         info1->result_name = NULL;
     481             : 
     482      183051 :         if (!name) {
     483           0 :                 return WERR_INVALID_PARAMETER;
     484             :         }
     485             : 
     486             :         /* TODO: - fill the correct names in all cases!
     487             :          *       - handle format_flags
     488             :          */
     489      183051 :         if (format_desired == DRSUAPI_DS_NAME_FORMAT_UNKNOWN) {
     490          20 :                 return WERR_OK;
     491             :         }
     492             :         /* here we need to set the domain_filter and/or the result_filter */
     493      183031 :         switch (format_offered) {
     494           0 :         case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
     495             :         {
     496             :                 unsigned int i;
     497           0 :                 enum drsuapi_DsNameFormat formats[] = {
     498             :                         DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
     499             :                         DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL,
     500             :                         DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY,
     501             :                         DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
     502             :                         DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
     503             :                         DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
     504             :                 };
     505             :                 WERROR werr;
     506           0 :                 for (i=0; i < ARRAY_SIZE(formats); i++) {
     507           0 :                         werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
     508           0 :                         if (!W_ERROR_IS_OK(werr)) {
     509           0 :                                 return werr;
     510             :                         }
     511           0 :                         if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND &&
     512           0 :                             (formats[i] != DRSUAPI_DS_NAME_FORMAT_CANONICAL ||
     513           0 :                              info1->status != DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR))
     514             :                         {
     515           0 :                                 return werr;
     516             :                         }
     517             :                 }
     518           0 :                 return werr;
     519             :         }
     520             : 
     521       85532 :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
     522             :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
     523             :         {
     524             :                 char *str, *s, *account;
     525       85532 :                 scope = LDB_SCOPE_ONELEVEL;
     526             : 
     527       85532 :                 if (strlen(name) == 0) {
     528           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     529           0 :                         return WERR_OK;
     530             :                 }
     531             : 
     532       85532 :                 str = talloc_strdup(mem_ctx, name);
     533       85532 :                 W_ERROR_HAVE_NO_MEMORY(str);
     534             : 
     535       85532 :                 if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
     536             :                         /* Look backwards for the \n, and replace it with / */
     537          25 :                         s = strrchr(str, '\n');
     538          25 :                         if (!s) {
     539           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     540           0 :                                 return WERR_OK;
     541             :                         }
     542          25 :                         s[0] = '/';
     543             :                 }
     544             : 
     545       85532 :                 s = strchr(str, '/');
     546       85532 :                 if (!s) {
     547             :                         /* there must be at least one / */
     548           1 :                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     549           1 :                         return WERR_OK;
     550             :                 }
     551             : 
     552       85531 :                 s[0] = '\0';
     553       85531 :                 s++;
     554             : 
     555       85531 :                 domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(dnsRoot=%s)(systemFlags:%s:=%u))",
     556             :                                                 ldb_binary_encode_string(mem_ctx, str),
     557             :                                                 LDB_OID_COMPARATOR_AND,
     558             :                                                 SYSTEM_FLAG_CR_NTDS_DOMAIN);
     559       85531 :                 W_ERROR_HAVE_NO_MEMORY(domain_filter);
     560             : 
     561             :                 /* There may not be anything after the domain component (search for the domain itself) */
     562       85531 :                 account = s;
     563       85531 :                 if (account && *account) {
     564          50 :                         WERROR werr = get_format_functional_filtering_param(sam_ctx,
     565             :                                                                                 mem_ctx,
     566             :                                                                                 account,
     567             :                                                                                 info1,
     568             :                                                                                 &search_dn,
     569             :                                                                                 domain_filter,
     570             :                                                                                 &result_filter);
     571          50 :                         if (!W_ERROR_IS_OK(werr)) {
     572           0 :                                 return werr;
     573             :                         }
     574          50 :                         if (info1->status != DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR)
     575           0 :                                 return WERR_OK;
     576             :                 }
     577       85531 :                 break;
     578             :         }
     579         332 :         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
     580             :                 char *p;
     581             :                 char *domain;
     582         332 :                 const char *account = NULL;
     583             : 
     584         332 :                 domain = talloc_strdup(mem_ctx, name);
     585         332 :                 W_ERROR_HAVE_NO_MEMORY(domain);
     586             : 
     587         332 :                 p = strchr(domain, '\\');
     588         332 :                 if (!p) {
     589             :                         /* invalid input format */
     590           2 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     591           2 :                         return WERR_OK;
     592             :                 }
     593         330 :                 p[0] = '\0';
     594             : 
     595         330 :                 if (p[1]) {
     596          59 :                         account = &p[1];
     597             :                 }
     598             : 
     599         330 :                 domain_filter = talloc_asprintf(mem_ctx, 
     600             :                                                 "(&(objectClass=crossRef)(netbiosName=%s)(systemFlags:%s:=%u))",
     601             :                                                 ldb_binary_encode_string(mem_ctx, domain),
     602             :                                                 LDB_OID_COMPARATOR_AND,
     603             :                                                 SYSTEM_FLAG_CR_NTDS_DOMAIN);
     604         330 :                 W_ERROR_HAVE_NO_MEMORY(domain_filter);
     605         330 :                 if (account) {
     606          59 :                         result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
     607             :                                                         ldb_binary_encode_string(mem_ctx, account));
     608          59 :                         W_ERROR_HAVE_NO_MEMORY(result_filter);
     609             :                 }
     610             : 
     611         330 :                 talloc_free(domain);
     612         330 :                 break;
     613             :         }
     614             : 
     615             :                 /* A LDAP DN as a string */
     616         347 :         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
     617         347 :                 domain_filter = NULL;
     618         347 :                 name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
     619         347 :                 if (! ldb_dn_validate(name_dn)) {
     620           2 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     621           2 :                         return WERR_OK;
     622             :                 }
     623         345 :                 break;
     624             :         }
     625             : 
     626             :                 /* A GUID as a string */
     627          56 :         case DRSUAPI_DS_NAME_FORMAT_GUID: {
     628             :                 struct GUID guid;
     629             :                 char *ldap_guid;
     630             :                 NTSTATUS nt_status;
     631          56 :                 domain_filter = NULL;
     632             : 
     633          56 :                 nt_status = GUID_from_string(name, &guid);
     634          56 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     635           2 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     636           4 :                         return WERR_OK;
     637             :                 }
     638             : 
     639          54 :                 ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
     640          54 :                 if (!ldap_guid) {
     641           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     642             :                 }
     643          54 :                 result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
     644             :                                                 ldap_guid);
     645          54 :                 W_ERROR_HAVE_NO_MEMORY(result_filter);
     646          54 :                 break;
     647             :         }
     648          23 :         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
     649          23 :                 domain_filter = NULL;
     650             : 
     651          23 :                 result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
     652             :                                                 ldb_binary_encode_string(mem_ctx, name), 
     653             :                                                 ldb_binary_encode_string(mem_ctx, name));
     654          23 :                 W_ERROR_HAVE_NO_MEMORY(result_filter);
     655          23 :                 break;
     656             :         }
     657             : 
     658             :                 /* A S-1234-5678 style string */
     659         319 :         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
     660         319 :                 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
     661             :                 char *ldap_sid;
     662             : 
     663         319 :                 domain_filter = NULL;
     664         319 :                 if (!sid) {
     665           2 :                         info1->dns_domain_name = NULL;
     666           2 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     667           2 :                         return WERR_OK;
     668             :                 }
     669         317 :                 ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx, 
     670             :                                                    sid);
     671         317 :                 if (!ldap_sid) {
     672           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     673             :                 }
     674         317 :                 result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
     675             :                                                 ldap_sid);
     676         317 :                 W_ERROR_HAVE_NO_MEMORY(result_filter);
     677         317 :                 break;
     678             :         }
     679       77005 :         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
     680             :                 krb5_principal principal;
     681             :                 char *unparsed_name;
     682             : 
     683       77005 :                 ret = smb_krb5_init_context(mem_ctx, 
     684       77005 :                                             (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), 
     685             :                                             &smb_krb5_context);
     686             : 
     687       77005 :                 if (ret) {
     688           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     689             :                 }
     690             : 
     691             :                 /* Ensure we reject complete junk first */
     692       77005 :                 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
     693       77005 :                 if (ret) {
     694           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     695           0 :                         return WERR_OK;
     696             :                 }
     697             : 
     698       77005 :                 domain_filter = NULL;
     699             : 
     700             :                 /*
     701             :                  * By getting the unparsed name here, we ensure the
     702             :                  * escaping is removed correctly (and trust the client
     703             :                  * less).  The important thing here is that a
     704             :                  * userPrincipalName may have a space in it, and this
     705             :                  * must not be kerberos escaped to match this filter,
     706             :                  * so we specify KRB5_PRINCIPAL_UNPARSE_DISPLAY
     707             :                  */
     708       77005 :                 ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context,
     709             :                                               principal,
     710             :                                               KRB5_PRINCIPAL_UNPARSE_DISPLAY,
     711             :                                               &unparsed_name);
     712       77005 :                 if (ret) {
     713           0 :                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
     714           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     715             :                 }
     716             : 
     717       77005 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     718             : 
     719             :                 /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
     720       77005 :                 result_filter = talloc_asprintf(mem_ctx, "(&(userPrincipalName=%s)(objectClass=user))",
     721             :                                                 ldb_binary_encode_string(mem_ctx, unparsed_name));
     722             : 
     723       77005 :                 free(unparsed_name);
     724       77005 :                 W_ERROR_HAVE_NO_MEMORY(result_filter);
     725       77005 :                 break;
     726             :         }
     727       19417 :         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
     728             :                 krb5_principal principal;
     729             :                 char *unparsed_name_short;
     730             :                 const krb5_data *component;
     731             :                 char *service;
     732             : 
     733       19417 :                 ret = smb_krb5_init_context(mem_ctx, 
     734       19417 :                                             (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), 
     735             :                                             &smb_krb5_context);
     736             : 
     737       19417 :                 if (ret) {
     738          14 :                         return WERR_NOT_ENOUGH_MEMORY;
     739             :                 }
     740             : 
     741       19417 :                 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
     742       38822 :                 if (ret == 0 &&
     743       19417 :                     krb5_princ_size(smb_krb5_context->krb5_context,
     744             :                                                         principal) < 2) {
     745           8 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     746           8 :                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
     747           8 :                         return WERR_OK;
     748       19409 :                 } else if (ret == 0) {
     749       19409 :                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
     750             :                 }
     751       19409 :                 ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
     752             :                                             KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
     753       19409 :                 if (ret) {
     754           6 :                         return dns_domain_from_principal(mem_ctx, smb_krb5_context,
     755             :                                                          name, info1);
     756             :                 }
     757             : 
     758       19403 :                 domain_filter = NULL;
     759             : 
     760       19403 :                 ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
     761             :                                               KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
     762       19403 :                 if (ret) {
     763           0 :                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
     764           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     765             :                 }
     766             : 
     767       19403 :                 component = krb5_princ_component(smb_krb5_context->krb5_context,
     768             :                                                  principal, 0);
     769       19403 :                 service = (char *)component->data;
     770       19403 :                 if ((krb5_princ_size(smb_krb5_context->krb5_context,
     771       19244 :                                                         principal) == 2) &&
     772       30389 :                         (strcasecmp(service, "host") == 0)) {
     773             :                         /* the 'cn' attribute is just the leading part of the name */
     774             :                         char *computer_name;
     775       22290 :                         component = krb5_princ_component(
     776       11145 :                                                 smb_krb5_context->krb5_context,
     777             :                                                 principal, 1);
     778       11145 :                         computer_name = talloc_strndup(mem_ctx, (char *)component->data,
     779       11145 :                                                         strcspn((char *)component->data, "."));
     780       11145 :                         if (computer_name == NULL) {
     781           0 :                                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     782           0 :                                 free(unparsed_name_short);
     783           0 :                                 return WERR_NOT_ENOUGH_MEMORY;
     784             :                         }
     785             : 
     786       11145 :                         result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))", 
     787             :                                                         ldb_binary_encode_string(mem_ctx, unparsed_name_short), 
     788             :                                                         ldb_binary_encode_string(mem_ctx, computer_name));
     789             :                 } else {
     790        8258 :                         result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))",
     791             :                                                         ldb_binary_encode_string(mem_ctx, unparsed_name_short));
     792             :                 }
     793       19403 :                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
     794       19403 :                 free(unparsed_name_short);
     795       19403 :                 W_ERROR_HAVE_NO_MEMORY(result_filter);
     796             : 
     797       19403 :                 break;
     798             :         }
     799           0 :         default: {
     800           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     801           0 :                 return WERR_OK;
     802             :         }
     803             :         }
     804             : 
     805      183008 :         if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
     806           4 :                 return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
     807             :                                                  name_dn, name, info1);
     808             :         }
     809             : 
     810      183004 :         return DsCrackNameOneFilter(sam_ctx, mem_ctx, 
     811             :                                     smb_krb5_context, 
     812             :                                     format_flags, format_offered, format_desired, 
     813             :                                     name_dn, name, 
     814             :                                     domain_filter, result_filter, 
     815             :                                     info1, scope, search_dn);
     816             : }
     817             : 
     818             : /* Subcase of CrackNames.  It is possible to translate a LDAP-style DN
     819             :  * (FQDN_1779) into a canoical name without actually searching the
     820             :  * database */
     821             : 
     822          29 : static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
     823             :                                         enum drsuapi_DsNameFormat format_offered,
     824             :                                         enum drsuapi_DsNameFormat format_desired,
     825             :                                         struct ldb_dn *name_dn, const char *name, 
     826             :                                         struct drsuapi_DsNameInfo1 *info1)
     827             : {
     828             :         char *cracked;
     829          29 :         if (format_offered != DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
     830           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
     831           0 :                 return WERR_OK;
     832             :         }
     833             : 
     834          29 :         switch (format_desired) {
     835           2 :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: 
     836           2 :                 cracked = ldb_dn_canonical_string(mem_ctx, name_dn);
     837           2 :                 break;
     838          27 :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
     839          27 :                 cracked = ldb_dn_canonical_ex_string(mem_ctx, name_dn);
     840          27 :                 break;
     841           0 :         default:
     842           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
     843           0 :                 return WERR_OK;
     844             :         }
     845          29 :         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
     846          29 :         info1->result_name   = cracked;
     847          29 :         if (!cracked) {
     848           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     849             :         }
     850             : 
     851          29 :         return WERR_OK; 
     852             : }
     853             : 
     854             : /* Given a filter for the domain, and one for the result, perform the
     855             :  * ldb search. The format offered and desired flags change the
     856             :  * behaviours, including what attributes to return.
     857             :  *
     858             :  * The smb_krb5_context is required because we use the krb5 libs for principal parsing
     859             :  */
     860             : 
     861      258043 : static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
     862             :                                    struct smb_krb5_context *smb_krb5_context,
     863             :                                    uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
     864             :                                    enum drsuapi_DsNameFormat format_desired,
     865             :                                    struct ldb_dn *name_dn, const char *name, 
     866             :                                    const char *domain_filter, const char *result_filter, 
     867             :                                    struct drsuapi_DsNameInfo1 *info1,
     868             :                                    int scope, struct ldb_dn *search_dn)
     869             : {
     870             :         int ldb_ret;
     871      258043 :         struct ldb_result *domain_res = NULL;
     872             :         const char * const *domain_attrs;
     873             :         const char * const *result_attrs;
     874      258043 :         struct ldb_message **result_res = NULL;
     875      258043 :         struct ldb_message *result = NULL;
     876             :         int i;
     877             :         char *p;
     878      258043 :         struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
     879             : 
     880      258043 :         const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
     881      258043 :         const char * const _result_attrs_null[] = { NULL };
     882             : 
     883      258043 :         const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
     884      258043 :         const char * const _result_attrs_canonical[] = { "canonicalName", NULL };
     885             : 
     886      258043 :         const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
     887      258043 :         const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};
     888             : 
     889      258043 :         const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
     890      258043 :         const char * const _result_attrs_guid[] = { "objectGUID", NULL};
     891             : 
     892      258043 :         const char * const _domain_attrs_upn[] = { "ncName", "dnsRoot", NULL};
     893      258043 :         const char * const _result_attrs_upn[] = { "userPrincipalName", NULL};
     894             : 
     895      258043 :         const char * const _domain_attrs_spn[] = { "ncName", "dnsRoot", NULL};
     896      258043 :         const char * const _result_attrs_spn[] = { "servicePrincipalName", NULL};
     897             : 
     898      258043 :         const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
     899      258043 :         const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};
     900             : 
     901      258043 :         const char * const _domain_attrs_sid[] = { "ncName", "dnsRoot", NULL};
     902      258043 :         const char * const _result_attrs_sid[] = { "objectSid", NULL};
     903             : 
     904      258043 :         const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
     905      258043 :         const char * const _result_attrs_none[] = { NULL};
     906             : 
     907             :         /* here we need to set the attrs lists for domain and result lookups */
     908      258043 :         switch (format_desired) {
     909      246981 :         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
     910             :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
     911      246981 :                 domain_attrs = _domain_attrs_1779;
     912      246981 :                 result_attrs = _result_attrs_null;
     913      246981 :                 break;
     914          27 :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
     915          27 :                 domain_attrs = _domain_attrs_canonical;
     916          27 :                 result_attrs = _result_attrs_canonical;
     917          27 :                 break;
     918       10876 :         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
     919       10876 :                 domain_attrs = _domain_attrs_nt4;
     920       10876 :                 result_attrs = _result_attrs_nt4;
     921       10876 :                 break;
     922          39 :         case DRSUAPI_DS_NAME_FORMAT_GUID:               
     923          39 :                 domain_attrs = _domain_attrs_guid;
     924          39 :                 result_attrs = _result_attrs_guid;
     925          39 :                 break;
     926          25 :         case DRSUAPI_DS_NAME_FORMAT_DISPLAY:            
     927          25 :                 domain_attrs = _domain_attrs_display;
     928          25 :                 result_attrs = _result_attrs_display;
     929          25 :                 break;
     930          25 :         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
     931          25 :                 domain_attrs = _domain_attrs_upn;
     932          25 :                 result_attrs = _result_attrs_upn;
     933          25 :                 break;
     934          25 :         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
     935          25 :                 domain_attrs = _domain_attrs_spn;
     936          25 :                 result_attrs = _result_attrs_spn;
     937          25 :                 break;
     938          23 :         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY:
     939          23 :                 domain_attrs = _domain_attrs_sid;
     940          23 :                 result_attrs = _result_attrs_sid;
     941          23 :                 break;
     942          22 :         default:
     943          22 :                 domain_attrs = _domain_attrs_none;
     944          22 :                 result_attrs = _result_attrs_none;
     945          22 :                 break;
     946             :         }
     947             : 
     948      258043 :         if (domain_filter) {
     949             :                 /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
     950      160900 :                 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
     951             :                                              partitions_basedn,
     952             :                                              LDB_SCOPE_ONELEVEL,
     953             :                                              domain_attrs,
     954             :                                              "%s", domain_filter);
     955             : 
     956      160900 :                 if (ldb_ret != LDB_SUCCESS) {
     957           0 :                         DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
     958           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     959           0 :                         return WERR_OK;
     960             :                 }
     961             : 
     962      160900 :                 switch (domain_res->count) {
     963      160890 :                 case 1:
     964      160890 :                         break;
     965          10 :                 case 0:
     966          10 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     967          10 :                         return WERR_OK;
     968           0 :                 default:
     969           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
     970           0 :                         return WERR_OK;
     971             :                 }
     972             : 
     973      160890 :                 info1->dns_domain_name       = ldb_msg_find_attr_as_string(domain_res->msgs[0], "dnsRoot", NULL);
     974      160890 :                 W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
     975      160890 :                 info1->status                = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
     976             :         } else {
     977       97143 :                 info1->dns_domain_name       = NULL;
     978       97143 :                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
     979             :         }
     980             : 
     981      258033 :         if (result_filter) {
     982             :                 int ret;
     983             :                 struct ldb_result *res;
     984      171946 :                 uint32_t dsdb_flags = 0;
     985      171946 :                 struct ldb_dn *real_search_dn = NULL;
     986      171946 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
     987             : 
     988             :                 /*
     989             :                  * From 4.1.4.2.11 of MS-DRSR
     990             :                  * if DS_NAME_FLAG_GCVERIFY in flags then
     991             :                  * rt := select all O from all
     992             :                  * where attrValue in GetAttrVals(O, att, false)
     993             :                  * else
     994             :                  * rt := select all O from subtree DefaultNC()
     995             :                  * where attrValue in GetAttrVals(O, att, false)
     996             :                  * endif
     997             :                  * return rt
     998             :                  */
     999      171946 :                 if (format_flags & DRSUAPI_DS_NAME_FLAG_GCVERIFY ||
    1000             :                     format_offered == DRSUAPI_DS_NAME_FORMAT_GUID)
    1001             :                 {
    1002          54 :                         dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
    1003      171892 :                 } else if (domain_res) {
    1004       75144 :                         if (!search_dn) {
    1005       75094 :                                 struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
    1006       75094 :                                 real_search_dn = tmp_dn;
    1007             :                         } else {
    1008          50 :                                 real_search_dn = search_dn;
    1009             :                         }
    1010             :                 } else {
    1011       96748 :                         real_search_dn = ldb_get_default_basedn(sam_ctx);
    1012             :                 }
    1013      171946 :                 if (format_offered == DRSUAPI_DS_NAME_FORMAT_GUID){
    1014          54 :                          dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
    1015             :                 }
    1016             :                 /* search with the 'phantom root' flag */
    1017      171946 :                 ret = dsdb_search(sam_ctx, mem_ctx, &res,
    1018             :                                   real_search_dn,
    1019             :                                   scope,
    1020             :                                   result_attrs,
    1021             :                                   dsdb_flags,
    1022             :                                   "%s", result_filter);
    1023      171946 :                 if (ret != LDB_SUCCESS) {
    1024           0 :                         DEBUG(2, ("DsCrackNameOneFilter search from '%s' with flags 0x%08x failed: %s\n",
    1025             :                                   ldb_dn_get_linearized(real_search_dn),
    1026             :                                   dsdb_flags,
    1027             :                                   ldb_errstring(sam_ctx)));
    1028           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    1029           0 :                         return WERR_OK;
    1030             :                 }
    1031             : 
    1032      171946 :                 ldb_ret = res->count;
    1033      171946 :                 result_res = res->msgs;
    1034       86087 :         } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
    1035         341 :                 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
    1036             :                                           result_attrs);
    1037       85746 :         } else if (domain_res) {
    1038       85746 :                 name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
    1039       85746 :                 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
    1040             :                                           result_attrs);
    1041             :         } else {
    1042             :                 /* Can't happen */
    1043           0 :                 DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not available: This can't happen...\n"));
    1044           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    1045           0 :                 return WERR_OK;
    1046             :         }
    1047             : 
    1048      258033 :         switch (ldb_ret) {
    1049      177391 :         case 1:
    1050      177391 :                 result = result_res[0];
    1051      177391 :                 break;
    1052       80642 :         case 0:
    1053       80558 :                 switch (format_offered) {
    1054        3158 :                 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: 
    1055        3242 :                         return DsCrackNameSPNAlias(sam_ctx, mem_ctx, 
    1056             :                                                    smb_krb5_context, 
    1057             :                                                    format_flags, format_offered, format_desired,
    1058             :                                                    name, info1);
    1059             : 
    1060       77473 :                 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
    1061       77473 :                         return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context, 
    1062             :                                               format_flags, format_offered, format_desired,
    1063             :                                               name, info1);
    1064          11 :                 default:
    1065          11 :                         break;
    1066             :                 }
    1067          11 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1068          11 :                 return WERR_OK;
    1069           0 :         case -1:
    1070           0 :                 DEBUG(2, ("DsCrackNameOneFilter result search failed: %s\n", ldb_errstring(sam_ctx)));
    1071           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    1072           0 :                 return WERR_OK;
    1073           0 :         default:
    1074           0 :                 switch (format_offered) {
    1075           0 :                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
    1076             :                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
    1077           0 :                 {
    1078           0 :                         const char *canonical_name = NULL; /* Not required, but we get warnings... */
    1079             :                         /* We may need to manually filter further */
    1080           0 :                         for (i = 0; i < ldb_ret; i++) {
    1081           0 :                                 switch (format_offered) {
    1082           0 :                                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
    1083           0 :                                         canonical_name = ldb_dn_canonical_string(mem_ctx, result_res[i]->dn);
    1084           0 :                                         break;
    1085           0 :                                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
    1086           0 :                                         canonical_name = ldb_dn_canonical_ex_string(mem_ctx, result_res[i]->dn);
    1087           0 :                                         break;
    1088           0 :                                 default:
    1089           0 :                                         break;
    1090             :                                 }
    1091           0 :                                 if (strcasecmp_m(canonical_name, name) == 0) {
    1092           0 :                                         result = result_res[i];
    1093           0 :                                         break;
    1094             :                                 }
    1095             :                         }
    1096           0 :                         if (!result) {
    1097           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1098           0 :                                 return WERR_OK;
    1099             :                         }
    1100             :                 }
    1101             :                 FALL_THROUGH;
    1102             :                 default:
    1103           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
    1104           0 :                         return WERR_OK;
    1105             :                 }
    1106             :         }
    1107             : 
    1108      177391 :         info1->dns_domain_name = ldb_dn_canonical_string(mem_ctx, result->dn);
    1109      177391 :         W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
    1110      177391 :         p = strchr(info1->dns_domain_name, '/');
    1111      177391 :         if (p) {
    1112      177391 :                 p[0] = '\0';
    1113             :         }
    1114             : 
    1115             :         /* here we can use result and domain_res[0] */
    1116      177391 :         switch (format_desired) {
    1117      171571 :         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
    1118      171571 :                 info1->result_name   = ldb_dn_alloc_linearized(mem_ctx, result->dn);
    1119      171571 :                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
    1120             : 
    1121      171571 :                 info1->status                = DRSUAPI_DS_NAME_STATUS_OK;
    1122      171571 :                 return WERR_OK;
    1123             :         }
    1124          25 :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
    1125          25 :                 info1->result_name   = ldb_msg_find_attr_as_string(result, "canonicalName", NULL);
    1126          25 :                 info1->status                = DRSUAPI_DS_NAME_STATUS_OK;
    1127          25 :                 return WERR_OK;
    1128             :         }
    1129          25 :         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
    1130             :                 /* Not in the virtual ldb attribute */
    1131          25 :                 return DsCrackNameOneSyntactical(mem_ctx, 
    1132             :                                                  DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
    1133             :                                                  DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
    1134             :                                                  result->dn, name, info1);
    1135             :         }
    1136        5623 :         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
    1137             : 
    1138        5623 :                 const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
    1139        5623 :                 const char *_acc = "", *_dom = "";
    1140        5623 :                 if (sid == NULL) {
    1141           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
    1142           0 :                         return WERR_OK;
    1143             :                 }
    1144             : 
    1145        5623 :                 if (samdb_find_attribute(sam_ctx, result, "objectClass",
    1146             :                                          "domain")) {
    1147             :                         /* This can also find a DomainDNSZones entry,
    1148             :                          * but it won't have the SID we just
    1149             :                          * checked.  */
    1150          15 :                         ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
    1151             :                                                      partitions_basedn,
    1152             :                                                      LDB_SCOPE_ONELEVEL,
    1153             :                                                      domain_attrs,
    1154             :                                                      "(ncName=%s)", ldb_dn_get_linearized(result->dn));
    1155             : 
    1156          15 :                         if (ldb_ret != LDB_SUCCESS) {
    1157           0 :                                 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
    1158           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    1159           0 :                                 return WERR_OK;
    1160             :                         }
    1161             : 
    1162          15 :                         switch (domain_res->count) {
    1163          15 :                         case 1:
    1164          15 :                                 break;
    1165           0 :                         case 0:
    1166           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1167           0 :                                 return WERR_OK;
    1168           0 :                         default:
    1169           0 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
    1170           0 :                                 return WERR_OK;
    1171             :                         }
    1172          15 :                         _dom = ldb_msg_find_attr_as_string(domain_res->msgs[0], "nETBIOSName", NULL);
    1173          15 :                         W_ERROR_HAVE_NO_MEMORY(_dom);
    1174             :                 } else {
    1175        5608 :                         _acc = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
    1176        5608 :                         if (!_acc) {
    1177           2 :                                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
    1178           2 :                                 return WERR_OK;
    1179             :                         }
    1180        5606 :                         if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx, SID_BUILTIN), sid)) {
    1181           2 :                                 _dom = "BUILTIN";
    1182             :                         } else {
    1183        5604 :                                 const char *attrs[] = { NULL };
    1184             :                                 struct ldb_result *domain_res2;
    1185        5604 :                                 struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
    1186        5604 :                                 if (!dom_sid) {
    1187           0 :                                         return WERR_OK;
    1188             :                                 }
    1189        5604 :                                 dom_sid->num_auths--;
    1190        5604 :                                 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
    1191             :                                                              NULL,
    1192             :                                                              LDB_SCOPE_BASE,
    1193             :                                                              attrs,
    1194             :                                                              "(&(objectSid=%s)(objectClass=domain))", 
    1195             :                                                              ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
    1196             : 
    1197        5604 :                                 if (ldb_ret != LDB_SUCCESS) {
    1198           0 :                                         DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s\n", ldb_errstring(sam_ctx)));
    1199           0 :                                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    1200           0 :                                         return WERR_OK;
    1201             :                                 }
    1202             : 
    1203        5604 :                                 switch (domain_res->count) {
    1204        5604 :                                 case 1:
    1205        5604 :                                         break;
    1206           0 :                                 case 0:
    1207           0 :                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1208           0 :                                         return WERR_OK;
    1209           0 :                                 default:
    1210           0 :                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
    1211           0 :                                         return WERR_OK;
    1212             :                                 }
    1213             : 
    1214        5604 :                                 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res2,
    1215             :                                                              partitions_basedn,
    1216             :                                                              LDB_SCOPE_ONELEVEL,
    1217             :                                                              domain_attrs,
    1218        5604 :                                                              "(ncName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
    1219             : 
    1220        5604 :                                 if (ldb_ret != LDB_SUCCESS) {
    1221           0 :                                         DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
    1222           0 :                                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    1223           0 :                                         return WERR_OK;
    1224             :                                 }
    1225             : 
    1226        5604 :                                 switch (domain_res2->count) {
    1227        5604 :                                 case 1:
    1228        5604 :                                         break;
    1229           0 :                                 case 0:
    1230           0 :                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1231           0 :                                         return WERR_OK;
    1232           0 :                                 default:
    1233           0 :                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
    1234           0 :                                         return WERR_OK;
    1235             :                                 }
    1236        5604 :                                 _dom = ldb_msg_find_attr_as_string(domain_res2->msgs[0], "nETBIOSName", NULL);
    1237        5604 :                                 W_ERROR_HAVE_NO_MEMORY(_dom);
    1238             :                         }
    1239             :                 }
    1240             : 
    1241        5621 :                 info1->result_name   = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
    1242        5621 :                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
    1243             : 
    1244        5621 :                 info1->status                = DRSUAPI_DS_NAME_STATUS_OK;
    1245        5621 :                 return WERR_OK;
    1246             :         }
    1247          37 :         case DRSUAPI_DS_NAME_FORMAT_GUID: {
    1248             :                 struct GUID guid;
    1249             : 
    1250          37 :                 guid = samdb_result_guid(result, "objectGUID");
    1251             : 
    1252          37 :                 info1->result_name   = GUID_string2(mem_ctx, &guid);
    1253          37 :                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
    1254             : 
    1255          37 :                 info1->status                = DRSUAPI_DS_NAME_STATUS_OK;
    1256          37 :                 return WERR_OK;
    1257             :         }
    1258          23 :         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
    1259          23 :                 info1->result_name   = ldb_msg_find_attr_as_string(result, "displayName", NULL);
    1260          23 :                 if (!info1->result_name) {
    1261           0 :                         info1->result_name   = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
    1262             :                 } 
    1263          23 :                 if (!info1->result_name) {
    1264           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1265             :                 } else {
    1266          23 :                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
    1267             :                 }
    1268          23 :                 return WERR_OK;
    1269             :         }
    1270          23 :         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
    1271          23 :                 struct ldb_message_element *el
    1272           0 :                         = ldb_msg_find_element(result,
    1273             :                                                "servicePrincipalName");
    1274          23 :                 if (el == NULL) {
    1275           1 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1276           1 :                         return WERR_OK;
    1277          22 :                 } else if (el->num_values > 1) {
    1278          21 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
    1279          21 :                         return WERR_OK;
    1280             :                 }
    1281             : 
    1282           1 :                 info1->result_name = ldb_msg_find_attr_as_string(result, "servicePrincipalName", NULL);
    1283           1 :                 if (!info1->result_name) {
    1284           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
    1285             :                 } else {
    1286           1 :                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
    1287             :                 }
    1288           1 :                 return WERR_OK;
    1289             :         }
    1290          20 :         case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN: {
    1291          20 :                 info1->dns_domain_name = NULL;
    1292          20 :                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    1293          20 :                 return WERR_OK;
    1294             :         }
    1295          21 :         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
    1296          21 :                 const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
    1297             : 
    1298          21 :                 if (sid == NULL) {
    1299           0 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
    1300           0 :                         return WERR_OK;
    1301             :                 }
    1302             : 
    1303          21 :                 info1->result_name = dom_sid_string(mem_ctx, sid);
    1304          21 :                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
    1305             : 
    1306          21 :                 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
    1307          21 :                 return WERR_OK;
    1308             :         }
    1309          23 :         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
    1310          23 :                 info1->result_name = ldb_msg_find_attr_as_string(result, "userPrincipalName", NULL);
    1311          23 :                 if (!info1->result_name) {
    1312          22 :                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
    1313             :                 } else {
    1314           1 :                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
    1315             :                 }
    1316          23 :                 return WERR_OK;
    1317             :         }
    1318           0 :         default:
    1319           0 :                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
    1320           0 :                 return WERR_OK;
    1321             :         }
    1322             : }
    1323             : 
    1324             : /* Given a user Principal Name (such as foo@bar.com),
    1325             :  * return the user and domain DNs.  This is used in the KDC to then
    1326             :  * return the Keys and evaluate policy */
    1327             : 
    1328       71715 : NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx, 
    1329             :                                    TALLOC_CTX *mem_ctx, 
    1330             :                                    const char *user_principal_name, 
    1331             :                                    struct ldb_dn **user_dn,
    1332             :                                    struct ldb_dn **domain_dn) 
    1333             : {
    1334             :         WERROR werr;
    1335             :         struct drsuapi_DsNameInfo1 info1;
    1336       71715 :         werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
    1337             :                                   DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
    1338             :                                   DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
    1339             :                                   user_principal_name,
    1340             :                                   &info1);
    1341       71715 :         if (!W_ERROR_IS_OK(werr)) {
    1342           0 :                 return werror_to_ntstatus(werr);
    1343             :         }
    1344       71715 :         switch (info1.status) {
    1345       69289 :         case DRSUAPI_DS_NAME_STATUS_OK:
    1346       69289 :                 break;
    1347        2426 :         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
    1348             :         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
    1349             :         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
    1350        2426 :                 return NT_STATUS_NO_SUCH_USER;
    1351           0 :         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
    1352             :         default:
    1353           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1354             :         }
    1355             : 
    1356       69289 :         *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
    1357             : 
    1358       69289 :         if (domain_dn) {
    1359       69270 :                 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
    1360             :                                           DRSUAPI_DS_NAME_FORMAT_CANONICAL,
    1361             :                                           DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
    1362       69270 :                                           talloc_asprintf(mem_ctx, "%s/", 
    1363             :                                                           info1.dns_domain_name),
    1364             :                                           &info1);
    1365       69270 :                 if (!W_ERROR_IS_OK(werr)) {
    1366           0 :                         return werror_to_ntstatus(werr);
    1367             :                 }
    1368       69270 :                 switch (info1.status) {
    1369       69270 :                 case DRSUAPI_DS_NAME_STATUS_OK:
    1370       69270 :                         break;
    1371           0 :                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
    1372             :                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
    1373             :                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
    1374           0 :                         return NT_STATUS_NO_SUCH_USER;
    1375           0 :                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
    1376             :                 default:
    1377           0 :                         return NT_STATUS_UNSUCCESSFUL;
    1378             :                 }
    1379             : 
    1380       69270 :                 *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
    1381             :         }
    1382             : 
    1383       69289 :         return NT_STATUS_OK;
    1384             : }
    1385             : 
    1386             : /* Given a Service Principal Name (such as host/foo.bar.com@BAR.COM),
    1387             :  * return the user and domain DNs.  This is used in the KDC to then
    1388             :  * return the Keys and evaluate policy */
    1389             : 
    1390       16444 : NTSTATUS crack_service_principal_name(struct ldb_context *sam_ctx, 
    1391             :                                       TALLOC_CTX *mem_ctx, 
    1392             :                                       const char *service_principal_name, 
    1393             :                                       struct ldb_dn **user_dn,
    1394             :                                       struct ldb_dn **domain_dn) 
    1395             : {
    1396             :         WERROR werr;
    1397             :         struct drsuapi_DsNameInfo1 info1;
    1398       16444 :         werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
    1399             :                                   DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
    1400             :                                   DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
    1401             :                                   service_principal_name,
    1402             :                                   &info1);
    1403       16444 :         if (!W_ERROR_IS_OK(werr)) {
    1404           0 :                 return werror_to_ntstatus(werr);
    1405             :         }
    1406       16444 :         switch (info1.status) {
    1407       16214 :         case DRSUAPI_DS_NAME_STATUS_OK:
    1408       16214 :                 break;
    1409         230 :         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
    1410             :         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
    1411             :         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
    1412         230 :                 return NT_STATUS_NO_SUCH_USER;
    1413           0 :         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
    1414             :         default:
    1415           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1416             :         }
    1417             : 
    1418       16214 :         *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
    1419             : 
    1420       16214 :         if (domain_dn) {
    1421       16211 :                 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
    1422             :                                           DRSUAPI_DS_NAME_FORMAT_CANONICAL,
    1423             :                                           DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
    1424       16211 :                                           talloc_asprintf(mem_ctx, "%s/", 
    1425             :                                                           info1.dns_domain_name),
    1426             :                                           &info1);
    1427       16211 :                 if (!W_ERROR_IS_OK(werr)) {
    1428           0 :                         return werror_to_ntstatus(werr);
    1429             :                 }
    1430       16211 :                 switch (info1.status) {
    1431       16211 :                 case DRSUAPI_DS_NAME_STATUS_OK:
    1432       16211 :                         break;
    1433           0 :                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
    1434             :                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
    1435             :                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
    1436           0 :                         return NT_STATUS_NO_SUCH_USER;
    1437           0 :                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
    1438             :                 default:
    1439           0 :                         return NT_STATUS_UNSUCCESSFUL;
    1440             :                 }
    1441             : 
    1442       16211 :                 *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
    1443             :         }
    1444             : 
    1445       16214 :         return NT_STATUS_OK;
    1446             : }
    1447             : 
    1448        5582 : NTSTATUS crack_name_to_nt4_name(TALLOC_CTX *mem_ctx, 
    1449             :                                 struct ldb_context *ldb,
    1450             :                                 enum drsuapi_DsNameFormat format_offered,
    1451             :                                 const char *name, 
    1452             :                                 const char **nt4_domain, const char **nt4_account)
    1453             : {
    1454             :         WERROR werr;
    1455             :         struct drsuapi_DsNameInfo1 info1;
    1456             :         char *p;
    1457             : 
    1458             :         /* Handle anonymous bind */
    1459        5582 :         if (!name || !*name) {
    1460           0 :                 *nt4_domain = "";
    1461           0 :                 *nt4_account = "";
    1462           0 :                 return NT_STATUS_OK;
    1463             :         }
    1464             : 
    1465        5582 :         werr = DsCrackNameOneName(ldb, mem_ctx, 0,
    1466             :                                   format_offered, 
    1467             :                                   DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
    1468             :                                   name,
    1469             :                                   &info1);
    1470        5582 :         if (!W_ERROR_IS_OK(werr)) {
    1471           0 :                 return werror_to_ntstatus(werr);
    1472             :         }
    1473        5582 :         switch (info1.status) {
    1474        5579 :         case DRSUAPI_DS_NAME_STATUS_OK:
    1475        5579 :                 break;
    1476           3 :         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
    1477             :         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
    1478             :         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
    1479           3 :                 return NT_STATUS_NO_SUCH_USER;
    1480           0 :         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
    1481             :         default:
    1482           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1483             :         }
    1484             : 
    1485        5579 :         *nt4_domain = talloc_strdup(mem_ctx, info1.result_name);
    1486        5579 :         if (*nt4_domain == NULL) {
    1487           0 :                 return NT_STATUS_NO_MEMORY;
    1488             :         }
    1489             : 
    1490        5579 :         p = strchr(*nt4_domain, '\\');
    1491        5579 :         if (!p) {
    1492           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1493             :         }
    1494        5579 :         p[0] = '\0';
    1495             : 
    1496        5579 :         *nt4_account = talloc_strdup(mem_ctx, &p[1]);
    1497        5579 :         if (*nt4_account == NULL) {
    1498           0 :                 return NT_STATUS_NO_MEMORY;
    1499             :         }
    1500             : 
    1501        5579 :         return NT_STATUS_OK;
    1502             : }
    1503             : 
    1504         374 : NTSTATUS crack_auto_name_to_nt4_name(TALLOC_CTX *mem_ctx,
    1505             :                                      struct ldb_context *ldb,
    1506             :                                      const char *name,
    1507             :                                      const char **nt4_domain,
    1508             :                                      const char **nt4_account)
    1509             : {
    1510         374 :         enum drsuapi_DsNameFormat format_offered = DRSUAPI_DS_NAME_FORMAT_UNKNOWN;
    1511             : 
    1512             :         /* Handle anonymous bind */
    1513         374 :         if (!name || !*name) {
    1514           4 :                 *nt4_domain = "";
    1515           4 :                 *nt4_account = "";
    1516           4 :                 return NT_STATUS_OK;
    1517             :         }
    1518             : 
    1519             :         /*
    1520             :          * Here we only consider a subset of the possible name forms listed in
    1521             :          * [MS-ADTS] 5.1.1.1.1, and we don't retry with a different name form if
    1522             :          * the first attempt fails.
    1523             :          */
    1524             : 
    1525         370 :         if (strchr_m(name, '=')) {
    1526         287 :                 format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
    1527          83 :         } else if (strchr_m(name, '@')) {
    1528          45 :                 format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL;
    1529          38 :         } else if (strchr_m(name, '\\')) {
    1530          32 :                 format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
    1531           6 :         } else if (strchr_m(name, '\n')) {
    1532           2 :                 format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX;
    1533           4 :         } else if (strchr_m(name, '/')) {
    1534           2 :                 format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL;
    1535           2 :         } else if ((name[0] == 'S' || name[0] == 's') && name[1] == '-') {
    1536           2 :                 format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
    1537             :         } else {
    1538           0 :                 return NT_STATUS_NO_SUCH_USER;
    1539             :         }
    1540             : 
    1541         370 :         return crack_name_to_nt4_name(mem_ctx, ldb, format_offered, name, nt4_domain, nt4_account);
    1542             : }
    1543             : 
    1544             : 
    1545           0 : WERROR dcesrv_drsuapi_ListRoles(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
    1546             :                                 const struct drsuapi_DsNameRequest1 *req1,
    1547             :                                 struct drsuapi_DsNameCtr1 **ctr1)
    1548             : {
    1549             :         struct drsuapi_DsNameInfo1 *names;
    1550             :         uint32_t i;
    1551           0 :         uint32_t count = 5;/*number of fsmo role owners we are going to return*/
    1552             : 
    1553           0 :         *ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
    1554           0 :         W_ERROR_HAVE_NO_MEMORY(*ctr1);
    1555           0 :         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
    1556           0 :         W_ERROR_HAVE_NO_MEMORY(names);
    1557             : 
    1558           0 :         for (i = 0; i < count; i++) {
    1559             :                 WERROR werr;
    1560             :                 struct ldb_dn *role_owner_dn, *fsmo_role_dn, *server_dn;
    1561           0 :                 werr = dsdb_get_fsmo_role_info(mem_ctx, sam_ctx, i,
    1562             :                                                &fsmo_role_dn, &role_owner_dn);
    1563           0 :                 if(!W_ERROR_IS_OK(werr)) {
    1564           0 :                         return werr;
    1565             :                 }
    1566           0 :                 server_dn = ldb_dn_copy(mem_ctx, role_owner_dn);
    1567           0 :                 ldb_dn_remove_child_components(server_dn, 1);
    1568           0 :                 names[i].status = DRSUAPI_DS_NAME_STATUS_OK;
    1569           0 :                 names[i].dns_domain_name = samdb_dn_to_dnshostname(sam_ctx, mem_ctx,
    1570             :                                                                    server_dn);
    1571           0 :                 if(!names[i].dns_domain_name) {
    1572           0 :                         DEBUG(4, ("list_roles: Failed to find dNSHostName for server %s\n",
    1573             :                                   ldb_dn_get_linearized(server_dn)));
    1574             :                 }
    1575           0 :                 names[i].result_name = talloc_strdup(mem_ctx, ldb_dn_get_linearized(role_owner_dn));
    1576             :         }
    1577             : 
    1578           0 :         (*ctr1)->count = count;
    1579           0 :         (*ctr1)->array = names;
    1580             : 
    1581           0 :         return WERR_OK;
    1582             : }
    1583             : 
    1584         907 : WERROR dcesrv_drsuapi_CrackNamesByNameFormat(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
    1585             :                                              const struct drsuapi_DsNameRequest1 *req1,
    1586             :                                              struct drsuapi_DsNameCtr1 **ctr1)
    1587             : {
    1588             :         struct drsuapi_DsNameInfo1 *names;
    1589             :         uint32_t i, count;
    1590             :         WERROR status;
    1591             : 
    1592         907 :         *ctr1 = talloc_zero(mem_ctx, struct drsuapi_DsNameCtr1);
    1593         907 :         W_ERROR_HAVE_NO_MEMORY(*ctr1);
    1594             : 
    1595         907 :         count = req1->count;
    1596         907 :         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
    1597         907 :         W_ERROR_HAVE_NO_MEMORY(names);
    1598             : 
    1599        1814 :         for (i=0; i < count; i++) {
    1600        2637 :                 status = DsCrackNameOneName(sam_ctx, mem_ctx,
    1601         907 :                                             req1->format_flags,
    1602          42 :                                             req1->format_offered,
    1603          42 :                                             req1->format_desired,
    1604         907 :                                             req1->names[i].str,
    1605         907 :                                             &names[i]);
    1606         907 :                 if (!W_ERROR_IS_OK(status)) {
    1607           0 :                         return status;
    1608             :                 }
    1609             :         }
    1610             : 
    1611         907 :         (*ctr1)->count = count;
    1612         907 :         (*ctr1)->array = names;
    1613             : 
    1614         907 :         return WERR_OK;
    1615             : }
    1616             : 
    1617           0 : WERROR dcesrv_drsuapi_ListInfoServer(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
    1618             :                                      const struct drsuapi_DsNameRequest1 *req1,
    1619             :                                      struct drsuapi_DsNameCtr1 **_ctr1)
    1620             : {
    1621             :         struct drsuapi_DsNameInfo1 *names;
    1622             :         struct ldb_result *res;
    1623             :         struct ldb_dn *server_dn, *dn;
    1624             :         struct drsuapi_DsNameCtr1 *ctr1;
    1625             :         int ret, i;
    1626             :         const char *str;
    1627           0 :         const char *attrs[] = {
    1628             :                 "dn",
    1629             :                 "dNSHostName",
    1630             :                 "serverReference",
    1631             :                 NULL
    1632             :         };
    1633             : 
    1634           0 :         *_ctr1 = NULL;
    1635             : 
    1636           0 :         ctr1 = talloc_zero(mem_ctx, struct drsuapi_DsNameCtr1);
    1637           0 :         W_ERROR_HAVE_NO_MEMORY(ctr1);
    1638             : 
    1639             :         /*
    1640             :          * No magic value here, we have to return 3 entries according to the
    1641             :          * MS-DRSR.pdf
    1642             :          */
    1643           0 :         ctr1->count = 3;
    1644           0 :         names = talloc_zero_array(ctr1, struct drsuapi_DsNameInfo1,
    1645             :                                   ctr1->count);
    1646           0 :         W_ERROR_HAVE_NO_MEMORY(names);
    1647           0 :         ctr1->array = names;
    1648             : 
    1649           0 :         for (i=0; i < ctr1->count; i++) {
    1650           0 :                 names[i].status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
    1651             :         }
    1652           0 :         *_ctr1 = ctr1;
    1653             : 
    1654           0 :         if (req1->count != 1) {
    1655           0 :                 DEBUG(1, ("Expected a count of 1 for the ListInfoServer crackname \n"));
    1656           0 :                 return WERR_OK;
    1657             :         }
    1658             : 
    1659           0 :         if (req1->names[0].str == NULL) {
    1660           0 :                 return WERR_OK;
    1661             :         }
    1662             : 
    1663           0 :         server_dn = ldb_dn_new(mem_ctx, sam_ctx, req1->names[0].str);
    1664           0 :         W_ERROR_HAVE_NO_MEMORY(server_dn);
    1665             : 
    1666           0 :         ret = ldb_search(sam_ctx, mem_ctx, &res, server_dn, LDB_SCOPE_ONELEVEL,
    1667             :                          NULL, "(objectClass=nTDSDSA)");
    1668             : 
    1669           0 :         if (ret != LDB_SUCCESS) {
    1670           0 :                 DEBUG(1, ("Search for objectClass=nTDSDSA "
    1671             :                           "returned less than 1 objects\n"));
    1672           0 :                 return WERR_OK;
    1673             :         }
    1674             : 
    1675           0 :         if (res->count != 1) {
    1676           0 :                 DEBUG(1, ("Search for objectClass=nTDSDSA "
    1677             :                           "returned less than 1 objects\n"));
    1678           0 :                 return WERR_OK;
    1679             :         }
    1680             : 
    1681           0 :         if (res->msgs[0]->dn) {
    1682           0 :                 names[0].result_name = ldb_dn_alloc_linearized(names, res->msgs[0]->dn);
    1683           0 :                 W_ERROR_HAVE_NO_MEMORY(names[0].result_name);
    1684           0 :                 names[0].status = DRSUAPI_DS_NAME_STATUS_OK;
    1685             :         }
    1686             : 
    1687           0 :         talloc_free(res);
    1688             : 
    1689           0 :         ret = ldb_search(sam_ctx, mem_ctx, &res, server_dn, LDB_SCOPE_BASE,
    1690             :                          attrs, "(objectClass=*)");
    1691           0 :         if (ret != LDB_SUCCESS) {
    1692           0 :                 DEBUG(1, ("Search for objectClass=* on dn %s"
    1693             :                           "returned %s\n", req1->names[0].str,
    1694             :                           ldb_strerror(ret)));
    1695           0 :                 return WERR_OK;
    1696             :         }
    1697             : 
    1698           0 :         if (res->count != 1) {
    1699           0 :                 DEBUG(1, ("Search for objectClass=* on dn %s"
    1700             :                           "returned less than 1 objects\n", req1->names[0].str));
    1701           0 :                 return WERR_OK;
    1702             :         }
    1703             : 
    1704           0 :         str = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
    1705           0 :         if (str != NULL) {
    1706           0 :                 names[1].result_name = talloc_strdup(names, str);
    1707           0 :                 W_ERROR_HAVE_NO_MEMORY(names[1].result_name);
    1708           0 :                 names[1].status = DRSUAPI_DS_NAME_STATUS_OK;
    1709             :         }
    1710             : 
    1711           0 :         dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, res->msgs[0], "serverReference");
    1712           0 :         if (dn != NULL) {
    1713           0 :                 names[2].result_name = ldb_dn_alloc_linearized(names, dn);
    1714           0 :                 W_ERROR_HAVE_NO_MEMORY(names[2].result_name);
    1715           0 :                 names[2].status = DRSUAPI_DS_NAME_STATUS_OK;
    1716             :         }
    1717             : 
    1718           0 :         talloc_free(dn);
    1719           0 :         talloc_free(res);
    1720             : 
    1721           0 :         return WERR_OK;
    1722             : }

Generated by: LCOV version 1.13