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