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