2 Unix SMB/CIFS implementation.
4 endpoint server for the drsuapi pipe
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "librpc/gen_ndr/drsuapi.h"
26 #include "lib/events/events.h"
27 #include "rpc_server/common/common.h"
29 #include <ldb_errors.h>
30 #include "auth/kerberos/kerberos.h"
31 #include "libcli/ldap/ldap_ndr.h"
32 #include "libcli/security/security.h"
33 #include "auth/auth.h"
34 #include "../lib/util/util_ldb.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "dsdb/common/util.h"
37 #include "param/param.h"
39 static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
40 struct smb_krb5_context *smb_krb5_context,
41 uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
42 enum drsuapi_DsNameFormat format_desired,
43 struct ldb_dn *name_dn, const char *name,
44 const char *domain_filter, const char *result_filter,
45 struct drsuapi_DsNameInfo1 *info1);
46 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
47 enum drsuapi_DsNameFormat format_offered,
48 enum drsuapi_DsNameFormat format_desired,
49 struct ldb_dn *name_dn, const char *name,
50 struct drsuapi_DsNameInfo1 *info1);
52 static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context,
54 struct drsuapi_DsNameInfo1 *info1)
57 krb5_principal principal;
58 /* perhaps it's a principal with a realm, so return the right 'domain only' response */
60 ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
61 KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
63 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
67 /* This isn't an allocation assignemnt, so it is free'ed with the krb5_free_principal */
68 realm = smb_krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);
70 info1->dns_domain_name = talloc_strdup(mem_ctx, realm);
71 krb5_free_principal(smb_krb5_context->krb5_context, principal);
73 W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
75 info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
79 static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx,
81 const char *alias_from,
86 struct ldb_result *res;
87 struct ldb_message_element *spnmappings;
89 struct ldb_dn *service_dn;
92 const char *directory_attrs[] = {
97 tmp_ctx = talloc_new(mem_ctx);
99 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
102 service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services");
103 if ( ! ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb_ctx))) {
104 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
106 service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn);
107 if ( ! service_dn_str) {
108 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
111 ret = ldb_search(ldb_ctx, tmp_ctx, &res, service_dn, LDB_SCOPE_BASE,
112 directory_attrs, "(objectClass=nTDSService)");
114 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
115 DEBUG(1, ("ldb_search: dn: %s not found: %s\n", service_dn_str, ldb_errstring(ldb_ctx)));
116 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
117 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
118 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
119 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
120 } else if (res->count != 1) {
122 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
123 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
126 spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings");
127 if (!spnmappings || spnmappings->num_values == 0) {
128 DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute\n", service_dn_str));
129 talloc_free(tmp_ctx);
130 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
133 for (i = 0; i < spnmappings->num_values; i++) {
134 char *mapping, *p, *str;
135 mapping = talloc_strdup(tmp_ctx,
136 (const char *)spnmappings->values[i].data);
138 DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));
139 talloc_free(tmp_ctx);
140 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
143 /* C string manipulation sucks */
145 p = strchr(mapping, '=');
147 DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n",
148 service_dn_str, mapping));
149 talloc_free(tmp_ctx);
150 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
161 if (strcasecmp(str, alias_from) == 0) {
163 talloc_steal(mem_ctx, mapping);
164 talloc_free(tmp_ctx);
165 return DRSUAPI_DS_NAME_STATUS_OK;
169 DEBUG(4, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
170 talloc_free(tmp_ctx);
171 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
174 /* When cracking a ServicePrincipalName, many services may be served
175 * by the host/ servicePrincipalName. The incoming query is for cifs/
176 * but we translate it here, and search on host/. This is done after
177 * the cifs/ entry has been searched for, making this a fallback */
179 static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
180 struct smb_krb5_context *smb_krb5_context,
181 uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
182 enum drsuapi_DsNameFormat format_desired,
183 const char *name, struct drsuapi_DsNameInfo1 *info1)
187 krb5_principal principal;
188 krb5_data *component;
189 const char *service, *dns_name;
192 enum drsuapi_DsNameStatus namestatus;
194 /* parse principal */
195 ret = krb5_parse_name_flags(smb_krb5_context->krb5_context,
196 name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
198 DEBUG(2, ("Could not parse principal: %s: %s\n",
199 name, smb_get_krb5_error_message(smb_krb5_context->krb5_context,
204 /* grab cifs/, http/ etc */
206 /* This is checked for in callers, but be safe */
207 if (krb5_princ_size(smb_krb5_context->krb5_context, principal) < 2) {
208 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
209 krb5_free_principal(smb_krb5_context->krb5_context, principal);
212 component = krb5_princ_component(smb_krb5_context->krb5_context,
214 service = (const char *)component->data;
215 component = krb5_princ_component(smb_krb5_context->krb5_context,
217 dns_name = (const char *)component->data;
220 namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context,
222 service, &new_service);
224 if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
226 info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
227 info1->dns_domain_name = talloc_strdup(mem_ctx, dns_name);
228 if (!info1->dns_domain_name) {
231 krb5_free_principal(smb_krb5_context->krb5_context, principal);
233 } else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
234 info1->status = namestatus;
235 krb5_free_principal(smb_krb5_context->krb5_context, principal);
239 /* reform principal */
240 new_princ = talloc_asprintf(mem_ctx, "%s/%s", new_service, dns_name);
242 krb5_free_principal(smb_krb5_context->krb5_context, principal);
246 wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
248 talloc_free(new_princ);
249 if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) {
250 info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
251 info1->dns_domain_name = talloc_strdup(mem_ctx, dns_name);
252 if (!info1->dns_domain_name) {
256 krb5_free_principal(smb_krb5_context->krb5_context, principal);
260 /* Subcase of CrackNames, for the userPrincipalName */
262 static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
263 struct smb_krb5_context *smb_krb5_context,
264 uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
265 enum drsuapi_DsNameFormat format_desired,
266 const char *name, struct drsuapi_DsNameInfo1 *info1)
270 const char *domain_filter = NULL;
271 const char *result_filter = NULL;
273 krb5_principal principal;
275 char *unparsed_name_short;
276 const char *domain_attrs[] = { NULL };
277 struct ldb_result *domain_res = NULL;
279 /* Prevent recursion */
281 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
285 ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
286 KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
288 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
292 realm = smb_krb5_principal_get_realm(smb_krb5_context->krb5_context,
295 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
296 samdb_partitions_dn(sam_ctx, mem_ctx),
299 "(&(objectClass=crossRef)(|(dnsRoot=%s)(netbiosName=%s))(systemFlags:%s:=%u))",
300 ldb_binary_encode_string(mem_ctx, realm),
301 ldb_binary_encode_string(mem_ctx, realm),
302 LDB_OID_COMPARATOR_AND,
303 SYSTEM_FLAG_CR_NTDS_DOMAIN);
305 if (ldb_ret != LDB_SUCCESS) {
306 DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
307 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
308 krb5_free_principal(smb_krb5_context->krb5_context, principal);
312 switch (domain_res->count) {
316 krb5_free_principal(smb_krb5_context->krb5_context, principal);
317 return dns_domain_from_principal(mem_ctx, smb_krb5_context,
320 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
321 krb5_free_principal(smb_krb5_context->krb5_context, principal);
325 ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
326 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
327 krb5_free_principal(smb_krb5_context->krb5_context, principal);
330 free(unparsed_name_short);
334 /* This may need to be extended for more userPrincipalName variations */
335 result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))",
336 ldb_binary_encode_string(mem_ctx, unparsed_name_short));
338 domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
340 if (!result_filter || !domain_filter) {
341 free(unparsed_name_short);
344 status = DsCrackNameOneFilter(sam_ctx, mem_ctx,
346 format_flags, format_offered, format_desired,
347 NULL, unparsed_name_short, domain_filter, result_filter,
349 free(unparsed_name_short);
354 /* Crack a single 'name', from format_offered into format_desired, returning the result in info1 */
356 WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
357 uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
358 enum drsuapi_DsNameFormat format_desired,
359 const char *name, struct drsuapi_DsNameInfo1 *info1)
362 const char *domain_filter = NULL;
363 const char *result_filter = NULL;
364 struct ldb_dn *name_dn = NULL;
366 struct smb_krb5_context *smb_krb5_context = NULL;
368 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
369 info1->dns_domain_name = NULL;
370 info1->result_name = NULL;
373 return WERR_INVALID_PARAM;
376 /* TODO: - fill the correct names in all cases!
377 * - handle format_flags
380 /* here we need to set the domain_filter and/or the result_filter */
381 switch (format_offered) {
382 case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
385 enum drsuapi_DsNameFormat formats[] = {
386 DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
387 DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL,
388 DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY,
389 DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
390 DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
391 DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
394 for (i=0; i < ARRAY_SIZE(formats); i++) {
395 werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
396 if (!W_ERROR_IS_OK(werr)) {
399 if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
406 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
407 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
409 char *str, *s, *account;
411 if (strlen(name) == 0) {
412 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
416 str = talloc_strdup(mem_ctx, name);
417 W_ERROR_HAVE_NO_MEMORY(str);
419 if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
420 /* Look backwards for the \n, and replace it with / */
421 s = strrchr(str, '\n');
423 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
429 s = strchr(str, '/');
431 /* there must be at least one / */
432 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
439 domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(dnsRoot=%s)(systemFlags:%s:=%u))",
440 ldb_binary_encode_string(mem_ctx, str),
441 LDB_OID_COMPARATOR_AND,
442 SYSTEM_FLAG_CR_NTDS_DOMAIN);
443 W_ERROR_HAVE_NO_MEMORY(domain_filter);
445 /* There may not be anything after the domain component (search for the domain itself) */
448 account = strrchr(s, '/');
454 account = ldb_binary_encode_string(mem_ctx, account);
455 W_ERROR_HAVE_NO_MEMORY(account);
456 result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
458 W_ERROR_HAVE_NO_MEMORY(result_filter);
462 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
465 const char *account = NULL;
467 domain = talloc_strdup(mem_ctx, name);
468 W_ERROR_HAVE_NO_MEMORY(domain);
470 p = strchr(domain, '\\');
472 /* invalid input format */
473 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
482 domain_filter = talloc_asprintf(mem_ctx,
483 "(&(objectClass=crossRef)(|(dnsRoot=%s)(netbiosName=%s))(systemFlags:%s:=%u))",
484 ldb_binary_encode_string(mem_ctx, domain),
485 ldb_binary_encode_string(mem_ctx, domain),
486 LDB_OID_COMPARATOR_AND,
487 SYSTEM_FLAG_CR_NTDS_DOMAIN);
488 W_ERROR_HAVE_NO_MEMORY(domain_filter);
490 result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
491 ldb_binary_encode_string(mem_ctx, account));
492 W_ERROR_HAVE_NO_MEMORY(result_filter);
499 /* A LDAP DN as a string */
500 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
501 domain_filter = NULL;
502 name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
503 if (! ldb_dn_validate(name_dn)) {
504 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
510 /* A GUID as a string */
511 case DRSUAPI_DS_NAME_FORMAT_GUID: {
515 domain_filter = NULL;
517 nt_status = GUID_from_string(name, &guid);
518 if (!NT_STATUS_IS_OK(nt_status)) {
519 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
523 ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
527 result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
529 W_ERROR_HAVE_NO_MEMORY(result_filter);
532 case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
533 domain_filter = NULL;
535 result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
536 ldb_binary_encode_string(mem_ctx, name),
537 ldb_binary_encode_string(mem_ctx, name));
538 W_ERROR_HAVE_NO_MEMORY(result_filter);
542 /* A S-1234-5678 style string */
543 case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
544 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
547 domain_filter = NULL;
549 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
552 ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx,
557 result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
559 W_ERROR_HAVE_NO_MEMORY(result_filter);
562 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
563 krb5_principal principal;
566 ret = smb_krb5_init_context(mem_ctx,
567 ldb_get_event_context(sam_ctx),
568 (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
575 /* Ensure we reject compleate junk first */
576 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
578 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
582 domain_filter = NULL;
584 /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */
585 ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
587 krb5_free_principal(smb_krb5_context->krb5_context, principal);
591 krb5_free_principal(smb_krb5_context->krb5_context, principal);
593 /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
594 result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))",
595 ldb_binary_encode_string(mem_ctx, unparsed_name));
598 W_ERROR_HAVE_NO_MEMORY(result_filter);
601 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
602 krb5_principal principal;
603 char *unparsed_name_short;
604 krb5_data *component;
607 ret = smb_krb5_init_context(mem_ctx,
608 ldb_get_event_context(sam_ctx),
609 (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
616 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
618 krb5_princ_size(smb_krb5_context->krb5_context,
620 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
621 krb5_free_principal(smb_krb5_context->krb5_context, principal);
623 } else if (ret == 0) {
624 krb5_free_principal(smb_krb5_context->krb5_context, principal);
626 ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
627 KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
629 return dns_domain_from_principal(mem_ctx, smb_krb5_context,
633 domain_filter = NULL;
635 ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
636 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
638 krb5_free_principal(smb_krb5_context->krb5_context, principal);
642 component = krb5_princ_component(smb_krb5_context->krb5_context,
644 service = (char *)component->data;
645 if ((krb5_princ_size(smb_krb5_context->krb5_context,
647 (strcasecmp(service, "host") == 0)) {
648 /* the 'cn' attribute is just the leading part of the name */
650 component = krb5_princ_component(
651 smb_krb5_context->krb5_context,
653 computer_name = talloc_strndup(mem_ctx, (char *)component->data,
654 strcspn((char *)component->data, "."));
655 if (computer_name == NULL) {
656 krb5_free_principal(smb_krb5_context->krb5_context, principal);
657 free(unparsed_name_short);
661 result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))",
662 ldb_binary_encode_string(mem_ctx, unparsed_name_short),
663 ldb_binary_encode_string(mem_ctx, computer_name));
665 result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))",
666 ldb_binary_encode_string(mem_ctx, unparsed_name_short));
668 krb5_free_principal(smb_krb5_context->krb5_context, principal);
669 free(unparsed_name_short);
670 W_ERROR_HAVE_NO_MEMORY(result_filter);
675 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
680 if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
681 return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
682 name_dn, name, info1);
685 return DsCrackNameOneFilter(sam_ctx, mem_ctx,
687 format_flags, format_offered, format_desired,
689 domain_filter, result_filter,
693 /* Subcase of CrackNames. It is possible to translate a LDAP-style DN
694 * (FQDN_1779) into a canoical name without actually searching the
697 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
698 enum drsuapi_DsNameFormat format_offered,
699 enum drsuapi_DsNameFormat format_desired,
700 struct ldb_dn *name_dn, const char *name,
701 struct drsuapi_DsNameInfo1 *info1)
704 if (format_offered != DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
705 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
709 switch (format_desired) {
710 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
711 cracked = ldb_dn_canonical_string(mem_ctx, name_dn);
713 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
714 cracked = ldb_dn_canonical_ex_string(mem_ctx, name_dn);
717 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
720 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
721 info1->result_name = cracked;
729 /* Given a filter for the domain, and one for the result, perform the
730 * ldb search. The format offered and desired flags change the
731 * behaviours, including what attributes to return.
733 * The smb_krb5_context is required because we use the krb5 libs for principal parsing
736 static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
737 struct smb_krb5_context *smb_krb5_context,
738 uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
739 enum drsuapi_DsNameFormat format_desired,
740 struct ldb_dn *name_dn, const char *name,
741 const char *domain_filter, const char *result_filter,
742 struct drsuapi_DsNameInfo1 *info1)
745 struct ldb_result *domain_res = NULL;
746 const char * const *domain_attrs;
747 const char * const *result_attrs;
748 struct ldb_message **result_res = NULL;
749 struct ldb_message *result = NULL;
752 struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
754 const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
755 const char * const _result_attrs_null[] = { NULL };
757 const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
758 const char * const _result_attrs_canonical[] = { "canonicalName", NULL };
760 const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
761 const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};
763 const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
764 const char * const _result_attrs_guid[] = { "objectGUID", NULL};
766 const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
767 const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};
769 const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
770 const char * const _result_attrs_none[] = { NULL};
772 /* here we need to set the attrs lists for domain and result lookups */
773 switch (format_desired) {
774 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
775 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
776 domain_attrs = _domain_attrs_1779;
777 result_attrs = _result_attrs_null;
779 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
780 domain_attrs = _domain_attrs_canonical;
781 result_attrs = _result_attrs_canonical;
783 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
784 domain_attrs = _domain_attrs_nt4;
785 result_attrs = _result_attrs_nt4;
787 case DRSUAPI_DS_NAME_FORMAT_GUID:
788 domain_attrs = _domain_attrs_guid;
789 result_attrs = _result_attrs_guid;
791 case DRSUAPI_DS_NAME_FORMAT_DISPLAY:
792 domain_attrs = _domain_attrs_display;
793 result_attrs = _result_attrs_display;
796 domain_attrs = _domain_attrs_none;
797 result_attrs = _result_attrs_none;
802 /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
803 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
807 "%s", domain_filter);
809 if (ldb_ret != LDB_SUCCESS) {
810 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
811 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
815 switch (domain_res->count) {
819 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
822 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
826 info1->dns_domain_name = ldb_msg_find_attr_as_string(domain_res->msgs[0], "dnsRoot", NULL);
827 W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
828 info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
830 info1->dns_domain_name = NULL;
831 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
836 struct ldb_result *res;
837 uint32_t dsdb_flags = 0;
838 struct ldb_dn *search_dn;
842 search_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
844 dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
847 if (format_desired == DRSUAPI_DS_NAME_FORMAT_GUID){
848 dsdb_flags = dsdb_flags| DSDB_SEARCH_SHOW_DELETED;
851 /* search with the 'phantom root' flag */
852 ret = dsdb_search(sam_ctx, mem_ctx, &res,
857 "%s", result_filter);
858 if (ret != LDB_SUCCESS) {
859 DEBUG(2, ("DsCrackNameOneFilter phantom root search failed: %s\n",
860 ldb_errstring(sam_ctx)));
861 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
865 ldb_ret = res->count;
866 result_res = res->msgs;
867 } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
868 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
870 } else if (domain_res) {
871 name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
872 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
876 DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not available: This can't happen...\n"));
877 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
883 result = result_res[0];
886 switch (format_offered) {
887 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
888 return DsCrackNameSPNAlias(sam_ctx, mem_ctx,
890 format_flags, format_offered, format_desired,
893 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
894 return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context,
895 format_flags, format_offered, format_desired,
900 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
903 DEBUG(2, ("DsCrackNameOneFilter result search failed: %s\n", ldb_errstring(sam_ctx)));
904 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
907 switch (format_offered) {
908 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
909 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
911 const char *canonical_name = NULL; /* Not required, but we get warnings... */
912 /* We may need to manually filter further */
913 for (i = 0; i < ldb_ret; i++) {
914 switch (format_offered) {
915 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
916 canonical_name = ldb_dn_canonical_string(mem_ctx, result_res[i]->dn);
918 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
919 canonical_name = ldb_dn_canonical_ex_string(mem_ctx, result_res[i]->dn);
924 if (strcasecmp_m(canonical_name, name) == 0) {
925 result = result_res[i];
930 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
935 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
940 info1->dns_domain_name = ldb_dn_canonical_string(mem_ctx, result->dn);
941 W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
942 p = strchr(info1->dns_domain_name, '/');
947 /* here we can use result and domain_res[0] */
948 switch (format_desired) {
949 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
950 info1->result_name = ldb_dn_alloc_linearized(mem_ctx, result->dn);
951 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
953 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
956 case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
957 info1->result_name = ldb_msg_find_attr_as_string(result, "canonicalName", NULL);
958 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
961 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
962 /* Not in the virtual ldb attribute */
963 return DsCrackNameOneSyntactical(mem_ctx,
964 DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
965 DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
966 result->dn, name, info1);
968 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
970 const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
971 const char *_acc = "", *_dom = "";
973 if (samdb_find_attribute(sam_ctx, result, "objectClass", "domain")) {
975 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
979 "(ncName=%s)", ldb_dn_get_linearized(result->dn));
981 if (ldb_ret != LDB_SUCCESS) {
982 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
983 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
987 switch (domain_res->count) {
991 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
994 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
997 _dom = ldb_msg_find_attr_as_string(domain_res->msgs[0], "nETBIOSName", NULL);
998 W_ERROR_HAVE_NO_MEMORY(_dom);
1000 _acc = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
1002 info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1005 if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx, SID_BUILTIN), sid)) {
1008 const char *attrs[] = { NULL };
1009 struct ldb_result *domain_res2;
1010 struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
1014 dom_sid->num_auths--;
1015 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
1019 "(&(objectSid=%s)(objectClass=domain))",
1020 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
1022 if (ldb_ret != LDB_SUCCESS) {
1023 DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s\n", ldb_errstring(sam_ctx)));
1024 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1028 switch (domain_res->count) {
1032 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1035 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1039 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res2,
1043 "(ncName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
1045 if (ldb_ret != LDB_SUCCESS) {
1046 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
1047 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1051 switch (domain_res2->count) {
1055 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1058 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1061 _dom = ldb_msg_find_attr_as_string(domain_res2->msgs[0], "nETBIOSName", NULL);
1062 W_ERROR_HAVE_NO_MEMORY(_dom);
1066 info1->result_name = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
1067 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
1069 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
1072 case DRSUAPI_DS_NAME_FORMAT_GUID: {
1075 guid = samdb_result_guid(result, "objectGUID");
1077 info1->result_name = GUID_string2(mem_ctx, &guid);
1078 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
1080 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
1083 case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
1084 info1->result_name = ldb_msg_find_attr_as_string(result, "displayName", NULL);
1085 if (!info1->result_name) {
1086 info1->result_name = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
1088 if (!info1->result_name) {
1089 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1091 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
1095 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
1096 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1099 case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN:
1100 case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
1101 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1105 info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1110 /* Given a user Principal Name (such as foo@bar.com),
1111 * return the user and domain DNs. This is used in the KDC to then
1112 * return the Keys and evaluate policy */
1114 NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx,
1115 TALLOC_CTX *mem_ctx,
1116 const char *user_principal_name,
1117 struct ldb_dn **user_dn,
1118 struct ldb_dn **domain_dn)
1121 struct drsuapi_DsNameInfo1 info1;
1122 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
1123 DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
1124 DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
1125 user_principal_name,
1127 if (!W_ERROR_IS_OK(werr)) {
1128 return werror_to_ntstatus(werr);
1130 switch (info1.status) {
1131 case DRSUAPI_DS_NAME_STATUS_OK:
1133 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1134 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1135 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1136 return NT_STATUS_NO_SUCH_USER;
1137 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1139 return NT_STATUS_UNSUCCESSFUL;
1142 *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1145 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
1146 DRSUAPI_DS_NAME_FORMAT_CANONICAL,
1147 DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
1148 talloc_asprintf(mem_ctx, "%s/",
1149 info1.dns_domain_name),
1151 if (!W_ERROR_IS_OK(werr)) {
1152 return werror_to_ntstatus(werr);
1154 switch (info1.status) {
1155 case DRSUAPI_DS_NAME_STATUS_OK:
1157 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1158 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1159 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1160 return NT_STATUS_NO_SUCH_USER;
1161 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1163 return NT_STATUS_UNSUCCESSFUL;
1166 *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1169 return NT_STATUS_OK;
1172 /* Given a Service Principal Name (such as host/foo.bar.com@BAR.COM),
1173 * return the user and domain DNs. This is used in the KDC to then
1174 * return the Keys and evaluate policy */
1176 NTSTATUS crack_service_principal_name(struct ldb_context *sam_ctx,
1177 TALLOC_CTX *mem_ctx,
1178 const char *service_principal_name,
1179 struct ldb_dn **user_dn,
1180 struct ldb_dn **domain_dn)
1183 struct drsuapi_DsNameInfo1 info1;
1184 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
1185 DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
1186 DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
1187 service_principal_name,
1189 if (!W_ERROR_IS_OK(werr)) {
1190 return werror_to_ntstatus(werr);
1192 switch (info1.status) {
1193 case DRSUAPI_DS_NAME_STATUS_OK:
1195 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1196 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1197 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1198 return NT_STATUS_NO_SUCH_USER;
1199 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1201 return NT_STATUS_UNSUCCESSFUL;
1204 *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1207 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
1208 DRSUAPI_DS_NAME_FORMAT_CANONICAL,
1209 DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
1210 talloc_asprintf(mem_ctx, "%s/",
1211 info1.dns_domain_name),
1213 if (!W_ERROR_IS_OK(werr)) {
1214 return werror_to_ntstatus(werr);
1216 switch (info1.status) {
1217 case DRSUAPI_DS_NAME_STATUS_OK:
1219 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1220 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1221 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1222 return NT_STATUS_NO_SUCH_USER;
1223 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1225 return NT_STATUS_UNSUCCESSFUL;
1228 *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1231 return NT_STATUS_OK;
1234 NTSTATUS crack_name_to_nt4_name(TALLOC_CTX *mem_ctx,
1235 struct tevent_context *ev_ctx,
1236 struct loadparm_context *lp_ctx,
1237 enum drsuapi_DsNameFormat format_offered,
1239 const char **nt4_domain, const char **nt4_account)
1242 struct drsuapi_DsNameInfo1 info1;
1243 struct ldb_context *ldb;
1246 /* Handle anonymous bind */
1247 if (!name || !*name) {
1250 return NT_STATUS_OK;
1253 ldb = samdb_connect(mem_ctx, ev_ctx, lp_ctx, system_session(lp_ctx), 0);
1255 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1258 werr = DsCrackNameOneName(ldb, mem_ctx, 0,
1260 DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
1263 if (!W_ERROR_IS_OK(werr)) {
1264 return werror_to_ntstatus(werr);
1266 switch (info1.status) {
1267 case DRSUAPI_DS_NAME_STATUS_OK:
1269 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1270 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1271 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1272 return NT_STATUS_NO_SUCH_USER;
1273 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1275 return NT_STATUS_UNSUCCESSFUL;
1278 *nt4_domain = talloc_strdup(mem_ctx, info1.result_name);
1279 if (*nt4_domain == NULL) {
1280 return NT_STATUS_NO_MEMORY;
1283 p = strchr(*nt4_domain, '\\');
1285 return NT_STATUS_INVALID_PARAMETER;
1289 *nt4_account = talloc_strdup(mem_ctx, &p[1]);
1290 if (*nt4_account == NULL) {
1291 return NT_STATUS_NO_MEMORY;
1294 return NT_STATUS_OK;
1297 NTSTATUS crack_auto_name_to_nt4_name(TALLOC_CTX *mem_ctx,
1298 struct tevent_context *ev_ctx,
1299 struct loadparm_context *lp_ctx,
1301 const char **nt4_domain,
1302 const char **nt4_account)
1304 enum drsuapi_DsNameFormat format_offered = DRSUAPI_DS_NAME_FORMAT_UNKNOWN;
1306 /* Handle anonymous bind */
1307 if (!name || !*name) {
1310 return NT_STATUS_OK;
1313 if (strchr_m(name, '=')) {
1314 format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
1315 } else if (strchr_m(name, '@')) {
1316 format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL;
1317 } else if (strchr_m(name, '\\')) {
1318 format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
1319 } else if (strchr_m(name, '/')) {
1320 format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL;
1322 return NT_STATUS_NO_SUCH_USER;
1325 return crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, format_offered, name, nt4_domain, nt4_account);
1329 WERROR dcesrv_drsuapi_ListRoles(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1330 const struct drsuapi_DsNameRequest1 *req1,
1331 struct drsuapi_DsNameCtr1 **ctr1)
1333 struct drsuapi_DsNameInfo1 *names;
1335 uint32_t count = 5;/*number of fsmo role owners we are going to return*/
1337 *ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
1338 W_ERROR_HAVE_NO_MEMORY(*ctr1);
1339 names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
1340 W_ERROR_HAVE_NO_MEMORY(names);
1342 for (i = 0; i < count; i++) {
1344 struct ldb_dn *role_owner_dn, *fsmo_role_dn, *server_dn;
1345 werr = dsdb_get_fsmo_role_info(mem_ctx, sam_ctx, i,
1346 &fsmo_role_dn, &role_owner_dn);
1347 if(!W_ERROR_IS_OK(werr)) {
1350 server_dn = ldb_dn_copy(mem_ctx, role_owner_dn);
1351 ldb_dn_remove_child_components(server_dn, 1);
1352 names[i].status = DRSUAPI_DS_NAME_STATUS_OK;
1353 names[i].dns_domain_name = samdb_dn_to_dnshostname(sam_ctx, mem_ctx,
1355 if(!names[i].dns_domain_name) {
1356 DEBUG(4, ("list_roles: Failed to find dNSHostName for server %s\n",
1357 ldb_dn_get_linearized(server_dn)));
1359 names[i].result_name = talloc_strdup(mem_ctx, ldb_dn_get_linearized(role_owner_dn));
1362 (*ctr1)->count = count;
1363 (*ctr1)->array = names;
1368 WERROR dcesrv_drsuapi_CrackNamesByNameFormat(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1369 const struct drsuapi_DsNameRequest1 *req1,
1370 struct drsuapi_DsNameCtr1 **ctr1)
1372 struct drsuapi_DsNameInfo1 *names;
1376 *ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
1377 W_ERROR_HAVE_NO_MEMORY(*ctr1);
1379 count = req1->count;
1380 names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
1381 W_ERROR_HAVE_NO_MEMORY(names);
1383 for (i=0; i < count; i++) {
1384 status = DsCrackNameOneName(sam_ctx, mem_ctx,
1386 req1->format_offered,
1387 req1->format_desired,
1390 if (!W_ERROR_IS_OK(status)) {
1395 (*ctr1)->count = count;
1396 (*ctr1)->array = names;