52f5e4164208d0953b9fadd0aa36611f0d5030cf
[samba.git] / source4 / dsdb / samdb / cracknames.c
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 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         krb5_error_code ret;
60         krb5_principal principal;
61         /* perhaps it's a principal with a realm, so return the right 'domain only' response */
62         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
63                                     KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
64         if (ret) {
65                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
66                 return WERR_OK;
67         }
68
69         info1->dns_domain_name = smb_krb5_principal_get_realm(
70                 mem_ctx, smb_krb5_context->krb5_context, principal);
71         krb5_free_principal(smb_krb5_context->krb5_context, principal);
72
73         W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
74
75         info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
76         return WERR_OK;
77 }
78
79 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         unsigned int i;
91         int ret;
92         struct ldb_result *res;
93         struct ldb_message_element *spnmappings;
94         TALLOC_CTX *tmp_ctx;
95         struct ldb_dn *service_dn;
96         char *service_dn_str;
97
98         const char *directory_attrs[] = {
99                 "sPNMappings", 
100                 NULL
101         };
102
103         tmp_ctx = talloc_new(mem_ctx);
104         if (!tmp_ctx) {
105                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
106         }
107
108         service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services");
109         if ( ! ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb_ctx))) {
110                 talloc_free(tmp_ctx);
111                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
112         }
113         service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn);
114         if ( ! service_dn_str) {
115                 talloc_free(tmp_ctx);
116                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
117         }
118
119         ret = ldb_search(ldb_ctx, tmp_ctx, &res, service_dn, LDB_SCOPE_BASE,
120                          directory_attrs, "(objectClass=nTDSService)");
121
122         if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
123                 DEBUG(1, ("ldb_search: dn: %s not found: %s\n", service_dn_str, ldb_errstring(ldb_ctx)));
124                 talloc_free(tmp_ctx);
125                 return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
126         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
127                 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
128                 talloc_free(tmp_ctx);
129                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
130         } else if (res->count != 1) {
131                 DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
132                 talloc_free(tmp_ctx);
133                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
134         }
135
136         spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings");
137         if (!spnmappings || spnmappings->num_values == 0) {
138                 DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute\n", service_dn_str));
139                 talloc_free(tmp_ctx);
140                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
141         }
142
143         for (i = 0; i < spnmappings->num_values; i++) {
144                 char *mapping, *p, *str;
145                 mapping = talloc_strdup(tmp_ctx, 
146                                         (const char *)spnmappings->values[i].data);
147                 if (!mapping) {
148                         DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));
149                         talloc_free(tmp_ctx);
150                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
151                 }
152
153                 /* C string manipulation sucks */
154
155                 p = strchr(mapping, '=');
156                 if (!p) {
157                         DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n", 
158                                   service_dn_str, mapping));
159                         talloc_free(tmp_ctx);
160                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
161                 }
162                 p[0] = '\0';
163                 p++;
164                 do {
165                         str = p;
166                         p = strchr(p, ',');
167                         if (p) {
168                                 p[0] = '\0';
169                                 p++;
170                         }
171                         if (strcasecmp(str, alias_from) == 0) {
172                                 *alias_to = mapping;
173                                 talloc_steal(mem_ctx, mapping);
174                                 talloc_free(tmp_ctx);
175                                 return DRSUAPI_DS_NAME_STATUS_OK;
176                         }
177                 } while (p);
178         }
179         DEBUG(4, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
180         talloc_free(tmp_ctx);
181         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
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 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         WERROR wret;
196         krb5_error_code ret;
197         krb5_principal principal;
198         krb5_data component;
199         const char *service, *dns_name;
200         char *new_service;
201         char *new_princ;
202         enum drsuapi_DsNameStatus namestatus;
203
204         /* parse principal */
205         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
206                                     name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
207         if (ret) {
208                 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                 return WERR_NOT_ENOUGH_MEMORY;
212         }
213
214         /* grab cifs/, http/ etc */
215
216         ret = smb_krb5_princ_component(smb_krb5_context->krb5_context,
217                                        principal, 0, &component);
218         if (ret) {
219                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
220                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
221                 return WERR_OK;
222         }
223         service = (const char *)component.data;
224         ret = smb_krb5_princ_component(smb_krb5_context->krb5_context,
225                                        principal, 1, &component);
226         if (ret) {
227                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
228                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
229                 return WERR_OK;
230         }
231         dns_name = (const char *)component.data;
232
233         /* MAP it */
234         namestatus = LDB_lookup_spn_alias(sam_ctx, mem_ctx,
235                                           service, &new_service);
236
237         if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
238                 wret = WERR_OK;
239                 info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
240                 info1->dns_domain_name  = talloc_strdup(mem_ctx, dns_name);
241                 if (!info1->dns_domain_name) {
242                         wret = WERR_NOT_ENOUGH_MEMORY;
243                 }
244                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
245                 return wret;
246         } else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
247                 info1->status = namestatus;
248                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
249                 return WERR_OK;
250         }
251
252         /* reform principal */
253         new_princ = talloc_asprintf(mem_ctx, "%s/%s", new_service, dns_name);
254         if (!new_princ) {
255                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
256                 return WERR_NOT_ENOUGH_MEMORY;
257         }
258
259         wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
260                                   new_princ, info1);
261         talloc_free(new_princ);
262         if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) {
263                 info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
264                 info1->dns_domain_name  = talloc_strdup(mem_ctx, dns_name);
265                 if (!info1->dns_domain_name) {
266                         wret = WERR_NOT_ENOUGH_MEMORY;
267                 }
268         }
269         krb5_free_principal(smb_krb5_context->krb5_context, principal);
270         return wret;
271 }
272
273 /* Subcase of CrackNames, for the userPrincipalName */
274
275 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         int ldb_ret;
282         WERROR status;
283         const char *domain_filter = NULL;
284         const char *result_filter = NULL;
285         krb5_error_code ret;
286         krb5_principal principal;
287         char *realm;
288         char *realm_encoded = NULL;
289         char *unparsed_name_short;
290         const char *unparsed_name_short_encoded = NULL;
291         const char *domain_attrs[] = { NULL };
292         struct ldb_result *domain_res = NULL;
293
294         /* Prevent recursion */
295         if (!name) {
296                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
297                 return WERR_OK;
298         }
299
300         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
301                                     KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
302         if (ret) {
303                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
304                 return WERR_OK;
305         }
306
307         realm = smb_krb5_principal_get_realm(
308                 mem_ctx, smb_krb5_context->krb5_context, principal);
309         if (realm == NULL) {
310                 return WERR_NOT_ENOUGH_MEMORY;
311         }
312
313         realm_encoded = ldb_binary_encode_string(mem_ctx, realm);
314         if (realm_encoded == NULL) {
315                 return WERR_NOT_ENOUGH_MEMORY;
316         }
317
318         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         TALLOC_FREE(realm_encoded);
328         TALLOC_FREE(realm);
329
330         if (ldb_ret != LDB_SUCCESS) {
331                 DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
332                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
333                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
334                 return WERR_OK;
335         }
336
337         switch (domain_res->count) {
338         case 1:
339                 break;
340         case 0:
341                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
342                 return dns_domain_from_principal(mem_ctx, smb_krb5_context, 
343                                                  name, info1);
344         default:
345                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
346                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
347                 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         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         krb5_free_principal(smb_krb5_context->krb5_context, principal);
361
362         if (ret) {
363                 free(unparsed_name_short);
364                 return WERR_NOT_ENOUGH_MEMORY;
365         }
366
367         unparsed_name_short_encoded = ldb_binary_encode_string(mem_ctx, unparsed_name_short);
368         if (unparsed_name_short_encoded == NULL) {
369                 free(unparsed_name_short);
370                 return WERR_NOT_ENOUGH_MEMORY;
371         }
372
373         /* This may need to be extended for more userPrincipalName variations */
374         result_filter = talloc_asprintf(mem_ctx, "(&(samAccountName=%s)(objectClass=user))",
375                                         unparsed_name_short_encoded);
376
377         domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
378
379         if (!result_filter || !domain_filter) {
380                 free(unparsed_name_short);
381                 return WERR_NOT_ENOUGH_MEMORY;
382         }
383         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         free(unparsed_name_short);
389
390         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 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         struct ldb_result *domain_res = NULL;
409         const char * const domain_attrs[] = {"ncName", NULL};
410         struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
411         int ldb_ret;
412         char *account,  *s, *result_filter = NULL;
413         struct ldb_dn *search_dn = NULL;
414
415         *psearch_dn = NULL;
416         *presult_filter = NULL;
417
418         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         if (ldb_ret != LDB_SUCCESS) {
425                 DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
426                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
427                 return WERR_FOOBAR;
428         }
429
430         if (domain_res->count == 1) {
431                 struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
432                 const char * const name_attrs[] = {"name", NULL};
433
434                 account = name;
435                 s = strchr(account, '/');
436                 talloc_free(domain_res);
437                 while(s) {
438                         s[0] = '\0';
439                         s++;
440
441                         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                         if (ldb_ret != LDB_SUCCESS) {
448                                 DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
449                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
450                                 return WERR_OK;
451                         }
452                         talloc_free(tmp_dn);
453                         switch (domain_res->count) {
454                         case 1:
455                                 break;
456                         case 0:
457                                 talloc_free(domain_res);
458                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
459                                 return WERR_OK;
460                         default:
461                                 talloc_free(domain_res);
462                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
463                                 return WERR_OK;
464                         }
465
466                         tmp_dn = talloc_steal(mem_ctx, domain_res->msgs[0]->dn);
467                         talloc_free(domain_res);
468                         search_dn = tmp_dn;
469                         account = s;
470                         s = strchr(account, '/');
471                 }
472                 account = ldb_binary_encode_string(mem_ctx, account);
473                 W_ERROR_HAVE_NO_MEMORY(account);
474                 result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
475                                                 account);
476                 W_ERROR_HAVE_NO_MEMORY(result_filter);
477         }
478         *psearch_dn = search_dn;
479         *presult_filter = result_filter;
480         return WERR_OK;
481 }
482
483 /* Crack a single 'name', from format_offered into format_desired, returning the result in info1 */
484
485 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         krb5_error_code ret;
491         const char *domain_filter = NULL;
492         const char *result_filter = NULL;
493         struct ldb_dn *name_dn = NULL;
494         struct ldb_dn *search_dn = NULL;
495
496         struct smb_krb5_context *smb_krb5_context = NULL;
497         int scope = LDB_SCOPE_SUBTREE;
498
499         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
500         info1->dns_domain_name = NULL;
501         info1->result_name = NULL;
502
503         if (!name) {
504                 return WERR_INVALID_PARAMETER;
505         }
506
507         /* TODO: - fill the correct names in all cases!
508          *       - handle format_flags
509          */
510         if (format_desired == DRSUAPI_DS_NAME_FORMAT_UNKNOWN) {
511                 return WERR_OK;
512         }
513         /* here we need to set the domain_filter and/or the result_filter */
514         switch (format_offered) {
515         case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
516         {
517                 unsigned int i;
518                 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                 WERROR werr;
527                 for (i=0; i < ARRAY_SIZE(formats); i++) {
528                         werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
529                         if (!W_ERROR_IS_OK(werr)) {
530                                 return werr;
531                         }
532                         if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND &&
533                             (formats[i] != DRSUAPI_DS_NAME_FORMAT_CANONICAL ||
534                              info1->status != DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR))
535                         {
536                                 return werr;
537                         }
538                 }
539                 return werr;
540         }
541
542         case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
543         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
544         {
545                 char *str, *s, *account;
546                 const char *str_encoded = NULL;
547                 scope = LDB_SCOPE_ONELEVEL;
548
549                 if (strlen(name) == 0) {
550                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
551                         return WERR_OK;
552                 }
553
554                 str = talloc_strdup(mem_ctx, name);
555                 W_ERROR_HAVE_NO_MEMORY(str);
556
557                 if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
558                         /* Look backwards for the \n, and replace it with / */
559                         s = strrchr(str, '\n');
560                         if (!s) {
561                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
562                                 return WERR_OK;
563                         }
564                         s[0] = '/';
565                 }
566
567                 s = strchr(str, '/');
568                 if (!s) {
569                         /* there must be at least one / */
570                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
571                         return WERR_OK;
572                 }
573
574                 s[0] = '\0';
575                 s++;
576
577                 str_encoded = ldb_binary_encode_string(mem_ctx, str);
578                 if (str_encoded == NULL) {
579                         return WERR_NOT_ENOUGH_MEMORY;
580                 }
581
582                 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                 W_ERROR_HAVE_NO_MEMORY(domain_filter);
587
588                 /* There may not be anything after the domain component (search for the domain itself) */
589                 account = s;
590                 if (account && *account) {
591                         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                         if (!W_ERROR_IS_OK(werr)) {
599                                 return werr;
600                         }
601                         if (info1->status != DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR)
602                                 return WERR_OK;
603                 }
604                 break;
605         }
606         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
607                 char *p;
608                 char *domain;
609                 char *domain_encoded = NULL;
610                 const char *account = NULL;
611
612                 domain = talloc_strdup(mem_ctx, name);
613                 W_ERROR_HAVE_NO_MEMORY(domain);
614
615                 p = strchr(domain, '\\');
616                 if (!p) {
617                         /* invalid input format */
618                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
619                         return WERR_OK;
620                 }
621                 p[0] = '\0';
622
623                 if (p[1]) {
624                         account = &p[1];
625                 }
626
627                 domain_encoded = ldb_binary_encode_string(mem_ctx, domain);
628                 if (domain_encoded == NULL) {
629                         return WERR_NOT_ENOUGH_MEMORY;
630                 }
631
632                 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                 W_ERROR_HAVE_NO_MEMORY(domain_filter);
638                 if (account) {
639                         const char *account_encoded = NULL;
640
641                         account_encoded = ldb_binary_encode_string(mem_ctx, account);
642                         if (account_encoded == NULL) {
643                                 return WERR_NOT_ENOUGH_MEMORY;
644                         }
645
646                         result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
647                                                         account_encoded);
648                         W_ERROR_HAVE_NO_MEMORY(result_filter);
649                 }
650
651                 talloc_free(domain);
652                 break;
653         }
654
655                 /* A LDAP DN as a string */
656         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
657                 domain_filter = NULL;
658                 name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
659                 if (! ldb_dn_validate(name_dn)) {
660                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
661                         return WERR_OK;
662                 }
663                 break;
664         }
665
666                 /* A GUID as a string */
667         case DRSUAPI_DS_NAME_FORMAT_GUID: {
668                 struct GUID guid;
669                 char *ldap_guid;
670                 NTSTATUS nt_status;
671                 domain_filter = NULL;
672
673                 nt_status = GUID_from_string(name, &guid);
674                 if (!NT_STATUS_IS_OK(nt_status)) {
675                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
676                         return WERR_OK;
677                 }
678
679                 ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
680                 if (!ldap_guid) {
681                         return WERR_NOT_ENOUGH_MEMORY;
682                 }
683                 result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
684                                                 ldap_guid);
685                 W_ERROR_HAVE_NO_MEMORY(result_filter);
686                 break;
687         }
688         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
689                 const char *name_encoded = NULL;
690
691                 domain_filter = NULL;
692
693                 name_encoded = ldb_binary_encode_string(mem_ctx, name);
694                 if (name_encoded == NULL) {
695                         return WERR_NOT_ENOUGH_MEMORY;
696                 }
697
698                 result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
699                                                 name_encoded,
700                                                 name_encoded);
701                 W_ERROR_HAVE_NO_MEMORY(result_filter);
702                 break;
703         }
704
705                 /* A S-1234-5678 style string */
706         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
707                 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
708                 char *ldap_sid;
709
710                 domain_filter = NULL;
711                 if (!sid) {
712                         info1->dns_domain_name = NULL;
713                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
714                         return WERR_OK;
715                 }
716                 ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx, 
717                                                    sid);
718                 if (!ldap_sid) {
719                         return WERR_NOT_ENOUGH_MEMORY;
720                 }
721                 result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
722                                                 ldap_sid);
723                 W_ERROR_HAVE_NO_MEMORY(result_filter);
724                 break;
725         }
726         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
727                 krb5_principal principal;
728                 char *unparsed_name;
729                 const char *unparsed_name_encoded = NULL;
730
731                 ret = smb_krb5_init_context(mem_ctx, 
732                                             (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), 
733                                             &smb_krb5_context);
734
735                 if (ret) {
736                         return WERR_NOT_ENOUGH_MEMORY;
737                 }
738
739                 /* Ensure we reject complete junk first */
740                 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
741                 if (ret) {
742                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
743                         return WERR_OK;
744                 }
745
746                 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                 ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context,
757                                               principal,
758                                               KRB5_PRINCIPAL_UNPARSE_DISPLAY,
759                                               &unparsed_name);
760                 if (ret) {
761                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
762                         return WERR_NOT_ENOUGH_MEMORY;
763                 }
764
765                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
766
767                 /* The ldb_binary_encode_string() here avoids LDAP filter injection attacks */
768                 unparsed_name_encoded = ldb_binary_encode_string(mem_ctx, unparsed_name);
769                 if (unparsed_name_encoded == NULL) {
770                         return WERR_NOT_ENOUGH_MEMORY;
771                 }
772
773                 result_filter = talloc_asprintf(mem_ctx, "(&(userPrincipalName=%s)(objectClass=user))",
774                                                 unparsed_name_encoded);
775
776                 free(unparsed_name);
777                 W_ERROR_HAVE_NO_MEMORY(result_filter);
778                 break;
779         }
780         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
781                 krb5_principal principal;
782                 char *unparsed_name_short;
783                 const char *unparsed_name_short_encoded = NULL;
784                 bool principal_is_host = false;
785
786                 ret = smb_krb5_init_context(mem_ctx, 
787                                             (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), 
788                                             &smb_krb5_context);
789
790                 if (ret) {
791                         return WERR_NOT_ENOUGH_MEMORY;
792                 }
793
794                 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
795                 if (ret == 0 &&
796                     krb5_princ_size(smb_krb5_context->krb5_context,
797                                                         principal) < 2) {
798                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
799                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
800                         return WERR_OK;
801                 } else if (ret == 0) {
802                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
803                 }
804                 ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
805                                             KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
806                 if (ret) {
807                         return dns_domain_from_principal(mem_ctx, smb_krb5_context,
808                                                          name, info1);
809                 }
810
811                 domain_filter = NULL;
812
813                 ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
814                                               KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
815                 if (ret) {
816                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
817                         return WERR_NOT_ENOUGH_MEMORY;
818                 }
819
820                 unparsed_name_short_encoded = ldb_binary_encode_string(mem_ctx, unparsed_name_short);
821                 if (unparsed_name_short_encoded == NULL) {
822                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
823                         free(unparsed_name_short);
824                         return WERR_NOT_ENOUGH_MEMORY;
825                 }
826
827                 if ((krb5_princ_size(smb_krb5_context->krb5_context, principal) == 2)) {
828                         krb5_data component;
829
830                         ret = smb_krb5_princ_component(smb_krb5_context->krb5_context,
831                                                        principal, 0, &component);
832                         if (ret) {
833                                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
834                                 free(unparsed_name_short);
835                                 return WERR_INTERNAL_ERROR;
836                         }
837
838                         principal_is_host = strcasecmp(component.data, "host") == 0;
839                 }
840
841                 if (principal_is_host) {
842                         /* the 'cn' attribute is just the leading part of the name */
843                         krb5_data component;
844                         char *computer_name;
845                         const char *computer_name_encoded = NULL;
846                         ret = smb_krb5_princ_component(
847                                 smb_krb5_context->krb5_context,
848                                 principal, 1, &component);
849                         if (ret) {
850                                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
851                                 free(unparsed_name_short);
852                                 return WERR_INTERNAL_ERROR;
853                         }
854                         computer_name = talloc_strndup(mem_ctx, (char *)component.data,
855                                                         strcspn((char *)component.data, "."));
856                         if (computer_name == NULL) {
857                                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
858                                 free(unparsed_name_short);
859                                 return WERR_NOT_ENOUGH_MEMORY;
860                         }
861
862                         computer_name_encoded = ldb_binary_encode_string(mem_ctx, computer_name);
863                         if (computer_name_encoded == NULL) {
864                                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
865                                 free(unparsed_name_short);
866                                 return WERR_NOT_ENOUGH_MEMORY;
867                         }
868
869                         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                         result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))",
874                                                         unparsed_name_short_encoded);
875                 }
876                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
877                 free(unparsed_name_short);
878                 W_ERROR_HAVE_NO_MEMORY(result_filter);
879
880                 break;
881         }
882         default: {
883                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
884                 return WERR_OK;
885         }
886         }
887
888         if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
889                 return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
890                                                  name_dn, name, info1);
891         }
892
893         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 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         char *cracked;
912         if (format_offered != DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
913                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
914                 return WERR_OK;
915         }
916
917         switch (format_desired) {
918         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: 
919                 cracked = ldb_dn_canonical_string(mem_ctx, name_dn);
920                 break;
921         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
922                 cracked = ldb_dn_canonical_ex_string(mem_ctx, name_dn);
923                 break;
924         default:
925                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
926                 return WERR_OK;
927         }
928         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
929         info1->result_name      = cracked;
930         if (!cracked) {
931                 return WERR_NOT_ENOUGH_MEMORY;
932         }
933
934         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 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         int ldb_ret;
954         struct ldb_result *domain_res = NULL;
955         const char * const *domain_attrs;
956         const char * const *result_attrs;
957         struct ldb_message **result_res = NULL;
958         struct ldb_message *result = NULL;
959         int i;
960         char *p;
961         struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
962
963         const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
964         const char * const _result_attrs_null[] = { NULL };
965
966         const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
967         const char * const _result_attrs_canonical[] = { "canonicalName", NULL };
968
969         const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
970         const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};
971
972         const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
973         const char * const _result_attrs_guid[] = { "objectGUID", NULL};
974
975         const char * const _domain_attrs_upn[] = { "ncName", "dnsRoot", NULL};
976         const char * const _result_attrs_upn[] = { "userPrincipalName", NULL};
977
978         const char * const _domain_attrs_spn[] = { "ncName", "dnsRoot", NULL};
979         const char * const _result_attrs_spn[] = { "servicePrincipalName", NULL};
980
981         const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
982         const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};
983
984         const char * const _domain_attrs_sid[] = { "ncName", "dnsRoot", NULL};
985         const char * const _result_attrs_sid[] = { "objectSid", NULL};
986
987         const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
988         const char * const _result_attrs_none[] = { NULL};
989
990         /* here we need to set the attrs lists for domain and result lookups */
991         switch (format_desired) {
992         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
993         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
994                 domain_attrs = _domain_attrs_1779;
995                 result_attrs = _result_attrs_null;
996                 break;
997         case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
998                 domain_attrs = _domain_attrs_canonical;
999                 result_attrs = _result_attrs_canonical;
1000                 break;
1001         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
1002                 domain_attrs = _domain_attrs_nt4;
1003                 result_attrs = _result_attrs_nt4;
1004                 break;
1005         case DRSUAPI_DS_NAME_FORMAT_GUID:               
1006                 domain_attrs = _domain_attrs_guid;
1007                 result_attrs = _result_attrs_guid;
1008                 break;
1009         case DRSUAPI_DS_NAME_FORMAT_DISPLAY:            
1010                 domain_attrs = _domain_attrs_display;
1011                 result_attrs = _result_attrs_display;
1012                 break;
1013         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
1014                 domain_attrs = _domain_attrs_upn;
1015                 result_attrs = _result_attrs_upn;
1016                 break;
1017         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
1018                 domain_attrs = _domain_attrs_spn;
1019                 result_attrs = _result_attrs_spn;
1020                 break;
1021         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY:
1022                 domain_attrs = _domain_attrs_sid;
1023                 result_attrs = _result_attrs_sid;
1024                 break;
1025         default:
1026                 domain_attrs = _domain_attrs_none;
1027                 result_attrs = _result_attrs_none;
1028                 break;
1029         }
1030
1031         if (domain_filter) {
1032                 /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
1033                 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                 if (ldb_ret != LDB_SUCCESS) {
1040                         DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
1041                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1042                         return WERR_OK;
1043                 }
1044
1045                 switch (domain_res->count) {
1046                 case 1:
1047                         break;
1048                 case 0:
1049                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1050                         return WERR_OK;
1051                 default:
1052                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1053                         return WERR_OK;
1054                 }
1055
1056                 info1->dns_domain_name  = ldb_msg_find_attr_as_string(domain_res->msgs[0], "dnsRoot", NULL);
1057                 W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
1058                 info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
1059         } else {
1060                 info1->dns_domain_name  = NULL;
1061                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1062         }
1063
1064         if (result_filter) {
1065                 int ret;
1066                 struct ldb_result *res;
1067                 uint32_t dsdb_flags = 0;
1068                 struct ldb_dn *real_search_dn = NULL;
1069                 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                 if (format_flags & DRSUAPI_DS_NAME_FLAG_GCVERIFY ||
1083                     format_offered == DRSUAPI_DS_NAME_FORMAT_GUID)
1084                 {
1085                         dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
1086                 } else if (domain_res) {
1087                         if (!search_dn) {
1088                                 struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
1089                                 real_search_dn = tmp_dn;
1090                         } else {
1091                                 real_search_dn = search_dn;
1092                         }
1093                 } else {
1094                         real_search_dn = ldb_get_default_basedn(sam_ctx);
1095                 }
1096                 if (format_offered == DRSUAPI_DS_NAME_FORMAT_GUID){
1097                          dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
1098                 }
1099                 /* search with the 'phantom root' flag */
1100                 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                 if (ret != LDB_SUCCESS) {
1107                         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                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1112                         return WERR_OK;
1113                 }
1114
1115                 ldb_ret = res->count;
1116                 result_res = res->msgs;
1117         } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
1118                 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
1119                                           result_attrs);
1120         } else if (domain_res) {
1121                 name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
1122                 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
1123                                           result_attrs);
1124         } else {
1125                 /* Can't happen */
1126                 DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not available: This can't happen...\n"));
1127                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1128                 return WERR_OK;
1129         }
1130
1131         switch (ldb_ret) {
1132         case 1:
1133                 result = result_res[0];
1134                 break;
1135         case 0:
1136                 switch (format_offered) {
1137                 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: 
1138                         return DsCrackNameSPNAlias(sam_ctx, mem_ctx, 
1139                                                    smb_krb5_context, 
1140                                                    format_flags, format_offered, format_desired,
1141                                                    name, info1);
1142
1143                 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
1144                         return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context, 
1145                                               format_flags, format_offered, format_desired,
1146                                               name, info1);
1147                 default:
1148                         break;
1149                 }
1150                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1151                 return WERR_OK;
1152         case -1:
1153                 DEBUG(2, ("DsCrackNameOneFilter result search failed: %s\n", ldb_errstring(sam_ctx)));
1154                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1155                 return WERR_OK;
1156         default:
1157                 switch (format_offered) {
1158                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
1159                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
1160                 {
1161                         const char *canonical_name = NULL; /* Not required, but we get warnings... */
1162                         /* We may need to manually filter further */
1163                         for (i = 0; i < ldb_ret; i++) {
1164                                 switch (format_offered) {
1165                                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
1166                                         canonical_name = ldb_dn_canonical_string(mem_ctx, result_res[i]->dn);
1167                                         break;
1168                                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
1169                                         canonical_name = ldb_dn_canonical_ex_string(mem_ctx, result_res[i]->dn);
1170                                         break;
1171                                 default:
1172                                         break;
1173                                 }
1174                                 if (strcasecmp_m(canonical_name, name) == 0) {
1175                                         result = result_res[i];
1176                                         break;
1177                                 }
1178                         }
1179                         if (!result) {
1180                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1181                                 return WERR_OK;
1182                         }
1183                 }
1184                 FALL_THROUGH;
1185                 default:
1186                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1187                         return WERR_OK;
1188                 }
1189         }
1190
1191         info1->dns_domain_name = ldb_dn_canonical_string(mem_ctx, result->dn);
1192         W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
1193         p = strchr(info1->dns_domain_name, '/');
1194         if (p) {
1195                 p[0] = '\0';
1196         }
1197
1198         /* here we can use result and domain_res[0] */
1199         switch (format_desired) {
1200         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
1201                 info1->result_name      = ldb_dn_alloc_linearized(mem_ctx, result->dn);
1202                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
1203
1204                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
1205                 return WERR_OK;
1206         }
1207         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
1208                 info1->result_name      = ldb_msg_find_attr_as_string(result, "canonicalName", NULL);
1209                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
1210                 return WERR_OK;
1211         }
1212         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
1213                 /* Not in the virtual ldb attribute */
1214                 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         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
1220
1221                 const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
1222                 const char *_acc = "", *_dom = "";
1223                 if (sid == NULL) {
1224                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1225                         return WERR_OK;
1226                 }
1227
1228                 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                         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                         if (ldb_ret != LDB_SUCCESS) {
1240                                 DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
1241                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1242                                 return WERR_OK;
1243                         }
1244
1245                         switch (domain_res->count) {
1246                         case 1:
1247                                 break;
1248                         case 0:
1249                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1250                                 return WERR_OK;
1251                         default:
1252                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1253                                 return WERR_OK;
1254                         }
1255                         _dom = ldb_msg_find_attr_as_string(domain_res->msgs[0], "nETBIOSName", NULL);
1256                         W_ERROR_HAVE_NO_MEMORY(_dom);
1257                 } else {
1258                         _acc = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
1259                         if (!_acc) {
1260                                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1261                                 return WERR_OK;
1262                         }
1263                         if (dom_sid_in_domain(&global_sid_Builtin, sid)) {
1264                                 _dom = "BUILTIN";
1265                         } else {
1266                                 const char *attrs[] = { NULL };
1267                                 struct ldb_result *domain_res2;
1268                                 struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
1269                                 if (!dom_sid) {
1270                                         return WERR_OK;
1271                                 }
1272                                 dom_sid->num_auths--;
1273                                 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                                 if (ldb_ret != LDB_SUCCESS) {
1281                                         DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s\n", ldb_errstring(sam_ctx)));
1282                                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1283                                         return WERR_OK;
1284                                 }
1285
1286                                 switch (domain_res->count) {
1287                                 case 1:
1288                                         break;
1289                                 case 0:
1290                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1291                                         return WERR_OK;
1292                                 default:
1293                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1294                                         return WERR_OK;
1295                                 }
1296
1297                                 ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res2,
1298                                                              partitions_basedn,
1299                                                              LDB_SCOPE_ONELEVEL,
1300                                                              domain_attrs,
1301                                                              "(ncName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));
1302
1303                                 if (ldb_ret != LDB_SUCCESS) {
1304                                         DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
1305                                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1306                                         return WERR_OK;
1307                                 }
1308
1309                                 switch (domain_res2->count) {
1310                                 case 1:
1311                                         break;
1312                                 case 0:
1313                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1314                                         return WERR_OK;
1315                                 default:
1316                                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1317                                         return WERR_OK;
1318                                 }
1319                                 _dom = ldb_msg_find_attr_as_string(domain_res2->msgs[0], "nETBIOSName", NULL);
1320                                 W_ERROR_HAVE_NO_MEMORY(_dom);
1321                         }
1322                 }
1323
1324                 info1->result_name      = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
1325                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
1326
1327                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
1328                 return WERR_OK;
1329         }
1330         case DRSUAPI_DS_NAME_FORMAT_GUID: {
1331                 struct GUID guid;
1332
1333                 guid = samdb_result_guid(result, "objectGUID");
1334
1335                 info1->result_name      = GUID_string2(mem_ctx, &guid);
1336                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
1337
1338                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
1339                 return WERR_OK;
1340         }
1341         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
1342                 info1->result_name      = ldb_msg_find_attr_as_string(result, "displayName", NULL);
1343                 if (!info1->result_name) {
1344                         info1->result_name      = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
1345                 } 
1346                 if (!info1->result_name) {
1347                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1348                 } else {
1349                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
1350                 }
1351                 return WERR_OK;
1352         }
1353         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
1354                 struct ldb_message_element *el
1355                         = ldb_msg_find_element(result,
1356                                                "servicePrincipalName");
1357                 if (el == NULL) {
1358                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1359                         return WERR_OK;
1360                 } else if (el->num_values > 1) {
1361                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
1362                         return WERR_OK;
1363                 }
1364
1365                 info1->result_name = ldb_msg_find_attr_as_string(result, "servicePrincipalName", NULL);
1366                 if (!info1->result_name) {
1367                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1368                 } else {
1369                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
1370                 }
1371                 return WERR_OK;
1372         }
1373         case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN: {
1374                 info1->dns_domain_name = NULL;
1375                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
1376                 return WERR_OK;
1377         }
1378         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
1379                 const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
1380
1381                 if (sid == NULL) {
1382                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1383                         return WERR_OK;
1384                 }
1385
1386                 info1->result_name = dom_sid_string(mem_ctx, sid);
1387                 W_ERROR_HAVE_NO_MEMORY(info1->result_name);
1388
1389                 info1->status = DRSUAPI_DS_NAME_STATUS_OK;
1390                 return WERR_OK;
1391         }
1392         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
1393                 info1->result_name = ldb_msg_find_attr_as_string(result, "userPrincipalName", NULL);
1394                 if (!info1->result_name) {
1395                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1396                 } else {
1397                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
1398                 }
1399                 return WERR_OK;
1400         }
1401         default:
1402                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
1403                 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 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         WERROR werr;
1418         struct drsuapi_DsNameInfo1 info1;
1419         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         if (!W_ERROR_IS_OK(werr)) {
1425                 return werror_to_ntstatus(werr);
1426         }
1427         switch (info1.status) {
1428         case DRSUAPI_DS_NAME_STATUS_OK:
1429                 break;
1430         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1431         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1432         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1433                 return NT_STATUS_NO_SUCH_USER;
1434         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1435         default:
1436                 return NT_STATUS_UNSUCCESSFUL;
1437         }
1438
1439         *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1440
1441         if (domain_dn) {
1442                 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
1443                                           DRSUAPI_DS_NAME_FORMAT_CANONICAL,
1444                                           DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
1445                                           talloc_asprintf(mem_ctx, "%s/", 
1446                                                           info1.dns_domain_name),
1447                                           &info1);
1448                 if (!W_ERROR_IS_OK(werr)) {
1449                         return werror_to_ntstatus(werr);
1450                 }
1451                 switch (info1.status) {
1452                 case DRSUAPI_DS_NAME_STATUS_OK:
1453                         break;
1454                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1455                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1456                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1457                         return NT_STATUS_NO_SUCH_USER;
1458                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1459                 default:
1460                         return NT_STATUS_UNSUCCESSFUL;
1461                 }
1462
1463                 *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1464         }
1465
1466         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 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         WERROR werr;
1480         struct drsuapi_DsNameInfo1 info1;
1481         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         if (!W_ERROR_IS_OK(werr)) {
1487                 return werror_to_ntstatus(werr);
1488         }
1489         switch (info1.status) {
1490         case DRSUAPI_DS_NAME_STATUS_OK:
1491                 break;
1492         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1493         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1494         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1495                 return NT_STATUS_NO_SUCH_USER;
1496         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1497         default:
1498                 return NT_STATUS_UNSUCCESSFUL;
1499         }
1500
1501         *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1502
1503         if (domain_dn) {
1504                 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
1505                                           DRSUAPI_DS_NAME_FORMAT_CANONICAL,
1506                                           DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
1507                                           talloc_asprintf(mem_ctx, "%s/", 
1508                                                           info1.dns_domain_name),
1509                                           &info1);
1510                 if (!W_ERROR_IS_OK(werr)) {
1511                         return werror_to_ntstatus(werr);
1512                 }
1513                 switch (info1.status) {
1514                 case DRSUAPI_DS_NAME_STATUS_OK:
1515                         break;
1516                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1517                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1518                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1519                         return NT_STATUS_NO_SUCH_USER;
1520                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1521                 default:
1522                         return NT_STATUS_UNSUCCESSFUL;
1523                 }
1524
1525                 *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name);
1526         }
1527
1528         return NT_STATUS_OK;
1529 }
1530
1531 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         WERROR werr;
1538         struct drsuapi_DsNameInfo1 info1;
1539         char *p;
1540
1541         /* Handle anonymous bind */
1542         if (!name || !*name) {
1543                 *nt4_domain = "";
1544                 *nt4_account = "";
1545                 return NT_STATUS_OK;
1546         }
1547
1548         werr = DsCrackNameOneName(ldb, mem_ctx, 0,
1549                                   format_offered, 
1550                                   DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
1551                                   name,
1552                                   &info1);
1553         if (!W_ERROR_IS_OK(werr)) {
1554                 return werror_to_ntstatus(werr);
1555         }
1556         switch (info1.status) {
1557         case DRSUAPI_DS_NAME_STATUS_OK:
1558                 break;
1559         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
1560         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
1561         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
1562                 return NT_STATUS_NO_SUCH_USER;
1563         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
1564         default:
1565                 return NT_STATUS_UNSUCCESSFUL;
1566         }
1567
1568         *nt4_domain = talloc_strdup(mem_ctx, info1.result_name);
1569         if (*nt4_domain == NULL) {
1570                 return NT_STATUS_NO_MEMORY;
1571         }
1572
1573         p = strchr(*nt4_domain, '\\');
1574         if (!p) {
1575                 return NT_STATUS_INVALID_PARAMETER;
1576         }
1577         p[0] = '\0';
1578
1579         *nt4_account = talloc_strdup(mem_ctx, &p[1]);
1580         if (*nt4_account == NULL) {
1581                 return NT_STATUS_NO_MEMORY;
1582         }
1583
1584         return NT_STATUS_OK;
1585 }
1586
1587 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         enum drsuapi_DsNameFormat format_offered = DRSUAPI_DS_NAME_FORMAT_UNKNOWN;
1594
1595         /* Handle anonymous bind */
1596         if (!name || !*name) {
1597                 *nt4_domain = "";
1598                 *nt4_account = "";
1599                 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         if (strchr_m(name, '=')) {
1609                 format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
1610         } else if (strchr_m(name, '@')) {
1611                 format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL;
1612         } else if (strchr_m(name, '\\')) {
1613                 format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
1614         } else if (strchr_m(name, '\n')) {
1615                 format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX;
1616         } else if (strchr_m(name, '/')) {
1617                 format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL;
1618         } else if ((name[0] == 'S' || name[0] == 's') && name[1] == '-') {
1619                 format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
1620         } else {
1621                 return NT_STATUS_NO_SUCH_USER;
1622         }
1623
1624         return crack_name_to_nt4_name(mem_ctx, ldb, format_offered, name, nt4_domain, nt4_account);
1625 }
1626
1627
1628 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         struct drsuapi_DsNameInfo1 *names;
1633         uint32_t i;
1634         uint32_t count = 5;/*number of fsmo role owners we are going to return*/
1635
1636         *ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
1637         W_ERROR_HAVE_NO_MEMORY(*ctr1);
1638         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
1639         W_ERROR_HAVE_NO_MEMORY(names);
1640
1641         for (i = 0; i < count; i++) {
1642                 WERROR werr;
1643                 struct ldb_dn *role_owner_dn, *fsmo_role_dn, *server_dn;
1644                 werr = dsdb_get_fsmo_role_info(mem_ctx, sam_ctx, i,
1645                                                &fsmo_role_dn, &role_owner_dn);
1646                 if(!W_ERROR_IS_OK(werr)) {
1647                         return werr;
1648                 }
1649                 server_dn = ldb_dn_copy(mem_ctx, role_owner_dn);
1650                 ldb_dn_remove_child_components(server_dn, 1);
1651                 names[i].status = DRSUAPI_DS_NAME_STATUS_OK;
1652                 names[i].dns_domain_name = samdb_dn_to_dnshostname(sam_ctx, mem_ctx,
1653                                                                    server_dn);
1654                 if(!names[i].dns_domain_name) {
1655                         DEBUG(4, ("list_roles: Failed to find dNSHostName for server %s\n",
1656                                   ldb_dn_get_linearized(server_dn)));
1657                 }
1658                 names[i].result_name = talloc_strdup(mem_ctx, ldb_dn_get_linearized(role_owner_dn));
1659         }
1660
1661         (*ctr1)->count = count;
1662         (*ctr1)->array = names;
1663
1664         return WERR_OK;
1665 }
1666
1667 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         struct drsuapi_DsNameInfo1 *names;
1672         uint32_t i, count;
1673         WERROR status;
1674
1675         *ctr1 = talloc_zero(mem_ctx, struct drsuapi_DsNameCtr1);
1676         W_ERROR_HAVE_NO_MEMORY(*ctr1);
1677
1678         count = req1->count;
1679         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
1680         W_ERROR_HAVE_NO_MEMORY(names);
1681
1682         for (i=0; i < count; i++) {
1683                 status = DsCrackNameOneName(sam_ctx, mem_ctx,
1684                                             req1->format_flags,
1685                                             req1->format_offered,
1686                                             req1->format_desired,
1687                                             req1->names[i].str,
1688                                             &names[i]);
1689                 if (!W_ERROR_IS_OK(status)) {
1690                         return status;
1691                 }
1692         }
1693
1694         (*ctr1)->count = count;
1695         (*ctr1)->array = names;
1696
1697         return WERR_OK;
1698 }
1699
1700 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         struct drsuapi_DsNameInfo1 *names;
1705         struct ldb_result *res;
1706         struct ldb_dn *server_dn, *dn;
1707         struct drsuapi_DsNameCtr1 *ctr1;
1708         int ret, i;
1709         const char *str;
1710         const char *attrs[] = {
1711                 "dNSHostName",
1712                 "serverReference",
1713                 NULL
1714         };
1715
1716         *_ctr1 = NULL;
1717
1718         ctr1 = talloc_zero(mem_ctx, struct drsuapi_DsNameCtr1);
1719         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         ctr1->count = 3;
1726         names = talloc_zero_array(ctr1, struct drsuapi_DsNameInfo1,
1727                                   ctr1->count);
1728         W_ERROR_HAVE_NO_MEMORY(names);
1729         ctr1->array = names;
1730
1731         for (i=0; i < ctr1->count; i++) {
1732                 names[i].status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
1733         }
1734         *_ctr1 = ctr1;
1735
1736         if (req1->count != 1) {
1737                 DEBUG(1, ("Expected a count of 1 for the ListInfoServer crackname \n"));
1738                 return WERR_OK;
1739         }
1740
1741         if (req1->names[0].str == NULL) {
1742                 return WERR_OK;
1743         }
1744
1745         server_dn = ldb_dn_new(mem_ctx, sam_ctx, req1->names[0].str);
1746         W_ERROR_HAVE_NO_MEMORY(server_dn);
1747
1748         ret = ldb_search(sam_ctx, mem_ctx, &res, server_dn, LDB_SCOPE_ONELEVEL,
1749                          NULL, "(objectClass=nTDSDSA)");
1750
1751         if (ret != LDB_SUCCESS) {
1752                 DEBUG(1, ("Search for objectClass=nTDSDSA "
1753                           "returned less than 1 objects\n"));
1754                 return WERR_OK;
1755         }
1756
1757         if (res->count != 1) {
1758                 DEBUG(1, ("Search for objectClass=nTDSDSA "
1759                           "returned less than 1 objects\n"));
1760                 return WERR_OK;
1761         }
1762
1763         if (res->msgs[0]->dn) {
1764                 names[0].result_name = ldb_dn_alloc_linearized(names, res->msgs[0]->dn);
1765                 W_ERROR_HAVE_NO_MEMORY(names[0].result_name);
1766                 names[0].status = DRSUAPI_DS_NAME_STATUS_OK;
1767         }
1768
1769         talloc_free(res);
1770
1771         ret = ldb_search(sam_ctx, mem_ctx, &res, server_dn, LDB_SCOPE_BASE,
1772                          attrs, "(objectClass=*)");
1773         if (ret != LDB_SUCCESS) {
1774                 DEBUG(1, ("Search for objectClass=* on dn %s"
1775                           "returned %s\n", req1->names[0].str,
1776                           ldb_strerror(ret)));
1777                 return WERR_OK;
1778         }
1779
1780         if (res->count != 1) {
1781                 DEBUG(1, ("Search for objectClass=* on dn %s"
1782                           "returned less than 1 objects\n", req1->names[0].str));
1783                 return WERR_OK;
1784         }
1785
1786         str = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
1787         if (str != NULL) {
1788                 names[1].result_name = talloc_strdup(names, str);
1789                 W_ERROR_HAVE_NO_MEMORY(names[1].result_name);
1790                 names[1].status = DRSUAPI_DS_NAME_STATUS_OK;
1791         }
1792
1793         dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, res->msgs[0], "serverReference");
1794         if (dn != NULL) {
1795                 names[2].result_name = ldb_dn_alloc_linearized(names, dn);
1796                 W_ERROR_HAVE_NO_MEMORY(names[2].result_name);
1797                 names[2].status = DRSUAPI_DS_NAME_STATUS_OK;
1798         }
1799
1800         talloc_free(dn);
1801         talloc_free(res);
1802
1803         return WERR_OK;
1804 }