2 Unix SMB/CIFS implementation.
4 crachnames implementation for the drsuapi pipe
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthieu Patou <mat@matws.net> 2012
10 Copyright (C) Catalyst .Net Ltd 2017
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "librpc/gen_ndr/drsuapi.h"
28 #include "lib/events/events.h"
30 #include <ldb_errors.h>
31 #include "auth/kerberos/kerberos.h"
32 #include "libcli/ldap/ldap_ndr.h"
33 #include "libcli/security/security.h"
34 #include "auth/auth.h"
35 #include "../lib/util/util_ldb.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "dsdb/common/util.h"
38 #include "param/param.h"
42 static WERROR
DsCrackNameOneFilter(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
43 struct smb_krb5_context
*smb_krb5_context
,
44 uint32_t format_flags
, enum drsuapi_DsNameFormat format_offered
,
45 enum drsuapi_DsNameFormat format_desired
,
46 struct ldb_dn
*name_dn
, const char *name
,
47 const char *domain_filter
, const char *result_filter
,
48 struct drsuapi_DsNameInfo1
*info1
, int scope
, struct ldb_dn
*search_dn
);
49 static WERROR
DsCrackNameOneSyntactical(TALLOC_CTX
*mem_ctx
,
50 enum drsuapi_DsNameFormat format_offered
,
51 enum drsuapi_DsNameFormat format_desired
,
52 struct ldb_dn
*name_dn
, const char *name
,
53 struct drsuapi_DsNameInfo1
*info1
);
55 static WERROR
dns_domain_from_principal(TALLOC_CTX
*mem_ctx
, struct smb_krb5_context
*smb_krb5_context
,
57 struct drsuapi_DsNameInfo1
*info1
)
60 krb5_principal principal
;
61 /* perhaps it's a principal with a realm, so return the right 'domain only' response */
62 ret
= krb5_parse_name_flags(smb_krb5_context
->krb5_context
, name
,
63 KRB5_PRINCIPAL_PARSE_REQUIRE_REALM
, &principal
);
65 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
69 info1
->dns_domain_name
= smb_krb5_principal_get_realm(
70 mem_ctx
, smb_krb5_context
->krb5_context
, principal
);
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(struct ldb_context
*ldb_ctx
,
81 const char *alias_from
,
85 * Some of the logic of this function is mirrored in find_spn_alias()
86 * in source4/dsdb.samdb/ldb_modules/samldb.c. If you change this to
87 * not return the first matched alias, you will need to rethink that
92 struct ldb_result
*res
;
93 struct ldb_message_element
*spnmappings
;
95 struct ldb_dn
*service_dn
;
98 const char *directory_attrs
[] = {
103 tmp_ctx
= talloc_new(mem_ctx
);
105 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
108 service_dn
= ldb_dn_new(tmp_ctx
, ldb_ctx
, "CN=Directory Service,CN=Windows NT,CN=Services");
109 if ( ! ldb_dn_add_base(service_dn
, ldb_get_config_basedn(ldb_ctx
))) {
110 talloc_free(tmp_ctx
);
111 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
113 service_dn_str
= ldb_dn_alloc_linearized(tmp_ctx
, service_dn
);
114 if ( ! service_dn_str
) {
115 talloc_free(tmp_ctx
);
116 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
119 ret
= ldb_search(ldb_ctx
, tmp_ctx
, &res
, service_dn
, LDB_SCOPE_BASE
,
120 directory_attrs
, "(objectClass=nTDSService)");
122 if (ret
!= LDB_SUCCESS
&& ret
!= LDB_ERR_NO_SUCH_OBJECT
) {
123 DEBUG(1, ("ldb_search: dn: %s not found: %s\n", service_dn_str
, ldb_errstring(ldb_ctx
)));
124 talloc_free(tmp_ctx
);
125 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
126 } else if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
127 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str
));
128 talloc_free(tmp_ctx
);
129 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
130 } else if (res
->count
!= 1) {
131 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str
));
132 talloc_free(tmp_ctx
);
133 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
136 spnmappings
= ldb_msg_find_element(res
->msgs
[0], "sPNMappings");
137 if (!spnmappings
|| spnmappings
->num_values
== 0) {
138 DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute\n", service_dn_str
));
139 talloc_free(tmp_ctx
);
140 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
143 for (i
= 0; i
< spnmappings
->num_values
; i
++) {
144 char *mapping
, *p
, *str
;
145 mapping
= talloc_strdup(tmp_ctx
,
146 (const char *)spnmappings
->values
[i
].data
);
148 DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str
));
149 talloc_free(tmp_ctx
);
150 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
153 /* C string manipulation sucks */
155 p
= strchr(mapping
, '=');
157 DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n",
158 service_dn_str
, mapping
));
159 talloc_free(tmp_ctx
);
160 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
171 if (strcasecmp(str
, alias_from
) == 0) {
173 talloc_steal(mem_ctx
, mapping
);
174 talloc_free(tmp_ctx
);
175 return DRSUAPI_DS_NAME_STATUS_OK
;
179 DEBUG(4, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from
));
180 talloc_free(tmp_ctx
);
181 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
184 /* When cracking a ServicePrincipalName, many services may be served
185 * by the host/ servicePrincipalName. The incoming query is for cifs/
186 * but we translate it here, and search on host/. This is done after
187 * the cifs/ entry has been searched for, making this a fallback */
189 static WERROR
DsCrackNameSPNAlias(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
190 struct smb_krb5_context
*smb_krb5_context
,
191 uint32_t format_flags
, enum drsuapi_DsNameFormat format_offered
,
192 enum drsuapi_DsNameFormat format_desired
,
193 const char *name
, struct drsuapi_DsNameInfo1
*info1
)
197 krb5_principal principal
;
198 const krb5_data
*component
;
199 const char *service
, *dns_name
;
202 enum drsuapi_DsNameStatus namestatus
;
204 /* parse principal */
205 ret
= krb5_parse_name_flags(smb_krb5_context
->krb5_context
,
206 name
, KRB5_PRINCIPAL_PARSE_NO_REALM
, &principal
);
208 DEBUG(2, ("Could not parse principal: %s: %s\n",
209 name
, smb_get_krb5_error_message(smb_krb5_context
->krb5_context
,
211 return WERR_NOT_ENOUGH_MEMORY
;
214 /* grab cifs/, http/ etc */
216 /* This is checked for in callers, but be safe */
217 if (krb5_princ_size(smb_krb5_context
->krb5_context
, principal
) < 2) {
218 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
219 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
222 component
= krb5_princ_component(smb_krb5_context
->krb5_context
,
224 service
= (const char *)component
->data
;
225 component
= krb5_princ_component(smb_krb5_context
->krb5_context
,
227 dns_name
= (const char *)component
->data
;
230 namestatus
= LDB_lookup_spn_alias(sam_ctx
, mem_ctx
,
231 service
, &new_service
);
233 if (namestatus
== DRSUAPI_DS_NAME_STATUS_NOT_FOUND
) {
235 info1
->status
= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
;
236 info1
->dns_domain_name
= talloc_strdup(mem_ctx
, dns_name
);
237 if (!info1
->dns_domain_name
) {
238 wret
= WERR_NOT_ENOUGH_MEMORY
;
240 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
242 } else if (namestatus
!= DRSUAPI_DS_NAME_STATUS_OK
) {
243 info1
->status
= namestatus
;
244 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
248 /* reform principal */
249 new_princ
= talloc_asprintf(mem_ctx
, "%s/%s", new_service
, dns_name
);
251 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
252 return WERR_NOT_ENOUGH_MEMORY
;
255 wret
= DsCrackNameOneName(sam_ctx
, mem_ctx
, format_flags
, format_offered
, format_desired
,
257 talloc_free(new_princ
);
258 if (W_ERROR_IS_OK(wret
) && (info1
->status
== DRSUAPI_DS_NAME_STATUS_NOT_FOUND
)) {
259 info1
->status
= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
;
260 info1
->dns_domain_name
= talloc_strdup(mem_ctx
, dns_name
);
261 if (!info1
->dns_domain_name
) {
262 wret
= WERR_NOT_ENOUGH_MEMORY
;
265 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
269 /* Subcase of CrackNames, for the userPrincipalName */
271 static WERROR
DsCrackNameUPN(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
272 struct smb_krb5_context
*smb_krb5_context
,
273 uint32_t format_flags
, enum drsuapi_DsNameFormat format_offered
,
274 enum drsuapi_DsNameFormat format_desired
,
275 const char *name
, struct drsuapi_DsNameInfo1
*info1
)
279 const char *domain_filter
= NULL
;
280 const char *result_filter
= NULL
;
282 krb5_principal principal
;
284 char *unparsed_name_short
;
285 const char *domain_attrs
[] = { NULL
};
286 struct ldb_result
*domain_res
= NULL
;
288 /* Prevent recursion */
290 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
294 ret
= krb5_parse_name_flags(smb_krb5_context
->krb5_context
, name
,
295 KRB5_PRINCIPAL_PARSE_REQUIRE_REALM
, &principal
);
297 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
301 realm
= smb_krb5_principal_get_realm(
302 mem_ctx
, smb_krb5_context
->krb5_context
, principal
);
304 ldb_ret
= ldb_search(sam_ctx
, mem_ctx
, &domain_res
,
305 samdb_partitions_dn(sam_ctx
, mem_ctx
),
308 "(&(objectClass=crossRef)(|(dnsRoot=%s)(netbiosName=%s))(systemFlags:%s:=%u))",
309 ldb_binary_encode_string(mem_ctx
, realm
),
310 ldb_binary_encode_string(mem_ctx
, realm
),
311 LDB_OID_COMPARATOR_AND
,
312 SYSTEM_FLAG_CR_NTDS_DOMAIN
);
315 if (ldb_ret
!= LDB_SUCCESS
) {
316 DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s\n", ldb_errstring(sam_ctx
)));
317 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
318 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
322 switch (domain_res
->count
) {
326 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
327 return dns_domain_from_principal(mem_ctx
, smb_krb5_context
,
330 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
331 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
336 * The important thing here is that a samAccountName may have
337 * a space in it, and this must not be kerberos escaped to
338 * match this filter, so we specify
339 * KRB5_PRINCIPAL_UNPARSE_DISPLAY
341 ret
= krb5_unparse_name_flags(smb_krb5_context
->krb5_context
, principal
,
342 KRB5_PRINCIPAL_UNPARSE_NO_REALM
|
343 KRB5_PRINCIPAL_UNPARSE_DISPLAY
,
344 &unparsed_name_short
);
345 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
348 free(unparsed_name_short
);
349 return WERR_NOT_ENOUGH_MEMORY
;
352 /* This may need to be extended for more userPrincipalName variations */
353 result_filter
= talloc_asprintf(mem_ctx
, "(&(samAccountName=%s)(objectClass=user))",
354 ldb_binary_encode_string(mem_ctx
, unparsed_name_short
));
356 domain_filter
= talloc_asprintf(mem_ctx
, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res
->msgs
[0]->dn
));
358 if (!result_filter
|| !domain_filter
) {
359 free(unparsed_name_short
);
360 return WERR_NOT_ENOUGH_MEMORY
;
362 status
= DsCrackNameOneFilter(sam_ctx
, mem_ctx
,
364 format_flags
, format_offered
, format_desired
,
365 NULL
, unparsed_name_short
, domain_filter
, result_filter
,
366 info1
, LDB_SCOPE_SUBTREE
, NULL
);
367 free(unparsed_name_short
);
373 * This function will workout the filtering parameter in order to be able to do
374 * the adapted search when the incomming format is format_functional.
375 * This boils down to defining the search_dn (passed as pointer to ldb_dn *) and the
376 * ldap filter request.
377 * Main input parameters are:
378 * * name, which is the portion of the functional name after the
380 * * domain_filter, which is a ldap search filter used to find the NC DN given the
381 * function name to crack.
383 static WERROR
get_format_functional_filtering_param(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
384 char *name
, struct drsuapi_DsNameInfo1
*info1
,
385 struct ldb_dn
**psearch_dn
, const char *domain_filter
, const char **presult_filter
)
387 struct ldb_result
*domain_res
= NULL
;
388 const char * const domain_attrs
[] = {"ncName", NULL
};
389 struct ldb_dn
*partitions_basedn
= samdb_partitions_dn(sam_ctx
, mem_ctx
);
391 char *account
, *s
, *result_filter
= NULL
;
392 struct ldb_dn
*search_dn
= NULL
;
395 *presult_filter
= NULL
;
397 ldb_ret
= ldb_search(sam_ctx
, mem_ctx
, &domain_res
,
401 "%s", domain_filter
);
403 if (ldb_ret
!= LDB_SUCCESS
) {
404 DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx
)));
405 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
409 if (domain_res
->count
== 1) {
410 struct ldb_dn
*tmp_dn
= samdb_result_dn(sam_ctx
, mem_ctx
, domain_res
->msgs
[0], "ncName", NULL
);
411 const char * const name_attrs
[] = {"name", NULL
};
414 s
= strchr(account
, '/');
415 talloc_free(domain_res
);
420 ldb_ret
= ldb_search(sam_ctx
, mem_ctx
, &domain_res
,
426 if (ldb_ret
!= LDB_SUCCESS
) {
427 DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx
)));
428 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
432 switch (domain_res
->count
) {
436 talloc_free(domain_res
);
437 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
440 talloc_free(domain_res
);
441 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
445 tmp_dn
= talloc_steal(mem_ctx
, domain_res
->msgs
[0]->dn
);
446 talloc_free(domain_res
);
449 s
= strchr(account
, '/');
451 account
= ldb_binary_encode_string(mem_ctx
, account
);
452 W_ERROR_HAVE_NO_MEMORY(account
);
453 result_filter
= talloc_asprintf(mem_ctx
, "(name=%s)",
455 W_ERROR_HAVE_NO_MEMORY(result_filter
);
457 *psearch_dn
= search_dn
;
458 *presult_filter
= result_filter
;
462 /* Crack a single 'name', from format_offered into format_desired, returning the result in info1 */
464 WERROR
DsCrackNameOneName(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
465 uint32_t format_flags
, enum drsuapi_DsNameFormat format_offered
,
466 enum drsuapi_DsNameFormat format_desired
,
467 const char *name
, struct drsuapi_DsNameInfo1
*info1
)
470 const char *domain_filter
= NULL
;
471 const char *result_filter
= NULL
;
472 struct ldb_dn
*name_dn
= NULL
;
473 struct ldb_dn
*search_dn
= NULL
;
475 struct smb_krb5_context
*smb_krb5_context
= NULL
;
476 int scope
= LDB_SCOPE_SUBTREE
;
478 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
479 info1
->dns_domain_name
= NULL
;
480 info1
->result_name
= NULL
;
483 return WERR_INVALID_PARAMETER
;
486 /* TODO: - fill the correct names in all cases!
487 * - handle format_flags
489 if (format_desired
== DRSUAPI_DS_NAME_FORMAT_UNKNOWN
) {
492 /* here we need to set the domain_filter and/or the result_filter */
493 switch (format_offered
) {
494 case DRSUAPI_DS_NAME_FORMAT_UNKNOWN
:
497 enum drsuapi_DsNameFormat formats
[] = {
498 DRSUAPI_DS_NAME_FORMAT_FQDN_1779
, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL
,
499 DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
, DRSUAPI_DS_NAME_FORMAT_CANONICAL
,
500 DRSUAPI_DS_NAME_FORMAT_GUID
, DRSUAPI_DS_NAME_FORMAT_DISPLAY
,
501 DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL
,
502 DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY
,
503 DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
506 for (i
=0; i
< ARRAY_SIZE(formats
); i
++) {
507 werr
= DsCrackNameOneName(sam_ctx
, mem_ctx
, format_flags
, formats
[i
], format_desired
, name
, info1
);
508 if (!W_ERROR_IS_OK(werr
)) {
511 if (info1
->status
!= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
&&
512 (formats
[i
] != DRSUAPI_DS_NAME_FORMAT_CANONICAL
||
513 info1
->status
!= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
))
521 case DRSUAPI_DS_NAME_FORMAT_CANONICAL
:
522 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
:
524 char *str
, *s
, *account
;
525 scope
= LDB_SCOPE_ONELEVEL
;
527 if (strlen(name
) == 0) {
528 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
532 str
= talloc_strdup(mem_ctx
, name
);
533 W_ERROR_HAVE_NO_MEMORY(str
);
535 if (format_offered
== DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
) {
536 /* Look backwards for the \n, and replace it with / */
537 s
= strrchr(str
, '\n');
539 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
545 s
= strchr(str
, '/');
547 /* there must be at least one / */
548 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
555 domain_filter
= talloc_asprintf(mem_ctx
, "(&(objectClass=crossRef)(dnsRoot=%s)(systemFlags:%s:=%u))",
556 ldb_binary_encode_string(mem_ctx
, str
),
557 LDB_OID_COMPARATOR_AND
,
558 SYSTEM_FLAG_CR_NTDS_DOMAIN
);
559 W_ERROR_HAVE_NO_MEMORY(domain_filter
);
561 /* There may not be anything after the domain component (search for the domain itself) */
563 if (account
&& *account
) {
564 WERROR werr
= get_format_functional_filtering_param(sam_ctx
,
571 if (!W_ERROR_IS_OK(werr
)) {
574 if (info1
->status
!= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
)
579 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
: {
582 const char *account
= NULL
;
584 domain
= talloc_strdup(mem_ctx
, name
);
585 W_ERROR_HAVE_NO_MEMORY(domain
);
587 p
= strchr(domain
, '\\');
589 /* invalid input format */
590 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
599 domain_filter
= talloc_asprintf(mem_ctx
,
600 "(&(objectClass=crossRef)(netbiosName=%s)(systemFlags:%s:=%u))",
601 ldb_binary_encode_string(mem_ctx
, domain
),
602 LDB_OID_COMPARATOR_AND
,
603 SYSTEM_FLAG_CR_NTDS_DOMAIN
);
604 W_ERROR_HAVE_NO_MEMORY(domain_filter
);
606 result_filter
= talloc_asprintf(mem_ctx
, "(sAMAccountName=%s)",
607 ldb_binary_encode_string(mem_ctx
, account
));
608 W_ERROR_HAVE_NO_MEMORY(result_filter
);
615 /* A LDAP DN as a string */
616 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779
: {
617 domain_filter
= NULL
;
618 name_dn
= ldb_dn_new(mem_ctx
, sam_ctx
, name
);
619 if (! ldb_dn_validate(name_dn
)) {
620 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
626 /* A GUID as a string */
627 case DRSUAPI_DS_NAME_FORMAT_GUID
: {
631 domain_filter
= NULL
;
633 nt_status
= GUID_from_string(name
, &guid
);
634 if (!NT_STATUS_IS_OK(nt_status
)) {
635 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
639 ldap_guid
= ldap_encode_ndr_GUID(mem_ctx
, &guid
);
641 return WERR_NOT_ENOUGH_MEMORY
;
643 result_filter
= talloc_asprintf(mem_ctx
, "(objectGUID=%s)",
645 W_ERROR_HAVE_NO_MEMORY(result_filter
);
648 case DRSUAPI_DS_NAME_FORMAT_DISPLAY
: {
649 domain_filter
= NULL
;
651 result_filter
= talloc_asprintf(mem_ctx
, "(|(displayName=%s)(samAccountName=%s))",
652 ldb_binary_encode_string(mem_ctx
, name
),
653 ldb_binary_encode_string(mem_ctx
, name
));
654 W_ERROR_HAVE_NO_MEMORY(result_filter
);
658 /* A S-1234-5678 style string */
659 case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY
: {
660 struct dom_sid
*sid
= dom_sid_parse_talloc(mem_ctx
, name
);
663 domain_filter
= NULL
;
665 info1
->dns_domain_name
= NULL
;
666 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
669 ldap_sid
= ldap_encode_ndr_dom_sid(mem_ctx
,
672 return WERR_NOT_ENOUGH_MEMORY
;
674 result_filter
= talloc_asprintf(mem_ctx
, "(objectSid=%s)",
676 W_ERROR_HAVE_NO_MEMORY(result_filter
);
679 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL
: {
680 krb5_principal principal
;
683 ret
= smb_krb5_init_context(mem_ctx
,
684 (struct loadparm_context
*)ldb_get_opaque(sam_ctx
, "loadparm"),
688 return WERR_NOT_ENOUGH_MEMORY
;
691 /* Ensure we reject complete junk first */
692 ret
= krb5_parse_name(smb_krb5_context
->krb5_context
, name
, &principal
);
694 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
698 domain_filter
= NULL
;
701 * By getting the unparsed name here, we ensure the
702 * escaping is removed correctly (and trust the client
703 * less). The important thing here is that a
704 * userPrincipalName may have a space in it, and this
705 * must not be kerberos escaped to match this filter,
706 * so we specify KRB5_PRINCIPAL_UNPARSE_DISPLAY
708 ret
= krb5_unparse_name_flags(smb_krb5_context
->krb5_context
,
710 KRB5_PRINCIPAL_UNPARSE_DISPLAY
,
713 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
714 return WERR_NOT_ENOUGH_MEMORY
;
717 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
719 /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
720 result_filter
= talloc_asprintf(mem_ctx
, "(&(userPrincipalName=%s)(objectClass=user))",
721 ldb_binary_encode_string(mem_ctx
, unparsed_name
));
724 W_ERROR_HAVE_NO_MEMORY(result_filter
);
727 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL
: {
728 krb5_principal principal
;
729 char *unparsed_name_short
;
730 const krb5_data
*component
;
733 ret
= smb_krb5_init_context(mem_ctx
,
734 (struct loadparm_context
*)ldb_get_opaque(sam_ctx
, "loadparm"),
738 return WERR_NOT_ENOUGH_MEMORY
;
741 ret
= krb5_parse_name(smb_krb5_context
->krb5_context
, name
, &principal
);
743 krb5_princ_size(smb_krb5_context
->krb5_context
,
745 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
746 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
748 } else if (ret
== 0) {
749 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
751 ret
= krb5_parse_name_flags(smb_krb5_context
->krb5_context
, name
,
752 KRB5_PRINCIPAL_PARSE_NO_REALM
, &principal
);
754 return dns_domain_from_principal(mem_ctx
, smb_krb5_context
,
758 domain_filter
= NULL
;
760 ret
= krb5_unparse_name_flags(smb_krb5_context
->krb5_context
, principal
,
761 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &unparsed_name_short
);
763 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
764 return WERR_NOT_ENOUGH_MEMORY
;
767 component
= krb5_princ_component(smb_krb5_context
->krb5_context
,
769 service
= (char *)component
->data
;
770 if ((krb5_princ_size(smb_krb5_context
->krb5_context
,
772 (strcasecmp(service
, "host") == 0)) {
773 /* the 'cn' attribute is just the leading part of the name */
775 component
= krb5_princ_component(
776 smb_krb5_context
->krb5_context
,
778 computer_name
= talloc_strndup(mem_ctx
, (char *)component
->data
,
779 strcspn((char *)component
->data
, "."));
780 if (computer_name
== NULL
) {
781 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
782 free(unparsed_name_short
);
783 return WERR_NOT_ENOUGH_MEMORY
;
786 result_filter
= talloc_asprintf(mem_ctx
, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))",
787 ldb_binary_encode_string(mem_ctx
, unparsed_name_short
),
788 ldb_binary_encode_string(mem_ctx
, computer_name
));
790 result_filter
= talloc_asprintf(mem_ctx
, "(&(servicePrincipalName=%s)(objectClass=user))",
791 ldb_binary_encode_string(mem_ctx
, unparsed_name_short
));
793 krb5_free_principal(smb_krb5_context
->krb5_context
, principal
);
794 free(unparsed_name_short
);
795 W_ERROR_HAVE_NO_MEMORY(result_filter
);
800 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
805 if (format_flags
& DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY
) {
806 return DsCrackNameOneSyntactical(mem_ctx
, format_offered
, format_desired
,
807 name_dn
, name
, info1
);
810 return DsCrackNameOneFilter(sam_ctx
, mem_ctx
,
812 format_flags
, format_offered
, format_desired
,
814 domain_filter
, result_filter
,
815 info1
, scope
, search_dn
);
818 /* Subcase of CrackNames. It is possible to translate a LDAP-style DN
819 * (FQDN_1779) into a canoical name without actually searching the
822 static WERROR
DsCrackNameOneSyntactical(TALLOC_CTX
*mem_ctx
,
823 enum drsuapi_DsNameFormat format_offered
,
824 enum drsuapi_DsNameFormat format_desired
,
825 struct ldb_dn
*name_dn
, const char *name
,
826 struct drsuapi_DsNameInfo1
*info1
)
829 if (format_offered
!= DRSUAPI_DS_NAME_FORMAT_FQDN_1779
) {
830 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING
;
834 switch (format_desired
) {
835 case DRSUAPI_DS_NAME_FORMAT_CANONICAL
:
836 cracked
= ldb_dn_canonical_string(mem_ctx
, name_dn
);
838 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
:
839 cracked
= ldb_dn_canonical_ex_string(mem_ctx
, name_dn
);
842 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING
;
845 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
846 info1
->result_name
= cracked
;
848 return WERR_NOT_ENOUGH_MEMORY
;
854 /* Given a filter for the domain, and one for the result, perform the
855 * ldb search. The format offered and desired flags change the
856 * behaviours, including what attributes to return.
858 * The smb_krb5_context is required because we use the krb5 libs for principal parsing
861 static WERROR
DsCrackNameOneFilter(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
862 struct smb_krb5_context
*smb_krb5_context
,
863 uint32_t format_flags
, enum drsuapi_DsNameFormat format_offered
,
864 enum drsuapi_DsNameFormat format_desired
,
865 struct ldb_dn
*name_dn
, const char *name
,
866 const char *domain_filter
, const char *result_filter
,
867 struct drsuapi_DsNameInfo1
*info1
,
868 int scope
, struct ldb_dn
*search_dn
)
871 struct ldb_result
*domain_res
= NULL
;
872 const char * const *domain_attrs
;
873 const char * const *result_attrs
;
874 struct ldb_message
**result_res
= NULL
;
875 struct ldb_message
*result
= NULL
;
878 struct ldb_dn
*partitions_basedn
= samdb_partitions_dn(sam_ctx
, mem_ctx
);
880 const char * const _domain_attrs_1779
[] = { "ncName", "dnsRoot", NULL
};
881 const char * const _result_attrs_null
[] = { NULL
};
883 const char * const _domain_attrs_canonical
[] = { "ncName", "dnsRoot", NULL
};
884 const char * const _result_attrs_canonical
[] = { "canonicalName", NULL
};
886 const char * const _domain_attrs_nt4
[] = { "ncName", "dnsRoot", "nETBIOSName", NULL
};
887 const char * const _result_attrs_nt4
[] = { "sAMAccountName", "objectSid", "objectClass", NULL
};
889 const char * const _domain_attrs_guid
[] = { "ncName", "dnsRoot", NULL
};
890 const char * const _result_attrs_guid
[] = { "objectGUID", NULL
};
892 const char * const _domain_attrs_upn
[] = { "ncName", "dnsRoot", NULL
};
893 const char * const _result_attrs_upn
[] = { "userPrincipalName", NULL
};
895 const char * const _domain_attrs_spn
[] = { "ncName", "dnsRoot", NULL
};
896 const char * const _result_attrs_spn
[] = { "servicePrincipalName", NULL
};
898 const char * const _domain_attrs_display
[] = { "ncName", "dnsRoot", NULL
};
899 const char * const _result_attrs_display
[] = { "displayName", "samAccountName", NULL
};
901 const char * const _domain_attrs_sid
[] = { "ncName", "dnsRoot", NULL
};
902 const char * const _result_attrs_sid
[] = { "objectSid", NULL
};
904 const char * const _domain_attrs_none
[] = { "ncName", "dnsRoot" , NULL
};
905 const char * const _result_attrs_none
[] = { NULL
};
907 /* here we need to set the attrs lists for domain and result lookups */
908 switch (format_desired
) {
909 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779
:
910 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
:
911 domain_attrs
= _domain_attrs_1779
;
912 result_attrs
= _result_attrs_null
;
914 case DRSUAPI_DS_NAME_FORMAT_CANONICAL
:
915 domain_attrs
= _domain_attrs_canonical
;
916 result_attrs
= _result_attrs_canonical
;
918 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
:
919 domain_attrs
= _domain_attrs_nt4
;
920 result_attrs
= _result_attrs_nt4
;
922 case DRSUAPI_DS_NAME_FORMAT_GUID
:
923 domain_attrs
= _domain_attrs_guid
;
924 result_attrs
= _result_attrs_guid
;
926 case DRSUAPI_DS_NAME_FORMAT_DISPLAY
:
927 domain_attrs
= _domain_attrs_display
;
928 result_attrs
= _result_attrs_display
;
930 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL
:
931 domain_attrs
= _domain_attrs_upn
;
932 result_attrs
= _result_attrs_upn
;
934 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL
:
935 domain_attrs
= _domain_attrs_spn
;
936 result_attrs
= _result_attrs_spn
;
938 case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY
:
939 domain_attrs
= _domain_attrs_sid
;
940 result_attrs
= _result_attrs_sid
;
943 domain_attrs
= _domain_attrs_none
;
944 result_attrs
= _result_attrs_none
;
949 /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
950 ldb_ret
= ldb_search(sam_ctx
, mem_ctx
, &domain_res
,
954 "%s", domain_filter
);
956 if (ldb_ret
!= LDB_SUCCESS
) {
957 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx
)));
958 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
962 switch (domain_res
->count
) {
966 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
969 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
973 info1
->dns_domain_name
= ldb_msg_find_attr_as_string(domain_res
->msgs
[0], "dnsRoot", NULL
);
974 W_ERROR_HAVE_NO_MEMORY(info1
->dns_domain_name
);
975 info1
->status
= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
;
977 info1
->dns_domain_name
= NULL
;
978 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
983 struct ldb_result
*res
;
984 uint32_t dsdb_flags
= 0;
985 struct ldb_dn
*real_search_dn
= NULL
;
986 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
989 * From 4.1.4.2.11 of MS-DRSR
990 * if DS_NAME_FLAG_GCVERIFY in flags then
991 * rt := select all O from all
992 * where attrValue in GetAttrVals(O, att, false)
994 * rt := select all O from subtree DefaultNC()
995 * where attrValue in GetAttrVals(O, att, false)
999 if (format_flags
& DRSUAPI_DS_NAME_FLAG_GCVERIFY
||
1000 format_offered
== DRSUAPI_DS_NAME_FORMAT_GUID
)
1002 dsdb_flags
= DSDB_SEARCH_SEARCH_ALL_PARTITIONS
;
1003 } else if (domain_res
) {
1005 struct ldb_dn
*tmp_dn
= samdb_result_dn(sam_ctx
, mem_ctx
, domain_res
->msgs
[0], "ncName", NULL
);
1006 real_search_dn
= tmp_dn
;
1008 real_search_dn
= search_dn
;
1011 real_search_dn
= ldb_get_default_basedn(sam_ctx
);
1013 if (format_offered
== DRSUAPI_DS_NAME_FORMAT_GUID
){
1014 dsdb_flags
|= DSDB_SEARCH_SHOW_RECYCLED
;
1016 /* search with the 'phantom root' flag */
1017 ret
= dsdb_search(sam_ctx
, mem_ctx
, &res
,
1022 "%s", result_filter
);
1023 if (ret
!= LDB_SUCCESS
) {
1024 DEBUG(2, ("DsCrackNameOneFilter search from '%s' with flags 0x%08x failed: %s\n",
1025 ldb_dn_get_linearized(real_search_dn
),
1027 ldb_errstring(sam_ctx
)));
1028 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
1032 ldb_ret
= res
->count
;
1033 result_res
= res
->msgs
;
1034 } else if (format_offered
== DRSUAPI_DS_NAME_FORMAT_FQDN_1779
) {
1035 ldb_ret
= gendb_search_dn(sam_ctx
, mem_ctx
, name_dn
, &result_res
,
1037 } else if (domain_res
) {
1038 name_dn
= samdb_result_dn(sam_ctx
, mem_ctx
, domain_res
->msgs
[0], "ncName", NULL
);
1039 ldb_ret
= gendb_search_dn(sam_ctx
, mem_ctx
, name_dn
, &result_res
,
1043 DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not available: This can't happen...\n"));
1044 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
1050 result
= result_res
[0];
1053 switch (format_offered
) {
1054 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL
:
1055 return DsCrackNameSPNAlias(sam_ctx
, mem_ctx
,
1057 format_flags
, format_offered
, format_desired
,
1060 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL
:
1061 return DsCrackNameUPN(sam_ctx
, mem_ctx
, smb_krb5_context
,
1062 format_flags
, format_offered
, format_desired
,
1067 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1070 DEBUG(2, ("DsCrackNameOneFilter result search failed: %s\n", ldb_errstring(sam_ctx
)));
1071 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
1074 switch (format_offered
) {
1075 case DRSUAPI_DS_NAME_FORMAT_CANONICAL
:
1076 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
:
1078 const char *canonical_name
= NULL
; /* Not required, but we get warnings... */
1079 /* We may need to manually filter further */
1080 for (i
= 0; i
< ldb_ret
; i
++) {
1081 switch (format_offered
) {
1082 case DRSUAPI_DS_NAME_FORMAT_CANONICAL
:
1083 canonical_name
= ldb_dn_canonical_string(mem_ctx
, result_res
[i
]->dn
);
1085 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
:
1086 canonical_name
= ldb_dn_canonical_ex_string(mem_ctx
, result_res
[i
]->dn
);
1091 if (strcasecmp_m(canonical_name
, name
) == 0) {
1092 result
= result_res
[i
];
1097 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1103 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
1108 info1
->dns_domain_name
= ldb_dn_canonical_string(mem_ctx
, result
->dn
);
1109 W_ERROR_HAVE_NO_MEMORY(info1
->dns_domain_name
);
1110 p
= strchr(info1
->dns_domain_name
, '/');
1115 /* here we can use result and domain_res[0] */
1116 switch (format_desired
) {
1117 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779
: {
1118 info1
->result_name
= ldb_dn_alloc_linearized(mem_ctx
, result
->dn
);
1119 W_ERROR_HAVE_NO_MEMORY(info1
->result_name
);
1121 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1124 case DRSUAPI_DS_NAME_FORMAT_CANONICAL
: {
1125 info1
->result_name
= ldb_msg_find_attr_as_string(result
, "canonicalName", NULL
);
1126 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1129 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
: {
1130 /* Not in the virtual ldb attribute */
1131 return DsCrackNameOneSyntactical(mem_ctx
,
1132 DRSUAPI_DS_NAME_FORMAT_FQDN_1779
,
1133 DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
,
1134 result
->dn
, name
, info1
);
1136 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
: {
1138 const struct dom_sid
*sid
= samdb_result_dom_sid(mem_ctx
, result
, "objectSid");
1139 const char *_acc
= "", *_dom
= "";
1141 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_MAPPING
;
1145 if (samdb_find_attribute(sam_ctx
, result
, "objectClass",
1147 /* This can also find a DomainDNSZones entry,
1148 * but it won't have the SID we just
1150 ldb_ret
= ldb_search(sam_ctx
, mem_ctx
, &domain_res
,
1154 "(ncName=%s)", ldb_dn_get_linearized(result
->dn
));
1156 if (ldb_ret
!= LDB_SUCCESS
) {
1157 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx
)));
1158 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
1162 switch (domain_res
->count
) {
1166 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1169 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
1172 _dom
= ldb_msg_find_attr_as_string(domain_res
->msgs
[0], "nETBIOSName", NULL
);
1173 W_ERROR_HAVE_NO_MEMORY(_dom
);
1175 _acc
= ldb_msg_find_attr_as_string(result
, "sAMAccountName", NULL
);
1177 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_MAPPING
;
1180 if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx
, SID_BUILTIN
), sid
)) {
1183 const char *attrs
[] = { NULL
};
1184 struct ldb_result
*domain_res2
;
1185 struct dom_sid
*dom_sid
= dom_sid_dup(mem_ctx
, sid
);
1189 dom_sid
->num_auths
--;
1190 ldb_ret
= ldb_search(sam_ctx
, mem_ctx
, &domain_res
,
1194 "(&(objectSid=%s)(objectClass=domain))",
1195 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid
));
1197 if (ldb_ret
!= LDB_SUCCESS
) {
1198 DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s\n", ldb_errstring(sam_ctx
)));
1199 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
1203 switch (domain_res
->count
) {
1207 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1210 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
1214 ldb_ret
= ldb_search(sam_ctx
, mem_ctx
, &domain_res2
,
1218 "(ncName=%s)", ldb_dn_get_linearized(domain_res
->msgs
[0]->dn
));
1220 if (ldb_ret
!= LDB_SUCCESS
) {
1221 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx
)));
1222 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
1226 switch (domain_res2
->count
) {
1230 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1233 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
1236 _dom
= ldb_msg_find_attr_as_string(domain_res2
->msgs
[0], "nETBIOSName", NULL
);
1237 W_ERROR_HAVE_NO_MEMORY(_dom
);
1241 info1
->result_name
= talloc_asprintf(mem_ctx
, "%s\\%s", _dom
, _acc
);
1242 W_ERROR_HAVE_NO_MEMORY(info1
->result_name
);
1244 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1247 case DRSUAPI_DS_NAME_FORMAT_GUID
: {
1250 guid
= samdb_result_guid(result
, "objectGUID");
1252 info1
->result_name
= GUID_string2(mem_ctx
, &guid
);
1253 W_ERROR_HAVE_NO_MEMORY(info1
->result_name
);
1255 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1258 case DRSUAPI_DS_NAME_FORMAT_DISPLAY
: {
1259 info1
->result_name
= ldb_msg_find_attr_as_string(result
, "displayName", NULL
);
1260 if (!info1
->result_name
) {
1261 info1
->result_name
= ldb_msg_find_attr_as_string(result
, "sAMAccountName", NULL
);
1263 if (!info1
->result_name
) {
1264 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1266 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1270 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL
: {
1271 struct ldb_message_element
*el
1272 = ldb_msg_find_element(result
,
1273 "servicePrincipalName");
1275 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1277 } else if (el
->num_values
> 1) {
1278 info1
->status
= DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
;
1282 info1
->result_name
= ldb_msg_find_attr_as_string(result
, "servicePrincipalName", NULL
);
1283 if (!info1
->result_name
) {
1284 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_MAPPING
;
1286 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1290 case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN
: {
1291 info1
->dns_domain_name
= NULL
;
1292 info1
->status
= DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
;
1295 case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY
: {
1296 const struct dom_sid
*sid
= samdb_result_dom_sid(mem_ctx
, result
, "objectSid");
1299 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_MAPPING
;
1303 info1
->result_name
= dom_sid_string(mem_ctx
, sid
);
1304 W_ERROR_HAVE_NO_MEMORY(info1
->result_name
);
1306 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1309 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL
: {
1310 info1
->result_name
= ldb_msg_find_attr_as_string(result
, "userPrincipalName", NULL
);
1311 if (!info1
->result_name
) {
1312 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_MAPPING
;
1314 info1
->status
= DRSUAPI_DS_NAME_STATUS_OK
;
1319 info1
->status
= DRSUAPI_DS_NAME_STATUS_NO_MAPPING
;
1324 /* Given a user Principal Name (such as foo@bar.com),
1325 * return the user and domain DNs. This is used in the KDC to then
1326 * return the Keys and evaluate policy */
1328 NTSTATUS
crack_user_principal_name(struct ldb_context
*sam_ctx
,
1329 TALLOC_CTX
*mem_ctx
,
1330 const char *user_principal_name
,
1331 struct ldb_dn
**user_dn
,
1332 struct ldb_dn
**domain_dn
)
1335 struct drsuapi_DsNameInfo1 info1
;
1336 werr
= DsCrackNameOneName(sam_ctx
, mem_ctx
, 0,
1337 DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL
,
1338 DRSUAPI_DS_NAME_FORMAT_FQDN_1779
,
1339 user_principal_name
,
1341 if (!W_ERROR_IS_OK(werr
)) {
1342 return werror_to_ntstatus(werr
);
1344 switch (info1
.status
) {
1345 case DRSUAPI_DS_NAME_STATUS_OK
:
1347 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND
:
1348 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
:
1349 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
:
1350 return NT_STATUS_NO_SUCH_USER
;
1351 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
:
1353 return NT_STATUS_UNSUCCESSFUL
;
1356 *user_dn
= ldb_dn_new(mem_ctx
, sam_ctx
, info1
.result_name
);
1359 werr
= DsCrackNameOneName(sam_ctx
, mem_ctx
, 0,
1360 DRSUAPI_DS_NAME_FORMAT_CANONICAL
,
1361 DRSUAPI_DS_NAME_FORMAT_FQDN_1779
,
1362 talloc_asprintf(mem_ctx
, "%s/",
1363 info1
.dns_domain_name
),
1365 if (!W_ERROR_IS_OK(werr
)) {
1366 return werror_to_ntstatus(werr
);
1368 switch (info1
.status
) {
1369 case DRSUAPI_DS_NAME_STATUS_OK
:
1371 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND
:
1372 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
:
1373 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
:
1374 return NT_STATUS_NO_SUCH_USER
;
1375 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
:
1377 return NT_STATUS_UNSUCCESSFUL
;
1380 *domain_dn
= ldb_dn_new(mem_ctx
, sam_ctx
, info1
.result_name
);
1383 return NT_STATUS_OK
;
1386 /* Given a Service Principal Name (such as host/foo.bar.com@BAR.COM),
1387 * return the user and domain DNs. This is used in the KDC to then
1388 * return the Keys and evaluate policy */
1390 NTSTATUS
crack_service_principal_name(struct ldb_context
*sam_ctx
,
1391 TALLOC_CTX
*mem_ctx
,
1392 const char *service_principal_name
,
1393 struct ldb_dn
**user_dn
,
1394 struct ldb_dn
**domain_dn
)
1397 struct drsuapi_DsNameInfo1 info1
;
1398 werr
= DsCrackNameOneName(sam_ctx
, mem_ctx
, 0,
1399 DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL
,
1400 DRSUAPI_DS_NAME_FORMAT_FQDN_1779
,
1401 service_principal_name
,
1403 if (!W_ERROR_IS_OK(werr
)) {
1404 return werror_to_ntstatus(werr
);
1406 switch (info1
.status
) {
1407 case DRSUAPI_DS_NAME_STATUS_OK
:
1409 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND
:
1410 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
:
1411 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
:
1412 return NT_STATUS_NO_SUCH_USER
;
1413 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
:
1415 return NT_STATUS_UNSUCCESSFUL
;
1418 *user_dn
= ldb_dn_new(mem_ctx
, sam_ctx
, info1
.result_name
);
1421 werr
= DsCrackNameOneName(sam_ctx
, mem_ctx
, 0,
1422 DRSUAPI_DS_NAME_FORMAT_CANONICAL
,
1423 DRSUAPI_DS_NAME_FORMAT_FQDN_1779
,
1424 talloc_asprintf(mem_ctx
, "%s/",
1425 info1
.dns_domain_name
),
1427 if (!W_ERROR_IS_OK(werr
)) {
1428 return werror_to_ntstatus(werr
);
1430 switch (info1
.status
) {
1431 case DRSUAPI_DS_NAME_STATUS_OK
:
1433 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND
:
1434 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
:
1435 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
:
1436 return NT_STATUS_NO_SUCH_USER
;
1437 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
:
1439 return NT_STATUS_UNSUCCESSFUL
;
1442 *domain_dn
= ldb_dn_new(mem_ctx
, sam_ctx
, info1
.result_name
);
1445 return NT_STATUS_OK
;
1448 NTSTATUS
crack_name_to_nt4_name(TALLOC_CTX
*mem_ctx
,
1449 struct ldb_context
*ldb
,
1450 enum drsuapi_DsNameFormat format_offered
,
1452 const char **nt4_domain
, const char **nt4_account
)
1455 struct drsuapi_DsNameInfo1 info1
;
1458 /* Handle anonymous bind */
1459 if (!name
|| !*name
) {
1462 return NT_STATUS_OK
;
1465 werr
= DsCrackNameOneName(ldb
, mem_ctx
, 0,
1467 DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
,
1470 if (!W_ERROR_IS_OK(werr
)) {
1471 return werror_to_ntstatus(werr
);
1473 switch (info1
.status
) {
1474 case DRSUAPI_DS_NAME_STATUS_OK
:
1476 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND
:
1477 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
:
1478 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
:
1479 return NT_STATUS_NO_SUCH_USER
;
1480 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR
:
1482 return NT_STATUS_UNSUCCESSFUL
;
1485 *nt4_domain
= talloc_strdup(mem_ctx
, info1
.result_name
);
1486 if (*nt4_domain
== NULL
) {
1487 return NT_STATUS_NO_MEMORY
;
1490 p
= strchr(*nt4_domain
, '\\');
1492 return NT_STATUS_INVALID_PARAMETER
;
1496 *nt4_account
= talloc_strdup(mem_ctx
, &p
[1]);
1497 if (*nt4_account
== NULL
) {
1498 return NT_STATUS_NO_MEMORY
;
1501 return NT_STATUS_OK
;
1504 NTSTATUS
crack_auto_name_to_nt4_name(TALLOC_CTX
*mem_ctx
,
1505 struct ldb_context
*ldb
,
1507 const char **nt4_domain
,
1508 const char **nt4_account
)
1510 enum drsuapi_DsNameFormat format_offered
= DRSUAPI_DS_NAME_FORMAT_UNKNOWN
;
1512 /* Handle anonymous bind */
1513 if (!name
|| !*name
) {
1516 return NT_STATUS_OK
;
1520 * Here we only consider a subset of the possible name forms listed in
1521 * [MS-ADTS] 5.1.1.1.1, and we don't retry with a different name form if
1522 * the first attempt fails.
1525 if (strchr_m(name
, '=')) {
1526 format_offered
= DRSUAPI_DS_NAME_FORMAT_FQDN_1779
;
1527 } else if (strchr_m(name
, '@')) {
1528 format_offered
= DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL
;
1529 } else if (strchr_m(name
, '\\')) {
1530 format_offered
= DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT
;
1531 } else if (strchr_m(name
, '\n')) {
1532 format_offered
= DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
;
1533 } else if (strchr_m(name
, '/')) {
1534 format_offered
= DRSUAPI_DS_NAME_FORMAT_CANONICAL
;
1535 } else if ((name
[0] == 'S' || name
[0] == 's') && name
[1] == '-') {
1536 format_offered
= DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY
;
1538 return NT_STATUS_NO_SUCH_USER
;
1541 return crack_name_to_nt4_name(mem_ctx
, ldb
, format_offered
, name
, nt4_domain
, nt4_account
);
1545 WERROR
dcesrv_drsuapi_ListRoles(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
1546 const struct drsuapi_DsNameRequest1
*req1
,
1547 struct drsuapi_DsNameCtr1
**ctr1
)
1549 struct drsuapi_DsNameInfo1
*names
;
1551 uint32_t count
= 5;/*number of fsmo role owners we are going to return*/
1553 *ctr1
= talloc(mem_ctx
, struct drsuapi_DsNameCtr1
);
1554 W_ERROR_HAVE_NO_MEMORY(*ctr1
);
1555 names
= talloc_array(mem_ctx
, struct drsuapi_DsNameInfo1
, count
);
1556 W_ERROR_HAVE_NO_MEMORY(names
);
1558 for (i
= 0; i
< count
; i
++) {
1560 struct ldb_dn
*role_owner_dn
, *fsmo_role_dn
, *server_dn
;
1561 werr
= dsdb_get_fsmo_role_info(mem_ctx
, sam_ctx
, i
,
1562 &fsmo_role_dn
, &role_owner_dn
);
1563 if(!W_ERROR_IS_OK(werr
)) {
1566 server_dn
= ldb_dn_copy(mem_ctx
, role_owner_dn
);
1567 ldb_dn_remove_child_components(server_dn
, 1);
1568 names
[i
].status
= DRSUAPI_DS_NAME_STATUS_OK
;
1569 names
[i
].dns_domain_name
= samdb_dn_to_dnshostname(sam_ctx
, mem_ctx
,
1571 if(!names
[i
].dns_domain_name
) {
1572 DEBUG(4, ("list_roles: Failed to find dNSHostName for server %s\n",
1573 ldb_dn_get_linearized(server_dn
)));
1575 names
[i
].result_name
= talloc_strdup(mem_ctx
, ldb_dn_get_linearized(role_owner_dn
));
1578 (*ctr1
)->count
= count
;
1579 (*ctr1
)->array
= names
;
1584 WERROR
dcesrv_drsuapi_CrackNamesByNameFormat(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
1585 const struct drsuapi_DsNameRequest1
*req1
,
1586 struct drsuapi_DsNameCtr1
**ctr1
)
1588 struct drsuapi_DsNameInfo1
*names
;
1592 *ctr1
= talloc_zero(mem_ctx
, struct drsuapi_DsNameCtr1
);
1593 W_ERROR_HAVE_NO_MEMORY(*ctr1
);
1595 count
= req1
->count
;
1596 names
= talloc_array(mem_ctx
, struct drsuapi_DsNameInfo1
, count
);
1597 W_ERROR_HAVE_NO_MEMORY(names
);
1599 for (i
=0; i
< count
; i
++) {
1600 status
= DsCrackNameOneName(sam_ctx
, mem_ctx
,
1602 req1
->format_offered
,
1603 req1
->format_desired
,
1606 if (!W_ERROR_IS_OK(status
)) {
1611 (*ctr1
)->count
= count
;
1612 (*ctr1
)->array
= names
;
1617 WERROR
dcesrv_drsuapi_ListInfoServer(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
1618 const struct drsuapi_DsNameRequest1
*req1
,
1619 struct drsuapi_DsNameCtr1
**_ctr1
)
1621 struct drsuapi_DsNameInfo1
*names
;
1622 struct ldb_result
*res
;
1623 struct ldb_dn
*server_dn
, *dn
;
1624 struct drsuapi_DsNameCtr1
*ctr1
;
1627 const char *attrs
[] = {
1636 ctr1
= talloc_zero(mem_ctx
, struct drsuapi_DsNameCtr1
);
1637 W_ERROR_HAVE_NO_MEMORY(ctr1
);
1640 * No magic value here, we have to return 3 entries according to the
1644 names
= talloc_zero_array(ctr1
, struct drsuapi_DsNameInfo1
,
1646 W_ERROR_HAVE_NO_MEMORY(names
);
1647 ctr1
->array
= names
;
1649 for (i
=0; i
< ctr1
->count
; i
++) {
1650 names
[i
].status
= DRSUAPI_DS_NAME_STATUS_NOT_FOUND
;
1654 if (req1
->count
!= 1) {
1655 DEBUG(1, ("Expected a count of 1 for the ListInfoServer crackname \n"));
1659 if (req1
->names
[0].str
== NULL
) {
1663 server_dn
= ldb_dn_new(mem_ctx
, sam_ctx
, req1
->names
[0].str
);
1664 W_ERROR_HAVE_NO_MEMORY(server_dn
);
1666 ret
= ldb_search(sam_ctx
, mem_ctx
, &res
, server_dn
, LDB_SCOPE_ONELEVEL
,
1667 NULL
, "(objectClass=nTDSDSA)");
1669 if (ret
!= LDB_SUCCESS
) {
1670 DEBUG(1, ("Search for objectClass=nTDSDSA "
1671 "returned less than 1 objects\n"));
1675 if (res
->count
!= 1) {
1676 DEBUG(1, ("Search for objectClass=nTDSDSA "
1677 "returned less than 1 objects\n"));
1681 if (res
->msgs
[0]->dn
) {
1682 names
[0].result_name
= ldb_dn_alloc_linearized(names
, res
->msgs
[0]->dn
);
1683 W_ERROR_HAVE_NO_MEMORY(names
[0].result_name
);
1684 names
[0].status
= DRSUAPI_DS_NAME_STATUS_OK
;
1689 ret
= ldb_search(sam_ctx
, mem_ctx
, &res
, server_dn
, LDB_SCOPE_BASE
,
1690 attrs
, "(objectClass=*)");
1691 if (ret
!= LDB_SUCCESS
) {
1692 DEBUG(1, ("Search for objectClass=* on dn %s"
1693 "returned %s\n", req1
->names
[0].str
,
1694 ldb_strerror(ret
)));
1698 if (res
->count
!= 1) {
1699 DEBUG(1, ("Search for objectClass=* on dn %s"
1700 "returned less than 1 objects\n", req1
->names
[0].str
));
1704 str
= ldb_msg_find_attr_as_string(res
->msgs
[0], "dNSHostName", NULL
);
1706 names
[1].result_name
= talloc_strdup(names
, str
);
1707 W_ERROR_HAVE_NO_MEMORY(names
[1].result_name
);
1708 names
[1].status
= DRSUAPI_DS_NAME_STATUS_OK
;
1711 dn
= ldb_msg_find_attr_as_dn(sam_ctx
, mem_ctx
, res
->msgs
[0], "serverReference");
1713 names
[2].result_name
= ldb_dn_alloc_linearized(names
, dn
);
1714 W_ERROR_HAVE_NO_MEMORY(names
[2].result_name
);
1715 names
[2].status
= DRSUAPI_DS_NAME_STATUS_OK
;