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