summaryrefslogtreecommitdiff
path: root/source4/dsdb
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-10-23 22:20:42 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:45:11 -0500
commitdb4b95827e4e6d13577513946bff4f956c849756 (patch)
treed87779f6511101d981bf958a90bdaddca92f8744 /source4/dsdb
parent28a3bc645b49ea6e997b3576ba7a8ba55e7caa9c (diff)
downloadsamba-db4b95827e4e6d13577513946bff4f956c849756.tar.gz
samba-db4b95827e4e6d13577513946bff4f956c849756.tar.bz2
samba-db4b95827e4e6d13577513946bff4f956c849756.zip
r11270: Move the core CrackNames code from rpc_server/drsuapi to dsdb/samdb.
I'm sure this will not be the final resting place, but it will do for now. Use the cracknames code in auth/ for creating a server_info given a principal name only (should avoid assumtions about spliting a user@realm principal). Andrew Bartlett (This used to be commit c9d5d8e45dd7b7c99b6cf35b087bc18012f31222)
Diffstat (limited to 'source4/dsdb')
-rw-r--r--source4/dsdb/config.mk1
-rw-r--r--source4/dsdb/samdb/cracknames.c772
2 files changed, 773 insertions, 0 deletions
diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk
index 59178c3cda..065eb65afa 100644
--- a/source4/dsdb/config.mk
+++ b/source4/dsdb/config.mk
@@ -48,6 +48,7 @@ INIT_OBJ_FILES = \
samdb/samdb.o
ADD_OBJ_FILES = \
samdb/samdb_privilege.o \
+ samdb/cracknames.o \
common/flag_mapping.o
REQUIRED_SUBSYSTEMS = \
DCERPC_COMMON
diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c
new file mode 100644
index 0000000000..6b04d05ad8
--- /dev/null
+++ b/source4/dsdb/samdb/cracknames.c
@@ -0,0 +1,772 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the drsuapi pipe
+ DsCrackNames()
+
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "rpc_server/dcerpc_server.h"
+#include "rpc_server/common/common.h"
+#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
+#include "lib/ldb/include/ldb.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+
+static WERROR DsCrackNameOneFilter(struct 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,
+ 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 drsuapi_DsNameInfo1 *info1);
+
+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)
+{
+ int i;
+ int count;
+ struct ldb_message **msg;
+ 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);
+ const char *directory_attrs[] = {
+ "sPNMappings",
+ NULL
+ };
+
+ count = ldb_search(ldb_ctx, service_dn, LDB_SCOPE_BASE, "(objectClass=nTDSService)",
+ directory_attrs, &msg);
+ talloc_steal(mem_ctx, msg);
+
+ if (count < 1) {
+ DEBUG(1, ("ldb_search: dn: %s not found: %d", service_dn_str, count));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ } else if (count > 1) {
+ DEBUG(1, ("ldb_search: dn: %s found %d times!", service_dn_str, count));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+
+ spnmappings = ldb_msg_find_element(msg[0], "sPNMappings");
+ if (!spnmappings || spnmappings->num_values == 0) {
+ DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute", service_dn_str));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+
+ for (i = 0; i < spnmappings->num_values; i++) {
+ char *mapping, *p, *str;
+ mapping = talloc_strdup(mem_ctx,
+ (const char *)spnmappings->values[i].data);
+ if (!mapping) {
+ DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+
+ /* C string manipulation sucks */
+
+ p = strchr(mapping, '=');
+ if (!p) {
+ DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n",
+ service_dn_str, mapping));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ }
+ p[0] = '\0';
+ p++;
+ do {
+ str = p;
+ p = strchr(p, ',');
+ if (p) {
+ p[0] = '\0';
+ p++;
+ }
+ if (strcasecmp(str, alias_from) == 0) {
+ *alias_to = mapping;
+ return DRSUAPI_DS_NAME_STATUS_OK;
+ }
+ } while (p);
+ }
+ DEBUG(1, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
+ return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+}
+
+static WERROR DsCrackNameSPNAlias(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 char *name, struct drsuapi_DsNameInfo1 *info1)
+{
+ WERROR wret;
+ krb5_error_code ret;
+ krb5_principal principal;
+ const char *service;
+ char *new_service;
+ char *new_princ;
+ enum drsuapi_DsNameStatus namestatus;
+
+ /* parse principal */
+ ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context,
+ name, &principal);
+ if (ret) {
+ DEBUG(2, ("Could not parse principal: %s: %s",
+ name, smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+ return WERR_NOMEM;
+ }
+
+ /* grab cifs/, http/ etc */
+
+ /* 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];
+
+ /* 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;
+ return WERR_OK;
+ }
+
+ if (ret != 0) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ }
+
+ /* ooh, very nasty playing around in the Principal... */
+ free(principal->name.name_string.val[0]);
+ principal->name.name_string.val[0] = strdup(new_service);
+ if (!principal->name.name_string.val[0]) {
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ return WERR_NOMEM;
+ }
+
+ /* reform principal */
+ ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &new_princ);
+
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+
+ if (ret) {
+ return WERR_NOMEM;
+ }
+
+ wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
+ new_princ, info1);
+ free(new_princ);
+ return wret;
+}
+
+static WERROR DsCrackNameUPN(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 char *name, struct drsuapi_DsNameInfo1 *info1)
+{
+ WERROR status;
+ const char *domain_filter = NULL;
+ const char *result_filter = NULL;
+ krb5_error_code ret;
+ krb5_principal principal;
+ char **realm;
+ char *unparsed_name_short;
+
+ /* Prevent recursion */
+ if (!name) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ ret = krb5_parse_name_mustrealm(smb_krb5_context->krb5_context, name, &principal);
+ if (ret) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ domain_filter = NULL;
+ realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
+ domain_filter = talloc_asprintf(mem_ctx,
+ "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
+ *realm, *realm);
+ ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+
+ if (ret) {
+ free(unparsed_name_short);
+ return WERR_NOMEM;
+ }
+
+ /* This may need to be extended for more userPrincipalName variations */
+ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))",
+ unparsed_name_short);
+ if (!result_filter || !domain_filter) {
+ free(unparsed_name_short);
+ return WERR_NOMEM;
+ }
+ status = DsCrackNameOneFilter(sam_ctx, mem_ctx,
+ smb_krb5_context,
+ format_flags, format_offered, format_desired,
+ NULL, unparsed_name_short, domain_filter, result_filter,
+ info1);
+ free(unparsed_name_short);
+ return status;
+}
+
+WERROR DsCrackNameOneName(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)
+{
+ krb5_error_code ret;
+ const char *domain_filter = NULL;
+ 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;
+ }
+
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ info1->dns_domain_name = NULL;
+ info1->result_name = NULL;
+
+ if (!name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ /* TODO: - fill the correct names in all cases!
+ * - handle format_flags
+ */
+
+ /* here we need to set the domain_filter and/or the result_filter */
+ switch (format_offered) {
+ case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
+ char *str;
+
+ str = talloc_strdup(mem_ctx, name);
+ WERR_TALLOC_CHECK(str);
+
+ if (strlen(str) == 0 || str[strlen(str)-1] != '/') {
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ }
+
+ str[strlen(str)-1] = '\0';
+
+ domain_filter = talloc_asprintf(mem_ctx,
+ "(&(&(&(dnsRoot=%s)(objectclass=crossRef)))(nETBIOSName=*)(ncName=*))",
+ str);
+ WERR_TALLOC_CHECK(domain_filter);
+
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
+ char *p;
+ char *domain;
+ const char *account = NULL;
+
+ domain = talloc_strdup(mem_ctx, name);
+ WERR_TALLOC_CHECK(domain);
+
+ p = strchr(domain, '\\');
+ if (!p) {
+ /* invalid input format */
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ p[0] = '\0';
+
+ if (p[1]) {
+ account = &p[1];
+ }
+
+ domain_filter = talloc_asprintf(mem_ctx,
+ "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
+ domain);
+ WERR_TALLOC_CHECK(domain_filter);
+ if (account) {
+ result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
+ account);
+ WERR_TALLOC_CHECK(result_filter);
+ }
+
+ talloc_free(domain);
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
+ name_dn = ldb_dn_explode(mem_ctx, name);
+ domain_filter = NULL;
+ if (!name_dn) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_GUID: {
+ struct GUID guid;
+ char *ldap_guid;
+ NTSTATUS nt_status;
+ domain_filter = NULL;
+
+ nt_status = GUID_from_string(name, &guid);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ 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);
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
+ domain_filter = NULL;
+
+ result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
+ name, name);
+ WERR_TALLOC_CHECK(result_filter);
+ break;
+ }
+
+ case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
+ struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
+ char *ldap_sid;
+
+ domain_filter = NULL;
+ if (!sid) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+ ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx,
+ sid);
+ if (!ldap_sid) {
+ return WERR_NOMEM;
+ }
+ result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
+ ldap_sid);
+ WERR_TALLOC_CHECK(result_filter);
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
+ krb5_principal principal;
+ char *unparsed_name;
+ ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
+ if (ret) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ domain_filter = NULL;
+
+ ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
+ if (ret) {
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ return WERR_NOMEM;
+ }
+
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))",
+ unparsed_name);
+
+ free(unparsed_name);
+ WERR_TALLOC_CHECK(result_filter);
+ break;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
+ krb5_principal principal;
+ char *unparsed_name_short;
+ ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, name, &principal);
+ if (ret || (principal->name.name_string.len < 2)) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ domain_filter = NULL;
+
+ ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+ krb5_free_principal(smb_krb5_context->krb5_context, principal);
+ if (ret) {
+ return WERR_NOMEM;
+ }
+
+ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(servicePrincipalName=%s))",
+ unparsed_name_short);
+ free(unparsed_name_short);
+ WERR_TALLOC_CHECK(result_filter);
+
+ break;
+ }
+ default: {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ }
+
+ }
+
+ if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
+ 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,
+ name_dn, name,
+ domain_filter, result_filter,
+ 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 drsuapi_DsNameInfo1 *info1)
+{
+ char *cracked;
+ if (format_offered != DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
+ return WERR_OK;
+ }
+
+ switch (format_desired) {
+ case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
+ cracked = ldb_dn_canonical_string(mem_ctx, name_dn);
+ break;
+ case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
+ cracked = ldb_dn_canonical_ex_string(mem_ctx, name_dn);
+ break;
+ default:
+ info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
+ return WERR_OK;
+ }
+ info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ info1->result_name = cracked;
+ if (!cracked) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+
+}
+
+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,
+ const char *domain_filter, const char *result_filter,
+ struct drsuapi_DsNameInfo1 *info1)
+{
+ int ldb_ret;
+ struct ldb_message **domain_res = NULL;
+ const char * const *domain_attrs;
+ const char * const *result_attrs;
+ struct ldb_message **result_res = NULL;
+ const struct ldb_dn *result_basedn;
+
+ /* here we need to set the attrs lists for domain and result lookups */
+ switch (format_desired) {
+ 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;
+ 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;
+ 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;
+ 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;
+ 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;
+ break;
+ }
+ default:
+ return WERR_OK;
+ }
+
+ if (domain_filter) {
+ /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
+ ldb_ret = gendb_search(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)));
+ }
+
+ switch (ldb_ret) {
+ case 1:
+ break;
+ case 0:
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ case -1:
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ default:
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+ return WERR_OK;
+ }
+
+ info1->dns_domain_name = samdb_result_string(domain_res[0], "dnsRoot", NULL);
+ 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);
+ } 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);
+ ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
+ result_attrs);
+ }
+
+ switch (ldb_ret) {
+ case 1:
+ break;
+ case 0:
+ switch (format_offered) {
+ case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
+ return DsCrackNameSPNAlias(sam_ctx, mem_ctx,
+ 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,
+ name, info1);
+ }
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ return WERR_OK;
+ case -1:
+ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
+ return WERR_OK;
+ default:
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+ return WERR_OK;
+ }
+
+ /* here we can use result_res[0] and domain_res[0] */
+ switch (format_desired) {
+ case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
+ info1->result_name = ldb_dn_linearize(mem_ctx, result_res[0]->dn);
+ WERR_TALLOC_CHECK(info1->result_name);
+
+ 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->status = DRSUAPI_DS_NAME_STATUS_OK;
+ return WERR_OK;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
+ /* Not in the virtual ldb attribute */
+ return DsCrackNameOneSyntactical(mem_ctx,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+ result_res[0]->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 char *_acc = "", *_dom = "";
+
+ if ((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) {
+ 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) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ 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;
+ return WERR_OK;
+ }
+
+ _dom = samdb_result_string(domain_res2[0], "nETBIOSName", NULL);
+ WERR_TALLOC_CHECK(_dom);
+
+ _acc = samdb_result_string(result_res[0], "sAMAccountName", NULL);
+ WERR_TALLOC_CHECK(_acc);
+ }
+
+ info1->result_name = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
+ WERR_TALLOC_CHECK(info1->result_name);
+
+ info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ return WERR_OK;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_GUID: {
+ struct GUID guid;
+
+ guid = samdb_result_guid(result_res[0], "objectGUID");
+
+ info1->result_name = GUID_string2(mem_ctx, &guid);
+ WERR_TALLOC_CHECK(info1->result_name);
+
+ info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ return WERR_OK;
+ }
+ case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
+ info1->result_name = samdb_result_string(result_res[0], "displayName", NULL);
+ if (!info1->result_name) {
+ info1->result_name = samdb_result_string(result_res[0], "sAMAccountName", NULL);
+ }
+ if (!info1->result_name) {
+ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
+ } else {
+ info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+ }
+ return WERR_OK;
+ }
+ default:
+ return WERR_OK;
+ }
+
+ return WERR_INVALID_PARAM;
+}
+
+NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *user_principal_name,
+ struct ldb_dn **user_dn,
+ struct ldb_dn **domain_dn)
+{
+ WERROR werr;
+ struct drsuapi_DsNameInfo1 info1;
+ werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
+ DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ user_principal_name,
+ &info1);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werror_to_ntstatus(werr);
+ }
+ switch (info1.status) {
+ case DRSUAPI_DS_NAME_STATUS_OK:
+ break;
+ case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
+ case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
+ case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
+ return NT_STATUS_NO_SUCH_USER;
+ case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
+ default:
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ *user_dn = ldb_dn_explode(mem_ctx, info1.result_name);
+
+ if (domain_dn) {
+ werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ talloc_asprintf(mem_ctx, "%s/",
+ info1.dns_domain_name),
+ &info1);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werror_to_ntstatus(werr);
+ }
+ switch (info1.status) {
+ case DRSUAPI_DS_NAME_STATUS_OK:
+ break;
+ case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
+ case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
+ case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
+ return NT_STATUS_NO_SUCH_USER;
+ case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
+ default:
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ *domain_dn = ldb_dn_explode(mem_ctx, info1.result_name);
+ }
+
+ return NT_STATUS_OK;
+
+}