s4:dsdb Fix crash from LDAP login of DOM\\
[ira/wip.git] / source4 / dsdb / samdb / cracknames.c
index b5479e89be5496598b3d9958214c1c3f73cb3117..8f7f481e2db6b03ae2d5801d482367b3270292b2 100644 (file)
 
    Copyright (C) Stefan Metzmacher 2004
    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "librpc/gen_ndr/ndr_drsuapi.h"
-#include "rpc_server/dcerpc_server.h"
+#include "librpc/gen_ndr/drsuapi.h"
 #include "rpc_server/common/common.h"
-#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
+#include "lib/events/events.h"
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
-#include "dsdb/samdb/samdb.h"
-#include "libcli/ldap/ldap.h"
+#include "libcli/ldap/ldap_ndr.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_misc.h"
 #include "auth/auth.h"
+#include "../lib/util/util_ldb.h"
+#include "dsdb/samdb/samdb.h"
+#include "param/param.h"
 
 static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                                   struct smb_krb5_context *smb_krb5_context,
                                   uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
-                                  const struct ldb_dn *name_dn, const char *name, 
+                                  struct ldb_dn *name_dn, const char *name, 
                                   const char *domain_filter, const char *result_filter, 
                                   struct drsuapi_DsNameInfo1 *info1);
 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
                                        uint32_t format_offered, uint32_t format_desired,
-                                       const struct ldb_dn *name_dn, const char *name, 
+                                       struct ldb_dn *name_dn, const char *name, 
                                        struct drsuapi_DsNameInfo1 *info1);
 
+static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, 
+                                       const char *name, 
+                                       struct drsuapi_DsNameInfo1 *info1) 
+{
+       krb5_error_code ret;
+       krb5_principal principal;
+       /* perhaps it's a principal with a realm, so return the right 'domain only' response */
+       char *realm;
+       ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
+                                   KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
+       if (ret) {
+               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+               return WERR_OK;
+       }
+
+       /* This isn't an allocation assignemnt, so it is free'ed with the krb5_free_principal */
+       realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);
+
+       info1->dns_domain_name  = talloc_strdup(mem_ctx, realm);
+       krb5_free_principal(smb_krb5_context->krb5_context, principal);
+
+       W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
+
+       info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
+       return WERR_OK;
+}              
+
 static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx, 
-                                  TALLOC_CTX *mem_ctx,
-                                  const char *alias_from,
-                                  char **alias_to)
+                                                     TALLOC_CTX *mem_ctx,
+                                                     const char *alias_from,
+                                                     char **alias_to)
 {
        int i;
        int ret;
        struct ldb_result *res;
        struct ldb_message_element *spnmappings;
-       struct ldb_dn *service_dn = ldb_dn_string_compose(mem_ctx, samdb_base_dn(mem_ctx),
-                                               "CN=Directory Service,CN=Windows NT"
-                                               ",CN=Services,CN=Configuration");
-       char *service_dn_str = ldb_dn_linearize(mem_ctx, service_dn);
+       TALLOC_CTX *tmp_ctx;
+       struct ldb_dn *service_dn;
+       char *service_dn_str;
+
        const char *directory_attrs[] = {
                "sPNMappings", 
                NULL
        };
 
-       ret = ldb_search(ldb_ctx, service_dn, LDB_SCOPE_BASE, "(objectClass=nTDSService)",
-                          directory_attrs, &res);
-       talloc_steal(mem_ctx, res);
+       tmp_ctx = talloc_new(mem_ctx);
+       if (!tmp_ctx) {
+               return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+       }
+
+       service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services");
+       if ( ! ldb_dn_add_base(service_dn, samdb_config_dn(ldb_ctx))) {
+               return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+       }
+       service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn);
+       if ( ! service_dn_str) {
+               return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+       }
 
-       if (ret != LDB_SUCCESS) {
+       ret = ldb_search(ldb_ctx, tmp_ctx, &res, service_dn, LDB_SCOPE_BASE,
+                        directory_attrs, "(objectClass=nTDSService)");
+
+       if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
                DEBUG(1, ("ldb_search: dn: %s not found: %s", service_dn_str, ldb_errstring(ldb_ctx)));
+               return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+       } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               DEBUG(1, ("ldb_search: dn: %s not found", service_dn_str));
                return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
-       } else if (res->count > 1) {
-               DEBUG(1, ("ldb_search: dn: %s found %d times!", service_dn_str, res->count));
+       } else if (res->count != 1) {
+               talloc_free(res);
+               DEBUG(1, ("ldb_search: dn: %s not found", service_dn_str));
                return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        }
-       
+
        spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings");
        if (!spnmappings || spnmappings->num_values == 0) {
                DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute", service_dn_str));
+               talloc_free(tmp_ctx);
                return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        }
 
        for (i = 0; i < spnmappings->num_values; i++) {
                char *mapping, *p, *str;
-               mapping = talloc_strdup(mem_ctx, 
+               mapping = talloc_strdup(tmp_ctx, 
                                        (const char *)spnmappings->values[i].data);
                if (!mapping) {
                        DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));
+                       talloc_free(tmp_ctx);
                        return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                }
-               
+
                /* C string manipulation sucks */
-               
+
                p = strchr(mapping, '=');
                if (!p) {
                        DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n", 
                                  service_dn_str, mapping));
+                       talloc_free(tmp_ctx);
                        return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                }
                p[0] = '\0';
@@ -110,11 +159,14 @@ static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, stru
                        }
                        if (strcasecmp(str, alias_from) == 0) {
                                *alias_to = mapping;
+                               talloc_steal(mem_ctx, mapping);
+                               talloc_free(tmp_ctx);
                                return DRSUAPI_DS_NAME_STATUS_OK;
                        }
                } while (p);
        }
-       DEBUG(1, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
+       DEBUG(4, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
+       talloc_free(tmp_ctx);
        return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
 }
 
@@ -131,45 +183,50 @@ static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_c
        WERROR wret;
        krb5_error_code ret;
        krb5_principal principal;
-       const char *service;
+       const char *service, *dns_name;
        char *new_service;
        char *new_princ;
        enum drsuapi_DsNameStatus namestatus;
-       
+
        /* parse principal */
-       ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, 
-                                     name, &principal);
+       ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
+                                   name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
        if (ret) {
                DEBUG(2, ("Could not parse principal: %s: %s",
                          name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
                                                           ret, mem_ctx)));
                return WERR_NOMEM;
        }
-       
+
        /* grab cifs/, http/ etc */
-       
+
        /* This is checked for in callers, but be safe */
        if (principal->name.name_string.len < 2) {
                info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                return WERR_OK;
        }
        service = principal->name.name_string.val[0];
-       
+       dns_name = principal->name.name_string.val[1];
+
        /* MAP it */
        namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context, 
                                          sam_ctx, mem_ctx, 
                                          service, &new_service);
-       
-       if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
-               info1->status = namestatus;
+
+       if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
+               info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
+               info1->dns_domain_name  = talloc_strdup(mem_ctx, dns_name);
+               if (!info1->dns_domain_name) {
+                       krb5_free_principal(smb_krb5_context->krb5_context, principal);
+                       return WERR_NOMEM;
+               }
                return WERR_OK;
-       }
-       
-       if (ret != 0) {
-               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+       } else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
+               info1->status = namestatus;
+               krb5_free_principal(smb_krb5_context->krb5_context, principal);
                return WERR_OK;
        }
-       
+
        /* ooh, very nasty playing around in the Principal... */
        free(principal->name.name_string.val[0]);
        principal->name.name_string.val[0] = strdup(new_service);
@@ -177,19 +234,27 @@ static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_c
                krb5_free_principal(smb_krb5_context->krb5_context, principal);
                return WERR_NOMEM;
        }
-       
+
        /* reform principal */
-       ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &new_princ);
+       ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
+                                     KRB5_PRINCIPAL_UNPARSE_NO_REALM, &new_princ);
 
-       krb5_free_principal(smb_krb5_context->krb5_context, principal);
-       
        if (ret) {
+               krb5_free_principal(smb_krb5_context->krb5_context, principal);
                return WERR_NOMEM;
        }
-       
+
        wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
                                  new_princ, info1);
        free(new_princ);
+       if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) {
+               info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
+               info1->dns_domain_name  = talloc_strdup(mem_ctx, dns_name);
+               if (!info1->dns_domain_name) {
+                       wret = WERR_NOMEM;
+               }
+       }
+       krb5_free_principal(smb_krb5_context->krb5_context, principal);
        return wret;
 }
 
@@ -200,13 +265,16 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                             uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                             const char *name, struct drsuapi_DsNameInfo1 *info1)
 {
+       int ldb_ret;
        WERROR status;
        const char *domain_filter = NULL;
        const char *result_filter = NULL;
        krb5_error_code ret;
        krb5_principal principal;
-       char **realm;
+       char *realm;
        char *unparsed_name_short;
+       const char *domain_attrs[] = { NULL };
+       struct ldb_result *domain_res = NULL;
 
        /* Prevent recursion */
        if (!name) {
@@ -214,29 +282,55 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                return WERR_OK;
        }
 
-       ret = krb5_parse_name_mustrealm(smb_krb5_context->krb5_context, name, &principal);
+       ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
+                                   KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
        if (ret) {
                info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                return WERR_OK;
        }
-       
-       domain_filter = NULL;
-       realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
-       domain_filter = talloc_asprintf(mem_ctx, 
-                                       "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
-                                       ldb_binary_encode_string(mem_ctx, *realm), 
-                                       ldb_binary_encode_string(mem_ctx, *realm));
-       ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+
+       realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);
+
+       ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
+                                    samdb_partitions_dn(sam_ctx, mem_ctx), 
+                                    LDB_SCOPE_ONELEVEL,
+                                    domain_attrs,
+                                    "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
+                                    ldb_binary_encode_string(mem_ctx, realm), 
+                                    ldb_binary_encode_string(mem_ctx, realm));
+
+       if (ldb_ret != LDB_SUCCESS) {
+               DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s", ldb_errstring(sam_ctx)));
+               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+               return WERR_OK;
+       }
+
+       switch (domain_res->count) {
+       case 1:
+               break;
+       case 0:
+               return dns_domain_from_principal(mem_ctx, smb_krb5_context, 
+                                                name, info1);
+       default:
+               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+               return WERR_OK;
+       }
+
+       ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
+                                     KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
-               
+
        if (ret) {
                free(unparsed_name_short);
                return WERR_NOMEM;
        }
-       
+
        /* This may need to be extended for more userPrincipalName variations */
        result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", 
                                        ldb_binary_encode_string(mem_ctx, unparsed_name_short));
+
+       domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
+
        if (!result_filter || !domain_filter) {
                free(unparsed_name_short);
                return WERR_NOMEM;
@@ -247,6 +341,7 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                                      NULL, unparsed_name_short, domain_filter, result_filter, 
                                      info1);
        free(unparsed_name_short);
+
        return status;
 }
 
@@ -261,12 +356,7 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
        const char *result_filter = NULL;
        struct ldb_dn *name_dn = NULL;
 
-       struct smb_krb5_context *smb_krb5_context;
-       ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
-                               
-       if (ret) {
-               return WERR_NOMEM;
-       }
+       struct smb_krb5_context *smb_krb5_context = NULL;
 
        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
        info1->dns_domain_name = NULL;
@@ -282,34 +372,92 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
 
        /* here we need to set the domain_filter and/or the result_filter */
        switch (format_offered) {
-       case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
-               char *str;
-               
+       case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
+       {
+               int i;
+               enum drsuapi_DsNameFormat formats[] = {
+                       DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+                       DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+                       DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY,
+                       DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+                       DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+                       DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
+               };
+               WERROR werr;
+               for (i=0; i < ARRAY_SIZE(formats); i++) {
+                       werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               return werr;
+                       }
+                       if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
+                               return werr;
+                       }
+               }
+               return werr;
+       }
+
+       case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
+       case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
+       {
+               char *str, *s, *account;
+
+               if (strlen(name) == 0) {
+                       info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                       return WERR_OK;
+               }
+
                str = talloc_strdup(mem_ctx, name);
-               WERR_TALLOC_CHECK(str);
-               
-               if (strlen(str) == 0 || str[strlen(str)-1] != '/') {
+               W_ERROR_HAVE_NO_MEMORY(str);
+
+               if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
+                       /* Look backwards for the \n, and replace it with / */
+                       s = strrchr(str, '\n');
+                       if (!s) {
+                               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                               return WERR_OK;
+                       }
+                       s[0] = '/';
+               }
+
+               s = strchr(str, '/');
+               if (!s) {
+                       /* there must be at least one / */
                        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                        return WERR_OK;
                }
-               
-               str[strlen(str)-1] = '\0';
-               
-               domain_filter = talloc_asprintf(mem_ctx, 
-                                               "(&(&(&(dnsRoot=%s)(objectclass=crossRef)))(nETBIOSName=*)(ncName=*))", 
-                                               ldb_binary_encode_string(mem_ctx, str));
-               WERR_TALLOC_CHECK(domain_filter);
-               
+
+               s[0] = '\0';
+               s++;
+
+               domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))", 
+                                               ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str)));
+               W_ERROR_HAVE_NO_MEMORY(domain_filter);
+
+               /* There may not be anything after the domain component (search for the domain itself) */
+               if (s[0]) {
+
+                       account = strrchr(s, '/');
+                       if (!account) {
+                               account = s;
+                       } else {
+                               account++;
+                       }
+                       account = ldb_binary_encode_string(mem_ctx, account);
+                       W_ERROR_HAVE_NO_MEMORY(account);
+                       result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
+                                                       account);              
+                       W_ERROR_HAVE_NO_MEMORY(result_filter);
+               }
                break;
        }
        case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
                char *p;
                char *domain;
                const char *account = NULL;
-               
+
                domain = talloc_strdup(mem_ctx, name);
-               WERR_TALLOC_CHECK(domain);
-               
+               W_ERROR_HAVE_NO_MEMORY(domain);
+
                p = strchr(domain, '\\');
                if (!p) {
                        /* invalid input format */
@@ -317,33 +465,37 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                        return WERR_OK;
                }
                p[0] = '\0';
-               
+
                if (p[1]) {
                        account = &p[1];
                }
-               
+
                domain_filter = talloc_asprintf(mem_ctx, 
                                                "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
                                                ldb_binary_encode_string(mem_ctx, domain));
-               WERR_TALLOC_CHECK(domain_filter);
+               W_ERROR_HAVE_NO_MEMORY(domain_filter);
                if (account) {
                        result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
                                                        ldb_binary_encode_string(mem_ctx, account));
-                       WERR_TALLOC_CHECK(result_filter);
+                       W_ERROR_HAVE_NO_MEMORY(result_filter);
                }
-               
+
                talloc_free(domain);
                break;
        }
+
+               /* A LDAP DN as a string */
        case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
-               name_dn = ldb_dn_explode(mem_ctx, name);
                domain_filter = NULL;
-               if (!name_dn) {
+               name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
+               if (! ldb_dn_validate(name_dn)) {
                        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                        return WERR_OK;
                }
                break;
        }
+
+               /* A GUID as a string */
        case DRSUAPI_DS_NAME_FORMAT_GUID: {
                struct GUID guid;
                char *ldap_guid;
@@ -355,14 +507,14 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                        return WERR_OK;
                }
-                       
+
                ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
                if (!ldap_guid) {
                        return WERR_NOMEM;
                }
                result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
                                                ldap_guid);
-               WERR_TALLOC_CHECK(result_filter);
+               W_ERROR_HAVE_NO_MEMORY(result_filter);
                break;
        }
        case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
@@ -371,14 +523,15 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
                                                ldb_binary_encode_string(mem_ctx, name), 
                                                ldb_binary_encode_string(mem_ctx, name));
-               WERR_TALLOC_CHECK(result_filter);
+               W_ERROR_HAVE_NO_MEMORY(result_filter);
                break;
        }
-       
+
+               /* A S-1234-5678 style string */
        case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
                struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
                char *ldap_sid;
-                                                                           
+
                domain_filter = NULL;
                if (!sid) {
                        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
@@ -391,20 +544,32 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                }
                result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
                                                ldap_sid);
-               WERR_TALLOC_CHECK(result_filter);
+               W_ERROR_HAVE_NO_MEMORY(result_filter);
                break;
        }
        case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
                krb5_principal principal;
                char *unparsed_name;
+
+               ret = smb_krb5_init_context(mem_ctx, 
+                                           ldb_get_event_context(sam_ctx),
+                                           (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), 
+                                           &smb_krb5_context);
+
+               if (ret) {
+                       return WERR_NOMEM;
+               }
+
+               /* Ensure we reject compleate junk first */
                ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
                if (ret) {
                        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                        return WERR_OK;
                }
-               
+
                domain_filter = NULL;
-               
+
+               /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */
                ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
                if (ret) {
                        krb5_free_principal(smb_krb5_context->krb5_context, principal);
@@ -412,46 +577,48 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                }
 
                krb5_free_principal(smb_krb5_context->krb5_context, principal);
+
+               /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
                result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))", 
                                                ldb_binary_encode_string(mem_ctx, unparsed_name));
-               
+
                free(unparsed_name);
-               WERR_TALLOC_CHECK(result_filter);
+               W_ERROR_HAVE_NO_MEMORY(result_filter);
                break;
        }
        case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
                krb5_principal principal;
                char *unparsed_name_short;
                char *service;
-               ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, name, &principal);
-               if (ret) {
-                       /* perhaps it's a principal with a realm, so return the right 'domain only' response */
-                       char **realm;
-                       ret = krb5_parse_name_mustrealm(smb_krb5_context->krb5_context, name, &principal);
-                       if (ret) {
-                               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
-                               return WERR_OK;
-                       }
-                               
-                       /* This isn't an allocation assignemnt, so it is free'ed with the krb5_free_principal */
-                       realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
 
-                       info1->dns_domain_name  = talloc_strdup(info1, *realm);
-                       krb5_free_principal(smb_krb5_context->krb5_context, principal);
-       
-                       WERR_TALLOC_CHECK(info1->dns_domain_name);
+               ret = smb_krb5_init_context(mem_ctx, 
+                                           ldb_get_event_context(sam_ctx),
+                                           (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), 
+                                           &smb_krb5_context);
 
-                       info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
-                       return WERR_OK;
-                       
-               } else if (principal->name.name_string.len < 2) {
+               if (ret) {
+                       return WERR_NOMEM;
+               }
+
+               ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
+               if (ret == 0 && principal->name.name_string.len < 2) {
                        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+                       krb5_free_principal(smb_krb5_context->krb5_context, principal);
                        return WERR_OK;
                }
+               ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
+                                           KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
+               if (ret) {
+                       krb5_free_principal(smb_krb5_context->krb5_context, principal);
+
+                       return dns_domain_from_principal(mem_ctx, smb_krb5_context,
+                                                        name, info1);
+               }
 
                domain_filter = NULL;
-               
-               ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+
+               ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
+                                             KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
                if (ret) {
                        krb5_free_principal(smb_krb5_context->krb5_context, principal);
                        return WERR_NOMEM;
@@ -476,8 +643,8 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                }
                krb5_free_principal(smb_krb5_context->krb5_context, principal);
                free(unparsed_name_short);
-               WERR_TALLOC_CHECK(result_filter);
-               
+               W_ERROR_HAVE_NO_MEMORY(result_filter);
+
                break;
        }
        default: {
@@ -491,7 +658,7 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
                                                 name_dn, name, info1);
        }
-       
+
        return DsCrackNameOneFilter(sam_ctx, mem_ctx, 
                                    smb_krb5_context, 
                                    format_flags, format_offered, format_desired, 
@@ -506,7 +673,7 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
 
 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
                                        uint32_t format_offered, uint32_t format_desired,
-                                       const struct ldb_dn *name_dn, const char *name, 
+                                       struct ldb_dn *name_dn, const char *name, 
                                        struct drsuapi_DsNameInfo1 *info1)
 {
        char *cracked;
@@ -531,7 +698,7 @@ static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
        if (!cracked) {
                return WERR_NOMEM;
        }
-       
+
        return WERR_OK; 
 }
 
@@ -545,107 +712,181 @@ static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
 static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                                   struct smb_krb5_context *smb_krb5_context,
                                   uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
-                                  const struct ldb_dn *name_dn, const char *name, 
+                                  struct ldb_dn *name_dn, const char *name, 
                                   const char *domain_filter, const char *result_filter, 
                                   struct drsuapi_DsNameInfo1 *info1)
 {
        int ldb_ret;
-       struct ldb_message **domain_res = NULL;
+       struct ldb_result *domain_res = NULL;
        const char * const *domain_attrs;
        const char * const *result_attrs;
        struct ldb_message **result_res = NULL;
-       const struct ldb_dn *result_basedn;
+       struct ldb_message *result = NULL;
+       struct ldb_dn *result_basedn = NULL;
+       int i;
+       char *p;
+       struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
+
+       const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
+       const char * const _result_attrs_null[] = { NULL };
+
+       const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
+       const char * const _result_attrs_canonical[] = { "canonicalName", NULL };
+
+       const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
+       const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};
+
+       const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
+       const char * const _result_attrs_guid[] = { "objectGUID", NULL};
+
+       const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
+       const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};
+
+       const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
+       const char * const _result_attrs_none[] = { NULL};
 
        /* here we need to set the attrs lists for domain and result lookups */
        switch (format_desired) {
        case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
-       case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
-               const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
-               const char * const _result_attrs[] = { NULL};
-               
-               domain_attrs = _domain_attrs;
-               result_attrs = _result_attrs;
+       case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
+               domain_attrs = _domain_attrs_1779;
+               result_attrs = _result_attrs_null;
                break;
-       }
-       case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
-               const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
-               const char * const _result_attrs[] = { "canonicalName", NULL };
-               
-               domain_attrs = _domain_attrs;
-               result_attrs = _result_attrs;
+       case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
+               domain_attrs = _domain_attrs_canonical;
+               result_attrs = _result_attrs_canonical;
                break;
-       }
-       case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
-               const char * const _domain_attrs[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
-               const char * const _result_attrs[] = { "sAMAccountName", "objectSid", NULL};
-               
-               domain_attrs = _domain_attrs;
-               result_attrs = _result_attrs;
+       case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
+               domain_attrs = _domain_attrs_nt4;
+               result_attrs = _result_attrs_nt4;
                break;
-       }
-       case DRSUAPI_DS_NAME_FORMAT_GUID: {
-               const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
-               const char * const _result_attrs[] = { "objectGUID", NULL};
-               
-               domain_attrs = _domain_attrs;
-               result_attrs = _result_attrs;
+       case DRSUAPI_DS_NAME_FORMAT_GUID:               
+               domain_attrs = _domain_attrs_guid;
+               result_attrs = _result_attrs_guid;
                break;
-       }
-       case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
-               const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
-               const char * const _result_attrs[] = { "displayName", "samAccountName", NULL};
-               
-               domain_attrs = _domain_attrs;
-               result_attrs = _result_attrs;
+       case DRSUAPI_DS_NAME_FORMAT_DISPLAY:            
+               domain_attrs = _domain_attrs_display;
+               result_attrs = _result_attrs_display;
                break;
-       }
        default:
-               return WERR_OK;
+               domain_attrs = _domain_attrs_none;
+               result_attrs = _result_attrs_none;
+               break;
        }
 
        if (domain_filter) {
                /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
-               ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
-                                      "%s", domain_filter);
-       } else {
-               ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
-                                      "(ncName=%s)", ldb_dn_linearize(mem_ctx, samdb_base_dn(mem_ctx)));
-       } 
+               ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
+                                            partitions_basedn,
+                                            LDB_SCOPE_ONELEVEL,
+                                            domain_attrs,
+                                            "%s", domain_filter);
 
-       switch (ldb_ret) {
-       case 1:
-               break;
-       case 0:
-               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
-               return WERR_OK;
-       case -1:
+               if (ldb_ret != LDB_SUCCESS) {
+                       DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s", ldb_errstring(sam_ctx)));
+                       info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                       return WERR_OK;
+               }
+
+               switch (domain_res->count) {
+               case 1:
+                       break;
+               case 0:
+                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+                       return WERR_OK;
+               default:
+                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+                       return WERR_OK;
+               }
+
+               info1->dns_domain_name  = samdb_result_string(domain_res->msgs[0], "dnsRoot", NULL);
+               W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
+               info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
+       } else {
+               info1->dns_domain_name  = NULL;
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
-               return WERR_OK;
-       default:
-               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
-               return WERR_OK;
        }
 
-       info1->dns_domain_name  = samdb_result_string(domain_res[0], "dnsRoot", NULL);
-       WERR_TALLOC_CHECK(info1->dns_domain_name);
-       info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
-
        if (result_filter) {
-               result_basedn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
-               
-               ldb_ret = gendb_search(sam_ctx, mem_ctx, result_basedn, &result_res,
-                                      result_attrs, "%s", result_filter);
+               int ret;
+               struct ldb_result *res;
+               if (domain_res) {
+                       result_basedn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
+
+                       ret = ldb_search(sam_ctx, mem_ctx, &res,
+                                                result_basedn, LDB_SCOPE_SUBTREE, 
+                                                result_attrs, "%s", result_filter);
+                       if (ret != LDB_SUCCESS) {
+                               talloc_free(result_res);
+                               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                               return WERR_OK;
+                       }
+                       ldb_ret = res->count;
+                       result_res = res->msgs;
+               } else {
+                       /* search with the 'phantom root' flag */
+                       struct ldb_request *req;
+
+                       res = talloc_zero(mem_ctx, struct ldb_result);
+                       W_ERROR_HAVE_NO_MEMORY(res);
+
+                       ret = ldb_build_search_req(&req, sam_ctx, mem_ctx,
+                                                  ldb_get_root_basedn(sam_ctx),
+                                                  LDB_SCOPE_SUBTREE,
+                                                  result_filter,
+                                                  result_attrs,
+                                                  NULL,
+                                                  res,
+                                                  ldb_search_default_callback,
+                                                  NULL);
+                       if (ret == LDB_SUCCESS) {
+                               struct ldb_search_options_control *search_options;
+                               search_options = talloc(req, struct ldb_search_options_control);
+                               W_ERROR_HAVE_NO_MEMORY(search_options);
+                               search_options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
+
+                               ret = ldb_request_add_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID, false, search_options);
+                       }
+                       if (ret != LDB_SUCCESS) {
+                               talloc_free(res);
+                               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                               return WERR_OK;
+                       }
+
+                       ret = ldb_request(sam_ctx, req);
+
+                       if (ret == LDB_SUCCESS) {
+                               ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+                       }
+
+                       talloc_free(req);
+
+                       if (ret != LDB_SUCCESS) {
+                               DEBUG(2, ("DsCrackNameOneFilter phantom root search failed: %s", 
+                                         ldb_errstring(sam_ctx)));
+                               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                               return WERR_OK;
+                       }
+                       ldb_ret = res->count;
+                       result_res = res->msgs;
+               }
        } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
                ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
                                          result_attrs);
-       } else {
-               name_dn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
+       } else if (domain_res) {
+               name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
                ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
                                          result_attrs);
+       } else {
+               /* Can't happen */
+               DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not availible: This can't happen..."));
+               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+               return WERR_OK;
        }
 
        switch (ldb_ret) {
        case 1:
+               result = result_res[0];
                break;
        case 0:
                switch (format_offered) {
@@ -654,7 +895,7 @@ static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_
                                                   smb_krb5_context, 
                                                   format_flags, format_offered, format_desired,
                                                   name, info1);
-                       
+
                case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
                        return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context, 
                                              format_flags, format_offered, format_desired,
@@ -663,24 +904,59 @@ static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_
                info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                return WERR_OK;
        case -1:
+               DEBUG(2, ("DsCrackNameOneFilter result search failed: %s", ldb_errstring(sam_ctx)));
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
        default:
-               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
-               return WERR_OK;
+               switch (format_offered) {
+               case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
+               case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
+               {
+                       const char *canonical_name = NULL; /* Not required, but we get warnings... */
+                       /* We may need to manually filter further */
+                       for (i = 0; i < ldb_ret; i++) {
+                               switch (format_offered) {
+                               case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
+                                       canonical_name = ldb_dn_canonical_string(mem_ctx, result_res[i]->dn);
+                                       break;
+                               case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
+                                       canonical_name = ldb_dn_canonical_ex_string(mem_ctx, result_res[i]->dn);
+                                       break;
+                               }
+                               if (strcasecmp_m(canonical_name, name) == 0) {
+                                       result = result_res[i];
+                                       break;
+                               }
+                       }
+                       if (!result) {
+                               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+                               return WERR_OK;
+                       }
+               }
+               default:
+                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+                       return WERR_OK;
+               }
+       }
+
+       info1->dns_domain_name = ldb_dn_canonical_string(mem_ctx, result->dn);
+       W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
+       p = strchr(info1->dns_domain_name, '/');
+       if (p) {
+               p[0] = '\0';
        }
 
-       /* here we can use result_res[0] and domain_res[0] */
+       /* here we can use result and domain_res[0] */
        switch (format_desired) {
        case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
-               info1->result_name      = ldb_dn_linearize(mem_ctx, result_res[0]->dn);
-               WERR_TALLOC_CHECK(info1->result_name);
+               info1->result_name      = ldb_dn_alloc_linearized(mem_ctx, result->dn);
+               W_ERROR_HAVE_NO_MEMORY(info1->result_name);
 
                info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
                return WERR_OK;
        }
        case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
-               info1->result_name      = samdb_result_string(result_res[0], "canonicalName", NULL);
+               info1->result_name      = samdb_result_string(result, "canonicalName", NULL);
                info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
                return WERR_OK;
        }
@@ -689,76 +965,127 @@ static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_
                return DsCrackNameOneSyntactical(mem_ctx, 
                                                 DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
                                                 DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
-                                                result_res[0]->dn, name, info1);
+                                                result->dn, name, info1);
        }
        case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
-               const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result_res[0], "objectSid");
+
+               const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
                const char *_acc = "", *_dom = "";
-               
-               if (!sid || (sid->num_auths < 4) || (sid->num_auths > 5)) {
-                       info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
-                       return WERR_OK;
-               }
 
-               if (sid->num_auths == 4) {
-                       ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
-                                              "(ncName=%s)", ldb_dn_linearize(mem_ctx, result_res[0]->dn));
-                       if (ldb_ret != 1) {
-                               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
-                               return WERR_OK;
-                       }
-                       _dom = samdb_result_string(domain_res[0], "nETBIOSName", NULL);
-                       WERR_TALLOC_CHECK(_dom);
-               
-               } else if (sid->num_auths == 5) {
-                       const char *attrs[] = { NULL };
-                       struct ldb_message **domain_res2;
-                       struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
-                       if (!dom_sid) {
+               if (samdb_find_attribute(sam_ctx, result, "objectClass", "domain")) {
+
+                       ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
+                                                    partitions_basedn,
+                                                    LDB_SCOPE_ONELEVEL,
+                                                    domain_attrs,
+                                                    "(ncName=%s)", ldb_dn_get_linearized(result->dn));
+
+                       if (ldb_ret != LDB_SUCCESS) {
+                               DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s", ldb_errstring(sam_ctx)));
+                               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                                return WERR_OK;
                        }
-                       dom_sid->num_auths--;
-                       ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, attrs,
-                                              "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
-                       if (ldb_ret != 1) {
+
+                       switch (domain_res->count) {
+                       case 1:
+                               break;
+                       case 0:
                                info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                                return WERR_OK;
+                       default:
+                               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+                               return WERR_OK;
                        }
-                       ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res2, domain_attrs,
-                                              "(ncName=%s)", ldb_dn_linearize(mem_ctx, domain_res[0]->dn));
-                       if (ldb_ret != 1) {
-                               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+                       _dom = samdb_result_string(domain_res->msgs[0], "nETBIOSName", NULL);
+                       W_ERROR_HAVE_NO_MEMORY(_dom);
+               } else {
+                       _acc = samdb_result_string(result, "sAMAccountName", NULL);
+                       if (!_acc) {
+                               info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
                                return WERR_OK;
                        }
-                       
-                       _dom = samdb_result_string(domain_res2[0], "nETBIOSName", NULL);
-                       WERR_TALLOC_CHECK(_dom);
+                       if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx, SID_BUILTIN), sid)) {
+                               _dom = "BUILTIN";
+                       } else {
+                               const char *attrs[] = { NULL };
+                               struct ldb_result *domain_res2;
+                               struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
+                               if (!dom_sid) {
+                                       return WERR_OK;
+                               }
+                               dom_sid->num_auths--;
+                               ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
+                                                            NULL,
+                                                            LDB_SCOPE_BASE,
+                                                            attrs,
+                                                            "(&(objectSid=%s)(objectClass=domain))", 
+                                                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
+
+                               if (ldb_ret != LDB_SUCCESS) {
+                                       DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s", ldb_errstring(sam_ctx)));
+                                       info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                                       return WERR_OK;
+                               }
 
-                       _acc = samdb_result_string(result_res[0], "sAMAccountName", NULL);
-                       WERR_TALLOC_CHECK(_acc);
+                               switch (domain_res->count) {
+                               case 1:
+                                       break;
+                               case 0:
+                                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+                                       return WERR_OK;
+                               default:
+                                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+                                       return WERR_OK;
+                               }
+
+                               ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res2,
+                                                            partitions_basedn,
+                                                            LDB_SCOPE_ONELEVEL,
+                                                            domain_attrs,
+                                                            "(ncName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
+
+                               if (ldb_ret != LDB_SUCCESS) {
+                                       DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s", ldb_errstring(sam_ctx)));
+                                       info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+                                       return WERR_OK;
+                               }
+
+                               switch (domain_res2->count) {
+                               case 1:
+                                       break;
+                               case 0:
+                                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+                                       return WERR_OK;
+                               default:
+                                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+                                       return WERR_OK;
+                               }
+                               _dom = samdb_result_string(domain_res2->msgs[0], "nETBIOSName", NULL);
+                               W_ERROR_HAVE_NO_MEMORY(_dom);
+                       }
                }
 
                info1->result_name      = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
-               WERR_TALLOC_CHECK(info1->result_name);
-               
+               W_ERROR_HAVE_NO_MEMORY(info1->result_name);
+
                info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
                return WERR_OK;
        }
        case DRSUAPI_DS_NAME_FORMAT_GUID: {
                struct GUID guid;
-               
-               guid = samdb_result_guid(result_res[0], "objectGUID");
-               
+
+               guid = samdb_result_guid(result, "objectGUID");
+
                info1->result_name      = GUID_string2(mem_ctx, &guid);
-               WERR_TALLOC_CHECK(info1->result_name);
-               
+               W_ERROR_HAVE_NO_MEMORY(info1->result_name);
+
                info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
                return WERR_OK;
        }
        case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
-               info1->result_name      = samdb_result_string(result_res[0], "displayName", NULL);
+               info1->result_name      = samdb_result_string(result, "displayName", NULL);
                if (!info1->result_name) {
-                       info1->result_name      = samdb_result_string(result_res[0], "sAMAccountName", NULL);
+                       info1->result_name      = samdb_result_string(result, "sAMAccountName", NULL);
                } 
                if (!info1->result_name) {
                        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
@@ -767,11 +1094,19 @@ static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_
                }
                return WERR_OK;
        }
+       case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
+               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+               return WERR_OK;
+       }
+       case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN: 
+       case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
+               info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+               return WERR_OK;
+       }
        default:
+               info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
                return WERR_OK;
        }
-       
-       return WERR_INVALID_PARAM;
 }
 
 /* Given a user Principal Name (such as foo@bar.com),
@@ -805,9 +1140,9 @@ NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx,
        default:
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
-       *user_dn = ldb_dn_explode(mem_ctx, info1.result_name);
-       
+
+       *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
+
        if (domain_dn) {
                werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
                                          DRSUAPI_DS_NAME_FORMAT_CANONICAL,
@@ -829,12 +1164,11 @@ NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx,
                default:
                        return NT_STATUS_UNSUCCESSFUL;
                }
-               
-               *domain_dn = ldb_dn_explode(mem_ctx, info1.result_name);
+
+               *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
        }
 
        return NT_STATUS_OK;
-       
 }
 
 /* Given a Service Principal Name (such as host/foo.bar.com@BAR.COM),
@@ -868,9 +1202,9 @@ NTSTATUS crack_service_principal_name(struct ldb_context *sam_ctx,
        default:
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
-       *user_dn = ldb_dn_explode(mem_ctx, info1.result_name);
-       
+
+       *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
+
        if (domain_dn) {
                werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
                                          DRSUAPI_DS_NAME_FORMAT_CANONICAL,
@@ -892,17 +1226,19 @@ NTSTATUS crack_service_principal_name(struct ldb_context *sam_ctx,
                default:
                        return NT_STATUS_UNSUCCESSFUL;
                }
-               
-               *domain_dn = ldb_dn_explode(mem_ctx, info1.result_name);
+
+               *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
        }
 
        return NT_STATUS_OK;
-       
 }
 
-NTSTATUS crack_dn_to_nt4_name(TALLOC_CTX *mem_ctx, 
-                             const char *dn, 
-                             const char **nt4_domain, const char **nt4_account)
+NTSTATUS crack_name_to_nt4_name(TALLOC_CTX *mem_ctx, 
+                               struct tevent_context *ev_ctx, 
+                               struct loadparm_context *lp_ctx,
+                               uint32_t format_offered,
+                               const char *name, 
+                               const char **nt4_domain, const char **nt4_account)
 {
        WERROR werr;
        struct drsuapi_DsNameInfo1 info1;
@@ -910,21 +1246,21 @@ NTSTATUS crack_dn_to_nt4_name(TALLOC_CTX *mem_ctx,
        char *p;
 
        /* Handle anonymous bind */
-       if (!dn || !*dn) {
+       if (!name || !*name) {
                *nt4_domain = "";
                *nt4_account = "";
                return NT_STATUS_OK;
        }
 
-       ldb = samdb_connect(mem_ctx, system_session(mem_ctx));
+       ldb = samdb_connect(mem_ctx, ev_ctx, lp_ctx, system_session(mem_ctx, lp_ctx));
        if (ldb == NULL) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
        werr = DsCrackNameOneName(ldb, mem_ctx, 0,
-                                 DRSUAPI_DS_NAME_FORMAT_FQDN_1779
+                                 format_offered
                                  DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
-                                 dn,
+                                 name,
                                  &info1);
        if (!W_ERROR_IS_OK(werr)) {
                return werror_to_ntstatus(werr);
@@ -940,23 +1276,53 @@ NTSTATUS crack_dn_to_nt4_name(TALLOC_CTX *mem_ctx,
        default:
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
+
        *nt4_domain = talloc_strdup(mem_ctx, info1.result_name);
-       
+       if (*nt4_domain == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        p = strchr(*nt4_domain, '\\');
        if (!p) {
                return NT_STATUS_INVALID_PARAMETER;
        }
        p[0] = '\0';
-       
-       if (p[1]) {
-               *nt4_account = talloc_strdup(mem_ctx, &p[1]);
-       }
 
-       if (!*nt4_account || !*nt4_domain) {
+       *nt4_account = talloc_strdup(mem_ctx, &p[1]);
+       if (*nt4_account == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
        return NT_STATUS_OK;
-       
+}
+
+NTSTATUS crack_auto_name_to_nt4_name(TALLOC_CTX *mem_ctx,
+                                    struct tevent_context *ev_ctx, 
+                                    struct loadparm_context *lp_ctx,
+                                    const char *name,
+                                    const char **nt4_domain,
+                                    const char **nt4_account)
+{
+       uint32_t format_offered = DRSUAPI_DS_NAME_FORMAT_UNKNOWN;
+
+       /* Handle anonymous bind */
+       if (!name || !*name) {
+               *nt4_domain = "";
+               *nt4_account = "";
+               return NT_STATUS_OK;
+       }
+
+       if (strchr_m(name, '=')) {
+               format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+       } else if (strchr_m(name, '@')) {
+               format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL;
+       } else if (strchr_m(name, '\\')) {
+               format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+       } else if (strchr_m(name, '/')) {
+               format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL;
+       } else {
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       return crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, format_offered, name, nt4_domain, nt4_account);
 }