r11339: Fix the build by adding the serviceprincial name cracknames helper.
[jelmer/samba4-debian.git] / source / dsdb / samdb / cracknames.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the drsuapi pipe
5    DsCrackNames()
6
7    Copyright (C) Stefan Metzmacher 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_drsuapi.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/drsuapi/dcesrv_drsuapi.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "system/kerberos.h"
32 #include "auth/kerberos/kerberos.h"
33
34 static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
35                                    struct smb_krb5_context *smb_krb5_context,
36                                    uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
37                                    const struct ldb_dn *name_dn, const char *name, 
38                                    const char *domain_filter, const char *result_filter, 
39                                    struct drsuapi_DsNameInfo1 *info1);
40 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
41                                         uint32_t format_offered, uint32_t format_desired,
42                                         const struct ldb_dn *name_dn, const char *name, 
43                                         struct drsuapi_DsNameInfo1 *info1);
44
45 static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx, 
46                                    TALLOC_CTX *mem_ctx,
47                                    const char *alias_from,
48                                    char **alias_to)
49 {
50         int i;
51         int count;
52         struct ldb_message **msg;
53         struct ldb_message_element *spnmappings;
54         struct ldb_dn *service_dn = ldb_dn_string_compose(mem_ctx, samdb_base_dn(mem_ctx),
55                                                 "CN=Directory Service,CN=Windows NT"
56                                                 ",CN=Services,CN=Configuration");
57         char *service_dn_str = ldb_dn_linearize(mem_ctx, service_dn);
58         const char *directory_attrs[] = {
59                 "sPNMappings", 
60                 NULL
61         };
62
63         count = ldb_search(ldb_ctx, service_dn, LDB_SCOPE_BASE, "(objectClass=nTDSService)",
64                            directory_attrs, &msg);
65         talloc_steal(mem_ctx, msg);
66
67         if (count < 1) {
68                 DEBUG(1, ("ldb_search: dn: %s not found: %d", service_dn_str, count));
69                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
70         } else if (count > 1) {
71                 DEBUG(1, ("ldb_search: dn: %s found %d times!", service_dn_str, count));
72                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
73         }
74         
75         spnmappings = ldb_msg_find_element(msg[0], "sPNMappings");
76         if (!spnmappings || spnmappings->num_values == 0) {
77                 DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute", service_dn_str));
78                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
79         }
80
81         for (i = 0; i < spnmappings->num_values; i++) {
82                 char *mapping, *p, *str;
83                 mapping = talloc_strdup(mem_ctx, 
84                                         (const char *)spnmappings->values[i].data);
85                 if (!mapping) {
86                         DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));
87                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
88                 }
89                 
90                 /* C string manipulation sucks */
91                 
92                 p = strchr(mapping, '=');
93                 if (!p) {
94                         DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n", 
95                                   service_dn_str, mapping));
96                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
97                 }
98                 p[0] = '\0';
99                 p++;
100                 do {
101                         str = p;
102                         p = strchr(p, ',');
103                         if (p) {
104                                 p[0] = '\0';
105                                 p++;
106                         }
107                         if (strcasecmp(str, alias_from) == 0) {
108                                 *alias_to = mapping;
109                                 return DRSUAPI_DS_NAME_STATUS_OK;
110                         }
111                 } while (p);
112         }
113         DEBUG(1, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
114         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
115 }
116
117 static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
118                                   struct smb_krb5_context *smb_krb5_context,
119                                   uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
120                                   const char *name, struct drsuapi_DsNameInfo1 *info1)
121 {
122         WERROR wret;
123         krb5_error_code ret;
124         krb5_principal principal;
125         const char *service;
126         char *new_service;
127         char *new_princ;
128         enum drsuapi_DsNameStatus namestatus;
129         
130         /* parse principal */
131         ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, 
132                                       name, &principal);
133         if (ret) {
134                 DEBUG(2, ("Could not parse principal: %s: %s",
135                           name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
136                                                            ret, mem_ctx)));
137                 return WERR_NOMEM;
138         }
139         
140         /* grab cifs/, http/ etc */
141         
142         /* This is checked for in callers, but be safe */
143         if (principal->name.name_string.len < 2) {
144                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
145                 return WERR_OK;
146         }
147         service = principal->name.name_string.val[0];
148         
149         /* MAP it */
150         namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context, 
151                                           sam_ctx, mem_ctx, 
152                                           service, &new_service);
153         
154         if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
155                 info1->status = namestatus;
156                 return WERR_OK;
157         }
158         
159         if (ret != 0) {
160                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
161                 return WERR_OK;
162         }
163         
164         /* ooh, very nasty playing around in the Principal... */
165         free(principal->name.name_string.val[0]);
166         principal->name.name_string.val[0] = strdup(new_service);
167         if (!principal->name.name_string.val[0]) {
168                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
169                 return WERR_NOMEM;
170         }
171         
172         /* reform principal */
173         ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &new_princ);
174
175         krb5_free_principal(smb_krb5_context->krb5_context, principal);
176         
177         if (ret) {
178                 return WERR_NOMEM;
179         }
180         
181         wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
182                                   new_princ, info1);
183         free(new_princ);
184         return wret;
185 }
186
187 static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
188                              struct smb_krb5_context *smb_krb5_context,
189                              uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
190                              const char *name, struct drsuapi_DsNameInfo1 *info1)
191 {
192         WERROR status;
193         const char *domain_filter = NULL;
194         const char *result_filter = NULL;
195         krb5_error_code ret;
196         krb5_principal principal;
197         char **realm;
198         char *unparsed_name_short;
199
200         /* Prevent recursion */
201         if (!name) {
202                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
203                 return WERR_OK;
204         }
205
206         ret = krb5_parse_name_mustrealm(smb_krb5_context->krb5_context, name, &principal);
207         if (ret) {
208                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
209                 return WERR_OK;
210         }
211         
212         domain_filter = NULL;
213         realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
214         domain_filter = talloc_asprintf(mem_ctx, 
215                                         "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
216                                         *realm, *realm);
217         ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
218         krb5_free_principal(smb_krb5_context->krb5_context, principal);
219                 
220         if (ret) {
221                 free(unparsed_name_short);
222                 return WERR_NOMEM;
223         }
224         
225         /* This may need to be extended for more userPrincipalName variations */
226         result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", 
227                                         unparsed_name_short);
228         if (!result_filter || !domain_filter) {
229                 free(unparsed_name_short);
230                 return WERR_NOMEM;
231         }
232         status = DsCrackNameOneFilter(sam_ctx, mem_ctx, 
233                                       smb_krb5_context, 
234                                       format_flags, format_offered, format_desired, 
235                                       NULL, unparsed_name_short, domain_filter, result_filter, 
236                                       info1);
237         free(unparsed_name_short);
238         return status;
239 }
240
241 WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
242                           uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
243                           const char *name, struct drsuapi_DsNameInfo1 *info1)
244 {
245         krb5_error_code ret;
246         const char *domain_filter = NULL;
247         const char *result_filter = NULL;
248         struct ldb_dn *name_dn = NULL;
249
250         struct smb_krb5_context *smb_krb5_context;
251         ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
252                                 
253         if (ret) {
254                 return WERR_NOMEM;
255         }
256
257         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
258         info1->dns_domain_name = NULL;
259         info1->result_name = NULL;
260
261         if (!name) {
262                 return WERR_INVALID_PARAM;
263         }
264
265         /* TODO: - fill the correct names in all cases!
266          *       - handle format_flags
267          */
268
269         /* here we need to set the domain_filter and/or the result_filter */
270         switch (format_offered) {
271         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
272                 char *str;
273                 
274                 str = talloc_strdup(mem_ctx, name);
275                 WERR_TALLOC_CHECK(str);
276                 
277                 if (strlen(str) == 0 || str[strlen(str)-1] != '/') {
278                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
279                         return WERR_OK;
280                 }
281                 
282                 str[strlen(str)-1] = '\0';
283                 
284                 domain_filter = talloc_asprintf(mem_ctx, 
285                                                 "(&(&(&(dnsRoot=%s)(objectclass=crossRef)))(nETBIOSName=*)(ncName=*))", 
286                                                 str);
287                 WERR_TALLOC_CHECK(domain_filter);
288                 
289                 break;
290         }
291         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
292                 char *p;
293                 char *domain;
294                 const char *account = NULL;
295                 
296                 domain = talloc_strdup(mem_ctx, name);
297                 WERR_TALLOC_CHECK(domain);
298                 
299                 p = strchr(domain, '\\');
300                 if (!p) {
301                         /* invalid input format */
302                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
303                         return WERR_OK;
304                 }
305                 p[0] = '\0';
306                 
307                 if (p[1]) {
308                         account = &p[1];
309                 }
310                 
311                 domain_filter = talloc_asprintf(mem_ctx, 
312                                                 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
313                                                 domain);
314                 WERR_TALLOC_CHECK(domain_filter);
315                 if (account) {
316                         result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
317                                                         account);
318                         WERR_TALLOC_CHECK(result_filter);
319                 }
320                 
321                 talloc_free(domain);
322                 break;
323         }
324         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
325                 name_dn = ldb_dn_explode(mem_ctx, name);
326                 domain_filter = NULL;
327                 if (!name_dn) {
328                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
329                         return WERR_OK;
330                 }
331                 break;
332         }
333         case DRSUAPI_DS_NAME_FORMAT_GUID: {
334                 struct GUID guid;
335                 char *ldap_guid;
336                 NTSTATUS nt_status;
337                 domain_filter = NULL;
338
339                 nt_status = GUID_from_string(name, &guid);
340                 if (!NT_STATUS_IS_OK(nt_status)) {
341                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
342                         return WERR_OK;
343                 }
344                         
345                 ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
346                 if (!ldap_guid) {
347                         return WERR_NOMEM;
348                 }
349                 result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
350                                                 ldap_guid);
351                 WERR_TALLOC_CHECK(result_filter);
352                 break;
353         }
354         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
355                 domain_filter = NULL;
356
357                 result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
358                                                 name, name);
359                 WERR_TALLOC_CHECK(result_filter);
360                 break;
361         }
362         
363         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
364                 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
365                 char *ldap_sid;
366                                                                             
367                 domain_filter = NULL;
368                 if (!sid) {
369                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
370                         return WERR_OK;
371                 }
372                 ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx, 
373                                                    sid);
374                 if (!ldap_sid) {
375                         return WERR_NOMEM;
376                 }
377                 result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
378                                                 ldap_sid);
379                 WERR_TALLOC_CHECK(result_filter);
380                 break;
381         }
382         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
383                 krb5_principal principal;
384                 char *unparsed_name;
385                 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
386                 if (ret) {
387                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
388                         return WERR_OK;
389                 }
390                 
391                 domain_filter = NULL;
392                 
393                 ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
394                 if (ret) {
395                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
396                         return WERR_NOMEM;
397                 }
398
399                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
400                 result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))", 
401                                                 unparsed_name);
402                 
403                 free(unparsed_name);
404                 WERR_TALLOC_CHECK(result_filter);
405                 break;
406         }
407         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
408                 krb5_principal principal;
409                 char *unparsed_name_short;
410                 ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, name, &principal);
411                 if (ret || (principal->name.name_string.len < 2)) {
412                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
413                         return WERR_OK;
414                 }
415
416                 domain_filter = NULL;
417                 
418                 ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
419                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
420                 if (ret) {
421                         return WERR_NOMEM;
422                 }
423
424                 result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(servicePrincipalName=%s))", 
425                                                 unparsed_name_short);
426                 free(unparsed_name_short);
427                 WERR_TALLOC_CHECK(result_filter);
428                 
429                 break;
430         }
431         default: {
432                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
433                 return WERR_OK;
434         }
435
436         }
437
438         if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
439                 return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
440                                                  name_dn, name, info1);
441         }
442         
443         return DsCrackNameOneFilter(sam_ctx, mem_ctx, 
444                                     smb_krb5_context, 
445                                     format_flags, format_offered, format_desired, 
446                                     name_dn, name, 
447                                     domain_filter, result_filter, 
448                                     info1);
449 }
450
451 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
452                                         uint32_t format_offered, uint32_t format_desired,
453                                         const struct ldb_dn *name_dn, const char *name, 
454                                         struct drsuapi_DsNameInfo1 *info1)
455 {
456         char *cracked;
457         if (format_offered != DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
458                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
459                 return WERR_OK;
460         }
461
462         switch (format_desired) {
463         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: 
464                 cracked = ldb_dn_canonical_string(mem_ctx, name_dn);
465                 break;
466         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
467                 cracked = ldb_dn_canonical_ex_string(mem_ctx, name_dn);
468                 break;
469         default:
470                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
471                 return WERR_OK;
472         }
473         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
474         info1->result_name      = cracked;
475         if (!cracked) {
476                 return WERR_NOMEM;
477         }
478         
479         return WERR_OK; 
480         
481 }
482
483 static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
484                                    struct smb_krb5_context *smb_krb5_context,
485                                    uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
486                                    const struct ldb_dn *name_dn, const char *name, 
487                                    const char *domain_filter, const char *result_filter, 
488                                    struct drsuapi_DsNameInfo1 *info1)
489 {
490         int ldb_ret;
491         struct ldb_message **domain_res = NULL;
492         const char * const *domain_attrs;
493         const char * const *result_attrs;
494         struct ldb_message **result_res = NULL;
495         const struct ldb_dn *result_basedn;
496
497         /* here we need to set the attrs lists for domain and result lookups */
498         switch (format_desired) {
499         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
500         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
501                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
502                 const char * const _result_attrs[] = { NULL};
503                 
504                 domain_attrs = _domain_attrs;
505                 result_attrs = _result_attrs;
506                 break;
507         }
508         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
509                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
510                 const char * const _result_attrs[] = { "canonicalName", NULL };
511                 
512                 domain_attrs = _domain_attrs;
513                 result_attrs = _result_attrs;
514                 break;
515         }
516         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
517                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
518                 const char * const _result_attrs[] = { "sAMAccountName", "objectSid", NULL};
519                 
520                 domain_attrs = _domain_attrs;
521                 result_attrs = _result_attrs;
522                 break;
523         }
524         case DRSUAPI_DS_NAME_FORMAT_GUID: {
525                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
526                 const char * const _result_attrs[] = { "objectGUID", NULL};
527                 
528                 domain_attrs = _domain_attrs;
529                 result_attrs = _result_attrs;
530                 break;
531         }
532         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
533                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
534                 const char * const _result_attrs[] = { "displayName", "samAccountName", NULL};
535                 
536                 domain_attrs = _domain_attrs;
537                 result_attrs = _result_attrs;
538                 break;
539         }
540         default:
541                 return WERR_OK;
542         }
543
544         if (domain_filter) {
545                 /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
546                 ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
547                                        "%s", domain_filter);
548         } else {
549                 ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
550                                        "(ncName=%s)", ldb_dn_linearize(mem_ctx, samdb_base_dn(mem_ctx)));
551         } 
552
553         switch (ldb_ret) {
554         case 1:
555                 break;
556         case 0:
557                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
558                 return WERR_OK;
559         case -1:
560                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
561                 return WERR_OK;
562         default:
563                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
564                 return WERR_OK;
565         }
566
567         info1->dns_domain_name  = samdb_result_string(domain_res[0], "dnsRoot", NULL);
568         WERR_TALLOC_CHECK(info1->dns_domain_name);
569         info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
570
571         if (result_filter) {
572                 result_basedn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
573                 
574                 ldb_ret = gendb_search(sam_ctx, mem_ctx, result_basedn, &result_res,
575                                        result_attrs, "%s", result_filter);
576         } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
577                 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
578                                           result_attrs);
579         } else {
580                 name_dn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
581                 ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
582                                           result_attrs);
583         }
584
585         switch (ldb_ret) {
586         case 1:
587                 break;
588         case 0:
589                 switch (format_offered) {
590                 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: 
591                         return DsCrackNameSPNAlias(sam_ctx, mem_ctx, 
592                                                    smb_krb5_context, 
593                                                    format_flags, format_offered, format_desired,
594                                                    name, info1);
595                         
596                 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
597                         return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context, 
598                                               format_flags, format_offered, format_desired,
599                                               name, info1);
600                 }
601                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
602                 return WERR_OK;
603         case -1:
604                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
605                 return WERR_OK;
606         default:
607                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
608                 return WERR_OK;
609         }
610
611         /* here we can use result_res[0] and domain_res[0] */
612         switch (format_desired) {
613         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
614                 info1->result_name      = ldb_dn_linearize(mem_ctx, result_res[0]->dn);
615                 WERR_TALLOC_CHECK(info1->result_name);
616
617                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
618                 return WERR_OK;
619         }
620         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
621                 info1->result_name      = samdb_result_string(result_res[0], "canonicalName", NULL);
622                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
623                 return WERR_OK;
624         }
625         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
626                 /* Not in the virtual ldb attribute */
627                 return DsCrackNameOneSyntactical(mem_ctx, 
628                                                  DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
629                                                  DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
630                                                  result_res[0]->dn, name, info1);
631         }
632         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
633                 const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result_res[0], "objectSid");
634                 const char *_acc = "", *_dom = "";
635                 
636                 if ((sid->num_auths < 4) || (sid->num_auths > 5)) {
637                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
638                         return WERR_OK;
639                 }
640
641                 if (sid->num_auths == 4) {
642                         ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
643                                                "(ncName=%s)", ldb_dn_linearize(mem_ctx, result_res[0]->dn));
644                         if (ldb_ret != 1) {
645                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
646                                 return WERR_OK;
647                         }
648                         _dom = samdb_result_string(domain_res[0], "nETBIOSName", NULL);
649                         WERR_TALLOC_CHECK(_dom);
650                 
651                 } else if (sid->num_auths == 5) {
652                         const char *attrs[] = { NULL };
653                         struct ldb_message **domain_res2;
654                         struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
655                         if (!dom_sid) {
656                                 return WERR_OK;
657                         }
658                         dom_sid->num_auths--;
659                         ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res, attrs,
660                                                "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
661                         if (ldb_ret != 1) {
662                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
663                                 return WERR_OK;
664                         }
665                         ldb_ret = gendb_search(sam_ctx, mem_ctx, NULL, &domain_res2, domain_attrs,
666                                                "(ncName=%s)", ldb_dn_linearize(mem_ctx, domain_res[0]->dn));
667                         if (ldb_ret != 1) {
668                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
669                                 return WERR_OK;
670                         }
671                         
672                         _dom = samdb_result_string(domain_res2[0], "nETBIOSName", NULL);
673                         WERR_TALLOC_CHECK(_dom);
674
675                         _acc = samdb_result_string(result_res[0], "sAMAccountName", NULL);
676                         WERR_TALLOC_CHECK(_acc);
677                 }
678
679                 info1->result_name      = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
680                 WERR_TALLOC_CHECK(info1->result_name);
681                 
682                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
683                 return WERR_OK;
684         }
685         case DRSUAPI_DS_NAME_FORMAT_GUID: {
686                 struct GUID guid;
687                 
688                 guid = samdb_result_guid(result_res[0], "objectGUID");
689                 
690                 info1->result_name      = GUID_string2(mem_ctx, &guid);
691                 WERR_TALLOC_CHECK(info1->result_name);
692                 
693                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
694                 return WERR_OK;
695         }
696         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
697                 info1->result_name      = samdb_result_string(result_res[0], "displayName", NULL);
698                 if (!info1->result_name) {
699                         info1->result_name      = samdb_result_string(result_res[0], "sAMAccountName", NULL);
700                 } 
701                 if (!info1->result_name) {
702                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
703                 } else {
704                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
705                 }
706                 return WERR_OK;
707         }
708         default:
709                 return WERR_OK;
710         }
711         
712         return WERR_INVALID_PARAM;
713 }
714
715 NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx, 
716                                    TALLOC_CTX *mem_ctx, 
717                                    const char *user_principal_name, 
718                                    struct ldb_dn **user_dn,
719                                    struct ldb_dn **domain_dn) 
720 {
721         WERROR werr;
722         struct drsuapi_DsNameInfo1 info1;
723         werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
724                                   DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
725                                   DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
726                                   user_principal_name,
727                                   &info1);
728         if (!W_ERROR_IS_OK(werr)) {
729                 return werror_to_ntstatus(werr);
730         }
731         switch (info1.status) {
732         case DRSUAPI_DS_NAME_STATUS_OK:
733                 break;
734         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
735         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
736         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
737                 return NT_STATUS_NO_SUCH_USER;
738         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
739         default:
740                 return NT_STATUS_UNSUCCESSFUL;
741         }
742         
743         *user_dn = ldb_dn_explode(mem_ctx, info1.result_name);
744         
745         if (domain_dn) {
746                 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
747                                           DRSUAPI_DS_NAME_FORMAT_CANONICAL,
748                                           DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
749                                           talloc_asprintf(mem_ctx, "%s/", 
750                                                           info1.dns_domain_name),
751                                           &info1);
752                 if (!W_ERROR_IS_OK(werr)) {
753                         return werror_to_ntstatus(werr);
754                 }
755                 switch (info1.status) {
756                 case DRSUAPI_DS_NAME_STATUS_OK:
757                         break;
758                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
759                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
760                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
761                         return NT_STATUS_NO_SUCH_USER;
762                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
763                 default:
764                         return NT_STATUS_UNSUCCESSFUL;
765                 }
766                 
767                 *domain_dn = ldb_dn_explode(mem_ctx, info1.result_name);
768         }
769
770         return NT_STATUS_OK;
771         
772 }
773
774 NTSTATUS crack_service_principal_name(struct ldb_context *sam_ctx, 
775                                       TALLOC_CTX *mem_ctx, 
776                                       const char *service_principal_name, 
777                                       struct ldb_dn **user_dn,
778                                       struct ldb_dn **domain_dn) 
779 {
780         WERROR werr;
781         struct drsuapi_DsNameInfo1 info1;
782         werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
783                                   DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
784                                   DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
785                                   service_principal_name,
786                                   &info1);
787         if (!W_ERROR_IS_OK(werr)) {
788                 return werror_to_ntstatus(werr);
789         }
790         switch (info1.status) {
791         case DRSUAPI_DS_NAME_STATUS_OK:
792                 break;
793         case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
794         case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
795         case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
796                 return NT_STATUS_NO_SUCH_USER;
797         case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
798         default:
799                 return NT_STATUS_UNSUCCESSFUL;
800         }
801         
802         *user_dn = ldb_dn_explode(mem_ctx, info1.result_name);
803         
804         if (domain_dn) {
805                 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
806                                           DRSUAPI_DS_NAME_FORMAT_CANONICAL,
807                                           DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
808                                           talloc_asprintf(mem_ctx, "%s/", 
809                                                           info1.dns_domain_name),
810                                           &info1);
811                 if (!W_ERROR_IS_OK(werr)) {
812                         return werror_to_ntstatus(werr);
813                 }
814                 switch (info1.status) {
815                 case DRSUAPI_DS_NAME_STATUS_OK:
816                         break;
817                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
818                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
819                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
820                         return NT_STATUS_NO_SUCH_USER;
821                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
822                 default:
823                         return NT_STATUS_UNSUCCESSFUL;
824                 }
825                 
826                 *domain_dn = ldb_dn_explode(mem_ctx, info1.result_name);
827         }
828
829         return NT_STATUS_OK;
830         
831 }