c1a6c19978501f72c4a84dcc17bb45713473b49b
[ira/wip.git] / source4 / rpc_server / drsuapi / drsuapi_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 drsuapi_bind_state *b_state, 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 DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
41                                  uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
42                                  const char *name, struct drsuapi_DsNameInfo1 *info1);
43
44 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
45                                         uint32_t format_offered, uint32_t format_desired,
46                                         const struct ldb_dn *name_dn, const char *name, 
47                                         struct drsuapi_DsNameInfo1 *info1);
48
49 static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx, 
50                                    TALLOC_CTX *mem_ctx,
51                                    const char *alias_from,
52                                    char **alias_to)
53 {
54         int i;
55         int count;
56         struct ldb_message **msg;
57         struct ldb_message_element *spnmappings;
58         struct ldb_dn *service_dn = ldb_dn_string_compose(mem_ctx, samdb_base_dn(mem_ctx),
59                                                 "CN=Directory Service,CN=Windows NT"
60                                                 ",CN=Services,CN=Configuration");
61         char *service_dn_str = ldb_dn_linearize(mem_ctx, service_dn);
62         const char *directory_attrs[] = {
63                 "sPNMappings", 
64                 NULL
65         };
66
67         count = ldb_search(ldb_ctx, service_dn, LDB_SCOPE_BASE, "(objectClass=nTDSService)",
68                            directory_attrs, &msg);
69         talloc_steal(mem_ctx, msg);
70
71         if (count < 1) {
72                 DEBUG(1, ("ldb_search: dn: %s not found: %d", service_dn_str, count));
73                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
74         } else if (count > 1) {
75                 DEBUG(1, ("ldb_search: dn: %s found %d times!", service_dn_str, count));
76                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
77         }
78         
79         spnmappings = ldb_msg_find_element(msg[0], "sPNMappings");
80         if (!spnmappings || spnmappings->num_values == 0) {
81                 DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute", service_dn_str));
82                 return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
83         }
84
85         for (i = 0; i < spnmappings->num_values; i++) {
86                 char *mapping, *p, *str;
87                 mapping = talloc_strdup(mem_ctx, 
88                                         (const char *)spnmappings->values[i].data);
89                 if (!mapping) {
90                         DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));
91                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
92                 }
93                 
94                 /* C string manipulation sucks */
95                 
96                 p = strchr(mapping, '=');
97                 if (!p) {
98                         DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n", 
99                                   service_dn_str, mapping));
100                         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
101                 }
102                 p[0] = '\0';
103                 p++;
104                 do {
105                         str = p;
106                         p = strchr(p, ',');
107                         if (p) {
108                                 p[0] = '\0';
109                                 p++;
110                         }
111                         if (strcasecmp(str, alias_from) == 0) {
112                                 *alias_to = mapping;
113                                 return DRSUAPI_DS_NAME_STATUS_OK;
114                         }
115                 } while (p);
116         }
117         DEBUG(1, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));
118         return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
119 }
120
121 static WERROR DsCrackNameSPNAlias(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
122                                   struct smb_krb5_context *smb_krb5_context,
123                                   uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
124                                   const char *name, struct drsuapi_DsNameInfo1 *info1)
125 {
126         WERROR wret;
127         krb5_error_code ret;
128         krb5_principal principal;
129         const char *service;
130         char *new_service;
131         char *new_princ;
132         enum drsuapi_DsNameStatus namestatus;
133         
134         /* parse principal */
135         ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, 
136                                       name, &principal);
137         if (ret) {
138                 DEBUG(2, ("Could not parse principal: %s: %s",
139                           name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
140                                                            ret, mem_ctx)));
141                 return WERR_NOMEM;
142         }
143         
144         /* grab cifs/, http/ etc */
145         
146         /* This is checked for in callers, but be safe */
147         if (principal->name.name_string.len < 2) {
148                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
149                 return WERR_OK;
150         }
151         service = principal->name.name_string.val[0];
152         
153         /* MAP it */
154         namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context, 
155                                           b_state->sam_ctx, mem_ctx, 
156                                           service, &new_service);
157         
158         if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
159                 info1->status = namestatus;
160                 return WERR_OK;
161         }
162         
163         if (ret != 0) {
164                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
165                 return WERR_OK;
166         }
167         
168         /* ooh, very nasty playing around in the Principal... */
169         free(principal->name.name_string.val[0]);
170         principal->name.name_string.val[0] = strdup(new_service);
171         if (!principal->name.name_string.val[0]) {
172                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
173                 return WERR_NOMEM;
174         }
175         
176         /* reform principal */
177         ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &new_princ);
178
179         krb5_free_principal(smb_krb5_context->krb5_context, principal);
180         
181         if (ret) {
182                 return WERR_NOMEM;
183         }
184         
185         wret = DsCrackNameOneName(b_state, mem_ctx, format_flags, format_offered, format_desired,
186                                   new_princ, info1);
187         free(new_princ);
188         return wret;
189 }
190
191 static WERROR DsCrackNameUPN(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
192                              struct smb_krb5_context *smb_krb5_context,
193                              uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
194                              const char *name, struct drsuapi_DsNameInfo1 *info1)
195 {
196         WERROR status;
197         const char *domain_filter = NULL;
198         const char *result_filter = NULL;
199         krb5_error_code ret;
200         krb5_principal principal;
201         char **realm;
202         char *unparsed_name_short;
203
204         /* Prevent recursion */
205         if (!name) {
206                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
207                 return WERR_OK;
208         }
209
210         ret = krb5_parse_name_mustrealm(smb_krb5_context->krb5_context, name, &principal);
211         if (ret) {
212                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
213                 return WERR_OK;
214         }
215         
216         domain_filter = NULL;
217         realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);
218         domain_filter = talloc_asprintf(mem_ctx, 
219                                         "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
220                                         *realm, *realm);
221         ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
222         krb5_free_principal(smb_krb5_context->krb5_context, principal);
223                 
224         if (ret) {
225                 free(unparsed_name_short);
226                 return WERR_NOMEM;
227         }
228         
229         /* This may need to be extended for more userPrincipalName variations */
230         result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", 
231                                         unparsed_name_short);
232         if (!result_filter || !domain_filter) {
233                 free(unparsed_name_short);
234                 return WERR_NOMEM;
235         }
236         status = DsCrackNameOneFilter(b_state, mem_ctx, 
237                                       smb_krb5_context, 
238                                       format_flags, format_offered, format_desired, 
239                                       NULL, unparsed_name_short, domain_filter, result_filter, 
240                                       info1);
241         free(unparsed_name_short);
242         return status;
243 }
244
245 static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
246                                  uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
247                                  const char *name, struct drsuapi_DsNameInfo1 *info1)
248 {
249         krb5_error_code ret;
250         const char *domain_filter = NULL;
251         const char *result_filter = NULL;
252         struct ldb_dn *name_dn = NULL;
253
254         struct smb_krb5_context *smb_krb5_context;
255         ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
256                                 
257         if (ret) {
258                 return WERR_NOMEM;
259         }
260
261         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
262         info1->dns_domain_name = NULL;
263         info1->result_name = NULL;
264
265         if (!name) {
266                 return WERR_INVALID_PARAM;
267         }
268
269         /* TODO: - fill the correct names in all cases!
270          *       - handle format_flags
271          */
272
273         /* here we need to set the domain_filter and/or the result_filter */
274         switch (format_offered) {
275         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
276                 char *str;
277                 
278                 str = talloc_strdup(mem_ctx, name);
279                 WERR_TALLOC_CHECK(str);
280                 
281                 if (strlen(str) == 0 || str[strlen(str)-1] != '/') {
282                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
283                         return WERR_OK;
284                 }
285                 
286                 str[strlen(str)-1] = '\0';
287                 
288                 domain_filter = talloc_asprintf(mem_ctx, 
289                                                 "(&(&(&(dnsRoot=%s)(objectclass=crossRef)))(nETBIOSName=*)(ncName=*))", 
290                                                 str);
291                 WERR_TALLOC_CHECK(domain_filter);
292                 
293                 break;
294         }
295         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
296                 char *p;
297                 char *domain;
298                 const char *account = NULL;
299                 
300                 domain = talloc_strdup(mem_ctx, name);
301                 WERR_TALLOC_CHECK(domain);
302                 
303                 p = strchr(domain, '\\');
304                 if (!p) {
305                         /* invalid input format */
306                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
307                         return WERR_OK;
308                 }
309                 p[0] = '\0';
310                 
311                 if (p[1]) {
312                         account = &p[1];
313                 }
314                 
315                 domain_filter = talloc_asprintf(mem_ctx, 
316                                                 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
317                                                 domain);
318                 WERR_TALLOC_CHECK(domain_filter);
319                 if (account) {
320                         result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
321                                                         account);
322                         WERR_TALLOC_CHECK(result_filter);
323                 }
324                 
325                 talloc_free(domain);
326                 break;
327         }
328         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
329                 name_dn = ldb_dn_explode(mem_ctx, name);
330                 domain_filter = NULL;
331                 if (!name_dn) {
332                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
333                         return WERR_OK;
334                 }
335                 break;
336         }
337         case DRSUAPI_DS_NAME_FORMAT_GUID: {
338                 struct GUID guid;
339                 char *ldap_guid;
340                 NTSTATUS nt_status;
341                 domain_filter = NULL;
342
343                 nt_status = GUID_from_string(name, &guid);
344                 if (!NT_STATUS_IS_OK(nt_status)) {
345                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
346                         return WERR_OK;
347                 }
348                         
349                 ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
350                 if (!ldap_guid) {
351                         return WERR_NOMEM;
352                 }
353                 result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
354                                                 ldap_guid);
355                 WERR_TALLOC_CHECK(result_filter);
356                 break;
357         }
358         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
359                 domain_filter = NULL;
360
361                 result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
362                                                 name, name);
363                 WERR_TALLOC_CHECK(result_filter);
364                 break;
365         }
366         
367         case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
368                 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
369                 char *ldap_sid;
370                                                                             
371                 domain_filter = NULL;
372                 if (!sid) {
373                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
374                         return WERR_OK;
375                 }
376                 ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx, 
377                                                    sid);
378                 if (!ldap_sid) {
379                         return WERR_NOMEM;
380                 }
381                 result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
382                                                 ldap_sid);
383                 WERR_TALLOC_CHECK(result_filter);
384                 break;
385         }
386         case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
387                 krb5_principal principal;
388                 char *unparsed_name;
389                 ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
390                 if (ret) {
391                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
392                         return WERR_OK;
393                 }
394                 
395                 domain_filter = NULL;
396                 
397                 ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
398                 if (ret) {
399                         krb5_free_principal(smb_krb5_context->krb5_context, principal);
400                         return WERR_NOMEM;
401                 }
402
403                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
404                 result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))", 
405                                                 unparsed_name);
406                 
407                 free(unparsed_name);
408                 WERR_TALLOC_CHECK(result_filter);
409                 break;
410         }
411         case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
412                 krb5_principal principal;
413                 char *unparsed_name_short;
414                 ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, name, &principal);
415                 if (ret || (principal->name.name_string.len < 2)) {
416                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
417                         return WERR_OK;
418                 }
419
420                 domain_filter = NULL;
421                 
422                 ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
423                 krb5_free_principal(smb_krb5_context->krb5_context, principal);
424                 if (ret) {
425                         return WERR_NOMEM;
426                 }
427
428                 result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(servicePrincipalName=%s))", 
429                                                 unparsed_name_short);
430                 free(unparsed_name_short);
431                 WERR_TALLOC_CHECK(result_filter);
432                 
433                 break;
434         }
435         default: {
436                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
437                 return WERR_OK;
438         }
439
440         }
441
442         if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
443                 return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
444                                                  name_dn, name, info1);
445         }
446         
447         return DsCrackNameOneFilter(b_state, mem_ctx, 
448                                     smb_krb5_context, 
449                                     format_flags, format_offered, format_desired, 
450                                     name_dn, name, 
451                                     domain_filter, result_filter, 
452                                     info1);
453 }
454
455 static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,
456                                         uint32_t format_offered, uint32_t format_desired,
457                                         const struct ldb_dn *name_dn, const char *name, 
458                                         struct drsuapi_DsNameInfo1 *info1)
459 {
460         char *cracked;
461         if (format_offered != DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
462                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
463                 return WERR_OK;
464         }
465
466         switch (format_desired) {
467         case DRSUAPI_DS_NAME_FORMAT_CANONICAL: 
468                 cracked = ldb_dn_canonical_string(mem_ctx, name_dn);
469                 break;
470         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
471                 cracked = ldb_dn_canonical_ex_string(mem_ctx, name_dn);
472                 break;
473         default:
474                 info1->status = DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING;
475                 return WERR_OK;
476         }
477         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
478         info1->result_name      = cracked;
479         if (!cracked) {
480                 return WERR_NOMEM;
481         }
482         
483         return WERR_OK; 
484         
485 }
486
487 static WERROR DsCrackNameOneFilter(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
488                                    struct smb_krb5_context *smb_krb5_context,
489                                    uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
490                                    const struct ldb_dn *name_dn, const char *name, 
491                                    const char *domain_filter, const char *result_filter, 
492                                    struct drsuapi_DsNameInfo1 *info1)
493 {
494         int ldb_ret;
495         struct ldb_message **domain_res = NULL;
496         const char * const *domain_attrs;
497         const char * const *result_attrs;
498         struct ldb_message **result_res = NULL;
499         const struct ldb_dn *result_basedn;
500
501         /* here we need to set the attrs lists for domain and result lookups */
502         switch (format_desired) {
503         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
504         case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
505         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
506                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
507                 const char * const _result_attrs[] = { NULL};
508                 
509                 domain_attrs = _domain_attrs;
510                 result_attrs = _result_attrs;
511                 break;
512         }
513         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
514                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
515                 const char * const _result_attrs[] = { "sAMAccountName", "objectSid", NULL};
516                 
517                 domain_attrs = _domain_attrs;
518                 result_attrs = _result_attrs;
519                 break;
520         }
521         case DRSUAPI_DS_NAME_FORMAT_GUID: {
522                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
523                 const char * const _result_attrs[] = { "objectGUID", NULL};
524                 
525                 domain_attrs = _domain_attrs;
526                 result_attrs = _result_attrs;
527                 break;
528         }
529         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
530                 const char * const _domain_attrs[] = { "ncName", "dnsRoot", NULL};
531                 const char * const _result_attrs[] = { "displayName", "samAccountName", NULL};
532                 
533                 domain_attrs = _domain_attrs;
534                 result_attrs = _result_attrs;
535                 break;
536         }
537         default:
538                 return WERR_OK;
539         }
540
541         if (domain_filter) {
542                 /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
543                 ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
544                                        "%s", domain_filter);
545         } else {
546                 ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
547                                        "(ncName=%s)", ldb_dn_linearize(mem_ctx, samdb_base_dn(mem_ctx)));
548         } 
549
550         switch (ldb_ret) {
551         case 1:
552                 break;
553         case 0:
554                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
555                 return WERR_OK;
556         case -1:
557                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
558                 return WERR_OK;
559         default:
560                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
561                 return WERR_OK;
562         }
563
564         info1->dns_domain_name  = samdb_result_string(domain_res[0], "dnsRoot", NULL);
565         WERR_TALLOC_CHECK(info1->dns_domain_name);
566         info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
567
568         if (result_filter) {
569                 result_basedn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
570                 
571                 ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, result_basedn, &result_res,
572                                        result_attrs, "%s", result_filter);
573         } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
574                 ldb_ret = gendb_search_dn(b_state->sam_ctx, mem_ctx, name_dn, &result_res,
575                                           result_attrs);
576         } else {
577                 name_dn = samdb_result_dn(mem_ctx, domain_res[0], "ncName", NULL);
578                 ldb_ret = gendb_search_dn(b_state->sam_ctx, mem_ctx, name_dn, &result_res,
579                                           result_attrs);
580         }
581
582         switch (ldb_ret) {
583         case 1:
584                 break;
585         case 0:
586                 switch (format_offered) {
587                 case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: 
588                         return DsCrackNameSPNAlias(b_state, mem_ctx, 
589                                                    smb_krb5_context, 
590                                                    format_flags, format_offered, format_desired,
591                                                    name, info1);
592                         
593                 case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
594                         return DsCrackNameUPN(b_state, mem_ctx, smb_krb5_context, 
595                                               format_flags, format_offered, format_desired,
596                                               name, info1);
597                 }
598                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
599                 return WERR_OK;
600         case -1:
601                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
602                 return WERR_OK;
603         default:
604                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
605                 return WERR_OK;
606         }
607
608         /* here we can use result_res[0] and domain_res[0] */
609         switch (format_desired) {
610         case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
611                 info1->result_name      = ldb_dn_linearize(mem_ctx, result_res[0]->dn);
612                 WERR_TALLOC_CHECK(info1->result_name);
613
614                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
615                 return WERR_OK;
616         }
617         case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
618                 return DsCrackNameOneSyntactical(mem_ctx, 
619                                                  DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
620                                                  DRSUAPI_DS_NAME_FORMAT_CANONICAL,
621                                                  result_res[0]->dn, name, info1);
622         case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
623                 return DsCrackNameOneSyntactical(mem_ctx, 
624                                                  DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
625                                                  DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
626                                                  result_res[0]->dn, name, info1);
627         case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
628                 const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result_res[0], "objectSid");
629                 const char *_acc = "", *_dom = "";
630                 
631                 if ((sid->num_auths < 4) || (sid->num_auths > 5)) {
632                         info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
633                         return WERR_OK;
634                 }
635
636                 if (sid->num_auths == 4) {
637                         ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
638                                                "(ncName=%s)", ldb_dn_linearize(mem_ctx, result_res[0]->dn));
639                         if (ldb_ret != 1) {
640                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
641                                 return WERR_OK;
642                         }
643                         _dom = samdb_result_string(domain_res[0], "nETBIOSName", NULL);
644                         WERR_TALLOC_CHECK(_dom);
645                 
646                 } else if (sid->num_auths == 5) {
647                         const char *attrs[] = { NULL };
648                         struct ldb_message **domain_res2;
649                         struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
650                         if (!dom_sid) {
651                                 return WERR_OK;
652                         }
653                         dom_sid->num_auths--;
654                         ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res2, attrs,
655                                                "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
656                         if (ldb_ret != 1) {
657                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
658                                 return WERR_OK;
659                         }
660                         ldb_ret = gendb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
661                                                "(ncName=%s)", ldb_dn_linearize(mem_ctx, domain_res2[0]->dn));
662                         if (ldb_ret != 1) {
663                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
664                                 return WERR_OK;
665                         }
666                         
667                         _dom = samdb_result_string(domain_res2[0], "nETBIOSName", NULL);
668                         WERR_TALLOC_CHECK(_dom);
669
670                         _acc = samdb_result_string(result_res[0], "sAMAccountName", NULL);
671                         WERR_TALLOC_CHECK(_acc);
672                 }
673
674                 info1->result_name      = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
675                 WERR_TALLOC_CHECK(info1->result_name);
676                 
677                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
678                 return WERR_OK;
679         }
680         case DRSUAPI_DS_NAME_FORMAT_GUID: {
681                 struct GUID guid;
682                 
683                 guid = samdb_result_guid(result_res[0], "objectGUID");
684                 
685                 info1->result_name      = GUID_string2(mem_ctx, &guid);
686                 WERR_TALLOC_CHECK(info1->result_name);
687                 
688                 info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
689                 return WERR_OK;
690         }
691         case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
692                 info1->result_name      = samdb_result_string(result_res[0], "displayName", NULL);
693                 if (!info1->result_name) {
694                         info1->result_name      = samdb_result_string(result_res[0], "sAMAccountName", NULL);
695                 } 
696                 if (!info1->result_name) {
697                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
698                 } else {
699                         info1->status = DRSUAPI_DS_NAME_STATUS_OK;
700                 }
701                 return WERR_OK;
702         }
703         default:
704                 return WERR_OK;
705         }
706         
707         return WERR_INVALID_PARAM;
708 }
709
710 /* 
711   drsuapi_DsCrackNames 
712 */
713 WERROR dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
714                        struct drsuapi_DsCrackNames *r)
715 {
716         WERROR status;
717         struct drsuapi_bind_state *b_state;
718         struct dcesrv_handle *h;
719
720         r->out.level = r->in.level;
721         ZERO_STRUCT(r->out.ctr);
722
723         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
724         b_state = h->data;
725
726         switch (r->in.level) {
727                 case 1: {
728                         struct drsuapi_DsNameCtr1 *ctr1;
729                         struct drsuapi_DsNameInfo1 *names;
730                         int count;
731                         int i;
732
733                         ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
734                         WERR_TALLOC_CHECK(ctr1);
735
736                         count = r->in.req.req1.count;
737                         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
738                         WERR_TALLOC_CHECK(names);
739
740                         for (i=0; i < count; i++) {
741                                 status = DsCrackNameOneName(b_state, mem_ctx,
742                                                             r->in.req.req1.format_flags,
743                                                             r->in.req.req1.format_offered,
744                                                             r->in.req.req1.format_desired,
745                                                             r->in.req.req1.names[i].str,
746                                                             &names[i]);
747                                 if (!W_ERROR_IS_OK(status)) {
748                                         return status;
749                                 }
750                         }
751
752                         ctr1->count = count;
753                         ctr1->array = names;
754                         r->out.ctr.ctr1 = ctr1;
755
756                         return WERR_OK;
757                 }
758         }
759         
760         return WERR_UNKNOWN_LEVEL;
761 }