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