cfda82c20af523be001711561ed31f2ef30c342a
[sfrench/samba-autobuild/.git] / source3 / winbindd / winbindd_ads.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind ADS backend functions
5
6    Copyright (C) Andrew Tridgell 2001
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
8    Copyright (C) Gerald (Jerry) Carter 2004
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 3 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "winbindd.h"
26 #include "rpc_client/rpc_client.h"
27 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
28 #include "../libds/common/flags.h"
29 #include "ads.h"
30 #include "../libcli/ldap/ldap_ndr.h"
31 #include "../libcli/security/security.h"
32 #include "../libds/common/flag_mapping.h"
33 #include "passdb.h"
34
35 #ifdef HAVE_ADS
36
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_WINBIND
39
40 extern struct winbindd_methods reconnect_methods;
41
42 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
43
44 /**
45  * Check if cached connection can be reused. If the connection cannot
46  * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
47  */
48 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
49 {
50
51         ADS_STRUCT *ads = *adsp;
52
53         if (ads != NULL) {
54                 time_t expire;
55                 time_t now = time(NULL);
56
57                 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
58
59                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
60                           "is now %d)\n", (uint32)expire - (uint32)now,
61                           (uint32) expire, (uint32) now));
62
63                 if ( ads->config.realm && (expire > now)) {
64                         return;
65                 } else {
66                         /* we own this ADS_STRUCT so make sure it goes away */
67                         DEBUG(7,("Deleting expired krb5 credential cache\n"));
68                         ads->is_mine = True;
69                         ads_destroy( &ads );
70                         ads_kdestroy(WINBIND_CCACHE_NAME);
71                         *adsp = NULL;
72                 }
73         }
74 }
75
76 /**
77  * @brief Establish a connection to a DC
78  *
79  * @param[out]   adsp             ADS_STRUCT that will be created
80  * @param[in]    target_realm     Realm of domain to connect to
81  * @param[in]    target_dom_name  'workgroup' name of domain to connect to
82  * @param[in]    ldap_server      DNS name of server to connect to
83  * @param[in]    password         Our machine acount secret
84  * @param[in]    auth_realm       Realm of local domain for creating krb token
85  * @param[in]    renewable        Renewable ticket time
86  *
87  * @return ADS_STATUS
88  */
89 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
90                                                 const char *target_realm,
91                                                 const char *target_dom_name,
92                                                 const char *ldap_server,
93                                                 char *password,
94                                                 char *auth_realm,
95                                                 time_t renewable)
96 {
97         ADS_STRUCT *ads;
98         ADS_STATUS status;
99         struct sockaddr_storage dc_ss;
100         fstring dc_name;
101
102         if (auth_realm == NULL) {
103                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
104         }
105
106         /* we don't want this to affect the users ccache */
107         setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
108
109         ads = ads_init(target_realm, target_dom_name, ldap_server);
110         if (!ads) {
111                 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
112                 return ADS_ERROR(LDAP_NO_MEMORY);
113         }
114
115         SAFE_FREE(ads->auth.password);
116         SAFE_FREE(ads->auth.realm);
117
118         ads->auth.renewable = renewable;
119         ads->auth.password = password;
120
121         ads->auth.realm = SMB_STRDUP(auth_realm);
122         if (!strupper_m(ads->auth.realm)) {
123                 ads_destroy(&ads);
124                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
125         }
126
127         /* Setup the server affinity cache.  We don't reaally care
128            about the name.  Just setup affinity and the KRB5_CONFIG
129            file. */
130         get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
131
132         status = ads_connect(ads);
133         if (!ADS_ERR_OK(status)) {
134                 DEBUG(1,("ads_connect for domain %s failed: %s\n",
135                          target_dom_name, ads_errstr(status)));
136                 ads_destroy(&ads);
137                 return status;
138         }
139
140         /* set the flag that says we don't own the memory even
141            though we do so that ads_destroy() won't destroy the
142            structure we pass back by reference */
143
144         ads->is_mine = False;
145
146         *adsp = ads;
147
148         return status;
149 }
150
151 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
152 {
153         char *ldap_server, *realm, *password;
154         struct winbindd_domain *wb_dom;
155         ADS_STATUS status;
156
157         ads_cached_connection_reuse(adsp);
158         if (*adsp != NULL) {
159                 return ADS_SUCCESS;
160         }
161
162         /*
163          * At this point we only have the NetBIOS domain name.
164          * Check if we can get server nam and realm from SAF cache
165          * and the domain list.
166          */
167         ldap_server = saf_fetch(talloc_tos(), dom_name);
168         DEBUG(10, ("ldap_server from saf cache: '%s'\n",
169                    ldap_server ? ldap_server : ""));
170
171         wb_dom = find_domain_from_name(dom_name);
172         if (wb_dom == NULL) {
173                 DEBUG(10, ("could not find domain '%s'\n", dom_name));
174                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
175         }
176
177         DEBUG(10, ("find_domain_from_name found realm '%s' for "
178                           " domain '%s'\n", wb_dom->alt_name, dom_name));
179
180         if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
181                 TALLOC_FREE(ldap_server);
182                 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
183         }
184
185         if (IS_DC) {
186                 realm = SMB_STRDUP(wb_dom->alt_name);
187         } else {
188                 struct winbindd_domain *our_domain = wb_dom;
189
190                 /* always give preference to the alt_name in our
191                    primary domain if possible */
192
193                 if (!wb_dom->primary) {
194                         our_domain = find_our_domain();
195                 }
196
197                 if (our_domain->alt_name != NULL) {
198                         realm = SMB_STRDUP(our_domain->alt_name);
199                 } else {
200                         realm = SMB_STRDUP(lp_realm());
201                 }
202         }
203
204         status = ads_cached_connection_connect(
205                 adsp,                   /* Returns ads struct. */
206                 wb_dom->alt_name,       /* realm to connect to. */
207                 dom_name,               /* 'workgroup' name for ads_init */
208                 ldap_server,            /* DNS name to connect to. */
209                 password,               /* password for auth realm. */
210                 realm,                  /* realm used for krb5 ticket. */
211                 0);                     /* renewable ticket time. */
212
213         SAFE_FREE(realm);
214         TALLOC_FREE(ldap_server);
215
216         return status;
217 }
218
219 /*
220   return our ads connections structure for a domain. We keep the connection
221   open to make things faster
222 */
223 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
224 {
225         ADS_STATUS status;
226         char *password, *realm;
227
228         DEBUG(10,("ads_cached_connection\n"));
229         ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
230
231         if (domain->private_data) {
232                 return (ADS_STRUCT *)domain->private_data;
233         }
234
235         /* the machine acct password might have change - fetch it every time */
236
237         if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
238                 return NULL;
239         }
240
241         if ( IS_DC ) {
242
243                 realm = SMB_STRDUP(domain->alt_name);
244         }
245         else {
246                 struct winbindd_domain *our_domain = domain;
247
248
249                 /* always give preference to the alt_name in our
250                    primary domain if possible */
251
252                 if ( !domain->primary )
253                         our_domain = find_our_domain();
254
255                 if (our_domain->alt_name != NULL) {
256                         realm = SMB_STRDUP( our_domain->alt_name );
257                 }
258                 else
259                         realm = SMB_STRDUP( lp_realm() );
260         }
261
262         status = ads_cached_connection_connect(
263                                         (ADS_STRUCT **)&domain->private_data,
264                                         domain->alt_name,
265                                         domain->name, NULL,
266                                         password, realm,
267                                         WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
268         SAFE_FREE(realm);
269
270         if (!ADS_ERR_OK(status)) {
271                 /* if we get ECONNREFUSED then it might be a NT4
272                    server, fall back to MSRPC */
273                 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
274                     status.err.rc == ECONNREFUSED) {
275                         /* 'reconnect_methods' is the MS-RPC backend. */
276                         DEBUG(1,("Trying MSRPC methods\n"));
277                         domain->backend = &reconnect_methods;
278                 }
279                 return NULL;
280         }
281
282         return (ADS_STRUCT *)domain->private_data;
283 }
284
285 /* Query display info for a realm. This is the basic user list fn */
286 static NTSTATUS query_user_list(struct winbindd_domain *domain,
287                                TALLOC_CTX *mem_ctx,
288                                uint32 *num_entries, 
289                                struct wbint_userinfo **pinfo)
290 {
291         ADS_STRUCT *ads = NULL;
292         const char *attrs[] = { "*", NULL };
293         int i, count;
294         ADS_STATUS rc;
295         LDAPMessage *res = NULL;
296         LDAPMessage *msg = NULL;
297         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
298
299         *num_entries = 0;
300
301         DEBUG(3,("ads: query_user_list\n"));
302
303         if ( !winbindd_can_contact_domain( domain ) ) {
304                 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
305                           domain->name));               
306                 return NT_STATUS_OK;
307         }
308
309         ads = ads_cached_connection(domain);
310
311         if (!ads) {
312                 domain->last_status = NT_STATUS_SERVER_DISABLED;
313                 goto done;
314         }
315
316         rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
317         if (!ADS_ERR_OK(rc)) {
318                 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
319                 status = ads_ntstatus(rc);
320                 goto done;
321         } else if (!res) {
322                 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
323                 goto done;
324         }
325
326         count = ads_count_replies(ads, res);
327         if (count == 0) {
328                 DEBUG(1,("query_user_list: No users found\n"));
329                 goto done;
330         }
331
332         (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
333         if (!*pinfo) {
334                 status = NT_STATUS_NO_MEMORY;
335                 goto done;
336         }
337
338         count = 0;
339
340         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
341                 struct wbint_userinfo *info = &((*pinfo)[count]);
342                 uint32 group;
343                 uint32 atype;
344
345                 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
346                     ds_atype_map(atype) != SID_NAME_USER) {
347                         DEBUG(1,("Not a user account? atype=0x%x\n", atype));
348                         continue;
349                 }
350
351                 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
352                 info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
353                 if (info->full_name == NULL) {
354                         info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
355                 }
356                 info->homedir = NULL;
357                 info->shell = NULL;
358                 info->primary_gid = (gid_t)-1;
359
360                 if (!ads_pull_sid(ads, msg, "objectSid",
361                                   &info->user_sid)) {
362                         DEBUG(1, ("No sid for %s !?\n", info->acct_name));
363                         continue;
364                 }
365
366                 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
367                         DEBUG(1, ("No primary group for %s !?\n",
368                                   info->acct_name));
369                         continue;
370                 }
371                 sid_compose(&info->group_sid, &domain->sid, group);
372
373                 count += 1;
374         }
375
376         (*num_entries) = count;
377         ads_msgfree(ads, res);
378
379         for (i=0; i<count; i++) {
380                 struct wbint_userinfo *info = &((*pinfo)[i]);
381                 const char *gecos = NULL;
382                 gid_t primary_gid = (gid_t)-1;
383
384                 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
385                                              &info->homedir, &info->shell,
386                                              &gecos, &primary_gid);
387                 if (!NT_STATUS_IS_OK(status)) {
388                         /*
389                          * Deliberately ignore this error, there might be more
390                          * users to fill
391                          */
392                         continue;
393                 }
394
395                 if (gecos != NULL) {
396                         info->full_name = gecos;
397                 }
398                 info->primary_gid = primary_gid;
399         }
400
401         status = NT_STATUS_OK;
402
403         DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
404
405 done:
406         return status;
407 }
408
409 /* list all domain groups */
410 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
411                                 TALLOC_CTX *mem_ctx,
412                                 uint32 *num_entries, 
413                                 struct wb_acct_info **info)
414 {
415         ADS_STRUCT *ads = NULL;
416         const char *attrs[] = {"userPrincipalName", "sAMAccountName",
417                                "name", "objectSid", NULL};
418         int i, count;
419         ADS_STATUS rc;
420         LDAPMessage *res = NULL;
421         LDAPMessage *msg = NULL;
422         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
423         const char *filter;
424         bool enum_dom_local_groups = False;
425
426         *num_entries = 0;
427
428         DEBUG(3,("ads: enum_dom_groups\n"));
429
430         if ( !winbindd_can_contact_domain( domain ) ) {
431                 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
432                           domain->name));               
433                 return NT_STATUS_OK;
434         }
435
436         /* only grab domain local groups for our domain */
437         if ( domain->active_directory && strequal(lp_realm(), domain->alt_name)  ) {
438                 enum_dom_local_groups = True;
439         }
440
441         /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
442          * rollup-fixes:
443          *
444          * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
445          * default value, it MUST be absent. In case of extensible matching the
446          * "dnattr" boolean defaults to FALSE and so it must be only be present
447          * when set to TRUE. 
448          *
449          * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
450          * filter using bitwise matching rule then the buggy AD fails to decode
451          * the extensible match. As a workaround set it to TRUE and thereby add
452          * the dnAttributes "dn" field to cope with those older AD versions.
453          * It should not harm and won't put any additional load on the AD since
454          * none of the dn components have a bitmask-attribute.
455          *
456          * Thanks to Ralf Haferkamp for input and testing - Guenther */
457
458         filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
459                                  ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
460                                  ADS_LDAP_MATCHING_RULE_BIT_AND, 
461                                  enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
462
463         if (filter == NULL) {
464                 status = NT_STATUS_NO_MEMORY;
465                 goto done;
466         }
467
468         ads = ads_cached_connection(domain);
469
470         if (!ads) {
471                 domain->last_status = NT_STATUS_SERVER_DISABLED;
472                 goto done;
473         }
474
475         rc = ads_search_retry(ads, &res, filter, attrs);
476         if (!ADS_ERR_OK(rc)) {
477                 status = ads_ntstatus(rc);
478                 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
479                 goto done;
480         } else if (!res) {
481                 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
482                 goto done;
483         }
484
485         count = ads_count_replies(ads, res);
486         if (count == 0) {
487                 DEBUG(1,("enum_dom_groups: No groups found\n"));
488                 goto done;
489         }
490
491         (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
492         if (!*info) {
493                 status = NT_STATUS_NO_MEMORY;
494                 goto done;
495         }
496
497         i = 0;
498
499         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
500                 char *name, *gecos;
501                 struct dom_sid sid;
502                 uint32 rid;
503
504                 name = ads_pull_username(ads, mem_ctx, msg);
505                 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
506                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
507                         DEBUG(1,("No sid for %s !?\n", name));
508                         continue;
509                 }
510
511                 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
512                         DEBUG(1,("No rid for %s !?\n", name));
513                         continue;
514                 }
515
516                 fstrcpy((*info)[i].acct_name, name);
517                 fstrcpy((*info)[i].acct_desc, gecos);
518                 (*info)[i].rid = rid;
519                 i++;
520         }
521
522         (*num_entries) = i;
523
524         status = NT_STATUS_OK;
525
526         DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
527
528 done:
529         if (res) 
530                 ads_msgfree(ads, res);
531
532         return status;
533 }
534
535 /* list all domain local groups */
536 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
537                                 TALLOC_CTX *mem_ctx,
538                                 uint32 *num_entries, 
539                                 struct wb_acct_info **info)
540 {
541         /*
542          * This is a stub function only as we returned the domain 
543          * local groups in enum_dom_groups() if the domain->native field
544          * was true.  This is a simple performance optimization when
545          * using LDAP.
546          *
547          * if we ever need to enumerate domain local groups separately, 
548          * then this optimization in enum_dom_groups() will need
549          * to be split out
550          */
551         *num_entries = 0;
552
553         return NT_STATUS_OK;
554 }
555
556 /* convert a single name to a sid in a domain - use rpc methods */
557 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
558                             TALLOC_CTX *mem_ctx,
559                             const char *domain_name,
560                             const char *name,
561                             uint32_t flags,
562                             struct dom_sid *sid,
563                             enum lsa_SidType *type)
564 {
565         return reconnect_methods.name_to_sid(domain, mem_ctx,
566                                              domain_name, name, flags,
567                                              sid, type);
568 }
569
570 /* convert a domain SID to a user or group name - use rpc methods */
571 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
572                             TALLOC_CTX *mem_ctx,
573                             const struct dom_sid *sid,
574                             char **domain_name,
575                             char **name,
576                             enum lsa_SidType *type)
577 {
578         return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
579                                              domain_name, name, type);
580 }
581
582 /* convert a list of rids to names - use rpc methods */
583 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
584                               TALLOC_CTX *mem_ctx,
585                               const struct dom_sid *sid,
586                               uint32 *rids,
587                               size_t num_rids,
588                               char **domain_name,
589                               char ***names,
590                               enum lsa_SidType **types)
591 {
592         return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
593                                                rids, num_rids,
594                                                domain_name, names, types);
595 }
596
597 /* If you are looking for "dn_lookup": Yes, it used to be here!
598  * It has gone now since it was a major speed bottleneck in
599  * lookup_groupmem (its only use). It has been replaced by
600  * an rpc lookup sids call... R.I.P. */
601
602 /* Lookup user information from a rid */
603 static NTSTATUS query_user(struct winbindd_domain *domain, 
604                            TALLOC_CTX *mem_ctx, 
605                            const struct dom_sid *sid,
606                            struct wbint_userinfo *info)
607 {
608         ADS_STRUCT *ads = NULL;
609         const char *attrs[] = { "*", NULL };
610         ADS_STATUS rc;
611         int count;
612         LDAPMessage *msg = NULL;
613         char *ldap_exp;
614         char *sidstr;
615         uint32 group_rid;
616         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
617         struct netr_SamInfo3 *user = NULL;
618         gid_t gid = -1;
619         int ret;
620         char *full_name;
621
622         DEBUG(3,("ads: query_user\n"));
623
624         info->homedir = NULL;
625         info->shell = NULL;
626
627         /* try netsamlogon cache first */
628
629         if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
630         {
631                 DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
632                          sid_string_dbg(sid)));
633
634                 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
635                 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
636
637                 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
638                 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
639
640                 nss_get_info_cached( domain, sid, mem_ctx,
641                               &info->homedir, &info->shell, &info->full_name, 
642                               &gid );
643                 info->primary_gid = gid;
644
645                 TALLOC_FREE(user);
646
647                 if (info->full_name == NULL) {
648                         /* this might fail so we dont check the return code */
649                         wcache_query_user_fullname(domain,
650                                                    mem_ctx,
651                                                    sid,
652                                                    &info->full_name);
653                 }
654
655                 return NT_STATUS_OK;
656         }
657
658         if ( !winbindd_can_contact_domain(domain)) {
659                 DEBUG(8,("query_user: No incoming trust from domain %s\n",
660                          domain->name));
661
662                 /* We still need to generate some basic information
663                    about the user even if we cannot contact the 
664                    domain.  Most of this stuff we can deduce. */
665
666                 sid_copy( &info->user_sid, sid );
667
668                 /* Assume "Domain Users" for the primary group */
669
670                 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
671
672                 /* Try to fill in what the nss_info backend can do */
673
674                 nss_get_info_cached( domain, sid, mem_ctx,
675                               &info->homedir, &info->shell, &info->full_name, 
676                               &gid);
677                 info->primary_gid = gid;
678
679                 return NT_STATUS_OK;
680         }
681
682         /* no cache...do the query */
683
684         if ( (ads = ads_cached_connection(domain)) == NULL ) {
685                 domain->last_status = NT_STATUS_SERVER_DISABLED;
686                 return NT_STATUS_SERVER_DISABLED;
687         }
688
689         sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
690
691         ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
692         TALLOC_FREE(sidstr);
693         if (ret == -1) {
694                 return NT_STATUS_NO_MEMORY;
695         }
696         rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
697         SAFE_FREE(ldap_exp);
698         if (!ADS_ERR_OK(rc)) {
699                 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
700                          sid_string_dbg(sid), ads_errstr(rc)));
701                 return ads_ntstatus(rc);
702         } else if (!msg) {
703                 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
704                          sid_string_dbg(sid)));
705                 return NT_STATUS_INTERNAL_ERROR;
706         }
707
708         count = ads_count_replies(ads, msg);
709         if (count != 1) {
710                 DEBUG(1,("query_user(sid=%s): Not found\n",
711                          sid_string_dbg(sid)));
712                 ads_msgfree(ads, msg);
713                 return NT_STATUS_NO_SUCH_USER;
714         }
715
716         info->acct_name = ads_pull_username(ads, mem_ctx, msg);
717
718         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
719                 DEBUG(1,("No primary group for %s !?\n",
720                          sid_string_dbg(sid)));
721                 ads_msgfree(ads, msg);
722                 return NT_STATUS_NO_SUCH_USER;
723         }
724         sid_copy(&info->user_sid, sid);
725         sid_compose(&info->group_sid, &domain->sid, group_rid);
726
727         /*
728          * We have to fetch the "name" attribute before doing the
729          * nss_get_info_cached call. nss_get_info_cached might destroy
730          * the ads struct, potentially invalidating the ldap message.
731          */
732         full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
733         if (full_name == NULL) {
734                 full_name = ads_pull_string(ads, mem_ctx, msg, "name");
735         }
736
737         ads_msgfree(ads, msg);
738         msg = NULL;
739
740         status = nss_get_info_cached( domain, sid, mem_ctx,
741                       &info->homedir, &info->shell, &info->full_name, 
742                       &gid);
743         info->primary_gid = gid;
744         if (!NT_STATUS_IS_OK(status)) {
745                 DEBUG(1, ("nss_get_info_cached failed: %s\n",
746                           nt_errstr(status)));
747                 return status;
748         }
749
750         if (info->full_name == NULL) {
751                 info->full_name = full_name;
752         } else {
753                 TALLOC_FREE(full_name);
754         }
755
756         status = NT_STATUS_OK;
757
758         DEBUG(3,("ads query_user gave %s\n", info->acct_name));
759         return NT_STATUS_OK;
760 }
761
762 /* Lookup groups a user is a member of - alternate method, for when
763    tokenGroups are not available. */
764 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
765                                          TALLOC_CTX *mem_ctx,
766                                          const char *user_dn, 
767                                          struct dom_sid *primary_group,
768                                          uint32_t *p_num_groups, struct dom_sid **user_sids)
769 {
770         ADS_STATUS rc;
771         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
772         int count;
773         LDAPMessage *res = NULL;
774         LDAPMessage *msg = NULL;
775         char *ldap_exp;
776         ADS_STRUCT *ads;
777         const char *group_attrs[] = {"objectSid", NULL};
778         char *escaped_dn;
779         uint32_t num_groups = 0;
780
781         DEBUG(3,("ads: lookup_usergroups_member\n"));
782
783         if ( !winbindd_can_contact_domain( domain ) ) {
784                 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
785                           domain->name));               
786                 return NT_STATUS_OK;
787         }
788
789         ads = ads_cached_connection(domain);
790
791         if (!ads) {
792                 domain->last_status = NT_STATUS_SERVER_DISABLED;
793                 goto done;
794         }
795
796         if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
797                 status = NT_STATUS_NO_MEMORY;
798                 goto done;
799         }
800
801         ldap_exp = talloc_asprintf(mem_ctx,
802                 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
803                 escaped_dn,
804                 ADS_LDAP_MATCHING_RULE_BIT_AND,
805                 GROUP_TYPE_SECURITY_ENABLED);
806         if (!ldap_exp) {
807                 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
808                 TALLOC_FREE(escaped_dn);
809                 status = NT_STATUS_NO_MEMORY;
810                 goto done;
811         }
812
813         TALLOC_FREE(escaped_dn);
814
815         rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
816
817         if (!ADS_ERR_OK(rc)) {
818                 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
819                 return ads_ntstatus(rc);
820         } else if (!res) {
821                 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
822                 return NT_STATUS_INTERNAL_ERROR;
823         }
824
825
826         count = ads_count_replies(ads, res);
827
828         *user_sids = NULL;
829         num_groups = 0;
830
831         /* always add the primary group to the sid array */
832         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
833                                   &num_groups);
834         if (!NT_STATUS_IS_OK(status)) {
835                 goto done;
836         }
837
838         if (count > 0) {
839                 for (msg = ads_first_entry(ads, res); msg;
840                      msg = ads_next_entry(ads, msg)) {
841                         struct dom_sid group_sid;
842
843                         if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
844                                 DEBUG(1,("No sid for this group ?!?\n"));
845                                 continue;
846                         }
847
848                         /* ignore Builtin groups from ADS - Guenther */
849                         if (sid_check_is_in_builtin(&group_sid)) {
850                                 continue;
851                         }
852
853                         status = add_sid_to_array(mem_ctx, &group_sid,
854                                                   user_sids, &num_groups);
855                         if (!NT_STATUS_IS_OK(status)) {
856                                 goto done;
857                         }
858                 }
859
860         }
861
862         *p_num_groups = num_groups;
863         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
864
865         DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
866 done:
867         if (res) 
868                 ads_msgfree(ads, res);
869
870         return status;
871 }
872
873 /* Lookup groups a user is a member of - alternate method, for when
874    tokenGroups are not available. */
875 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
876                                            TALLOC_CTX *mem_ctx,
877                                            const char *user_dn,
878                                            struct dom_sid *primary_group,
879                                            uint32_t *p_num_groups,
880                                            struct dom_sid **user_sids)
881 {
882         ADS_STATUS rc;
883         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
884         ADS_STRUCT *ads;
885         const char *attrs[] = {"memberOf", NULL};
886         uint32_t num_groups = 0;
887         struct dom_sid *group_sids = NULL;
888         int i;
889         char **strings = NULL;
890         size_t num_strings = 0, num_sids = 0;
891
892
893         DEBUG(3,("ads: lookup_usergroups_memberof\n"));
894
895         if ( !winbindd_can_contact_domain( domain ) ) {
896                 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
897                           "domain %s\n", domain->name));
898                 return NT_STATUS_OK;
899         }
900
901         ads = ads_cached_connection(domain);
902
903         if (!ads) {
904                 domain->last_status = NT_STATUS_SERVER_DISABLED;
905                 return NT_STATUS_UNSUCCESSFUL;
906         }
907
908         rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
909                                                  ADS_EXTENDED_DN_HEX_STRING,
910                                                  &strings, &num_strings);
911
912         if (!ADS_ERR_OK(rc)) {
913                 DEBUG(1,("lookup_usergroups_memberof ads_search "
914                         "member=%s: %s\n", user_dn, ads_errstr(rc)));
915                 return ads_ntstatus(rc);
916         }
917
918         *user_sids = NULL;
919         num_groups = 0;
920
921         /* always add the primary group to the sid array */
922         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
923                                   &num_groups);
924         if (!NT_STATUS_IS_OK(status)) {
925                 goto done;
926         }
927
928         group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
929         if (!group_sids) {
930                 status = NT_STATUS_NO_MEMORY;
931                 goto done;
932         }
933
934         for (i=0; i<num_strings; i++) {
935                 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
936                                                   ADS_EXTENDED_DN_HEX_STRING,
937                                                   &(group_sids)[i]);
938                 if (!ADS_ERR_OK(rc)) {
939                         /* ignore members without SIDs */
940                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
941                             NT_STATUS_NOT_FOUND)) {
942                                 continue;
943                         }
944                         else {
945                                 status = ads_ntstatus(rc);
946                                 goto done;
947                         }
948                 }
949                 num_sids++;
950         }
951
952         if (i == 0) {
953                 DEBUG(1,("No memberOf for this user?!?\n"));
954                 status = NT_STATUS_NO_MEMORY;
955                 goto done;
956         }
957
958         for (i=0; i<num_sids; i++) {
959
960                 /* ignore Builtin groups from ADS - Guenther */
961                 if (sid_check_is_in_builtin(&group_sids[i])) {
962                         continue;
963                 }
964
965                 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
966                                           &num_groups);
967                 if (!NT_STATUS_IS_OK(status)) {
968                         goto done;
969                 }
970
971         }
972
973         *p_num_groups = num_groups;
974         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
975
976         DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
977                 user_dn));
978
979 done:
980         TALLOC_FREE(strings);
981         TALLOC_FREE(group_sids);
982
983         return status;
984 }
985
986
987 /* Lookup groups a user is a member of. */
988 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
989                                   TALLOC_CTX *mem_ctx,
990                                   const struct dom_sid *sid,
991                                   uint32 *p_num_groups, struct dom_sid **user_sids)
992 {
993         ADS_STRUCT *ads = NULL;
994         const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
995         ADS_STATUS rc;
996         int count;
997         LDAPMessage *msg = NULL;
998         char *user_dn = NULL;
999         struct dom_sid *sids;
1000         int i;
1001         struct dom_sid primary_group;
1002         uint32 primary_group_rid;
1003         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1004         uint32_t num_groups = 0;
1005
1006         DEBUG(3,("ads: lookup_usergroups\n"));
1007         *p_num_groups = 0;
1008
1009         status = lookup_usergroups_cached(domain, mem_ctx, sid, 
1010                                           p_num_groups, user_sids);
1011         if (NT_STATUS_IS_OK(status)) {
1012                 return NT_STATUS_OK;
1013         }
1014
1015         if ( !winbindd_can_contact_domain( domain ) ) {
1016                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
1017                           domain->name));
1018
1019                 /* Tell the cache manager not to remember this one */
1020
1021                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
1022         }
1023
1024         ads = ads_cached_connection(domain);
1025
1026         if (!ads) {
1027                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1028                 status = NT_STATUS_SERVER_DISABLED;
1029                 goto done;
1030         }
1031
1032         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
1033
1034         if (!ADS_ERR_OK(rc)) {
1035                 status = ads_ntstatus(rc);
1036                 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1037                           "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
1038                 goto done;
1039         }
1040
1041         count = ads_count_replies(ads, msg);
1042         if (count != 1) {
1043                 status = NT_STATUS_UNSUCCESSFUL;
1044                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1045                          "invalid number of results (count=%d)\n", 
1046                          sid_string_dbg(sid), count));
1047                 goto done;
1048         }
1049
1050         if (!msg) {
1051                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
1052                          sid_string_dbg(sid)));
1053                 status = NT_STATUS_UNSUCCESSFUL;
1054                 goto done;
1055         }
1056
1057         user_dn = ads_get_dn(ads, mem_ctx, msg);
1058         if (user_dn == NULL) {
1059                 status = NT_STATUS_NO_MEMORY;
1060                 goto done;
1061         }
1062
1063         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
1064                 DEBUG(1,("%s: No primary group for sid=%s !?\n", 
1065                          domain->name, sid_string_dbg(sid)));
1066                 goto done;
1067         }
1068
1069         sid_compose(&primary_group, &domain->sid, primary_group_rid);
1070
1071         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
1072
1073         /* there must always be at least one group in the token, 
1074            unless we are talking to a buggy Win2k server */
1075
1076         /* actually this only happens when the machine account has no read
1077          * permissions on the tokenGroup attribute - gd */
1078
1079         if (count == 0) {
1080
1081                 /* no tokenGroups */
1082
1083                 /* lookup what groups this user is a member of by DN search on
1084                  * "memberOf" */
1085
1086                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
1087                                                     &primary_group,
1088                                                     &num_groups, user_sids);
1089                 *p_num_groups = num_groups;
1090                 if (NT_STATUS_IS_OK(status)) {
1091                         goto done;
1092                 }
1093
1094                 /* lookup what groups this user is a member of by DN search on
1095                  * "member" */
1096
1097                 status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
1098                                                   &primary_group,
1099                                                   &num_groups, user_sids);
1100                 *p_num_groups = num_groups;
1101                 goto done;
1102         }
1103
1104         *user_sids = NULL;
1105         num_groups = 0;
1106
1107         status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1108                                   &num_groups);
1109         if (!NT_STATUS_IS_OK(status)) {
1110                 goto done;
1111         }
1112
1113         for (i=0;i<count;i++) {
1114
1115                 /* ignore Builtin groups from ADS - Guenther */
1116                 if (sid_check_is_in_builtin(&sids[i])) {
1117                         continue;
1118                 }
1119
1120                 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1121                                                  user_sids, &num_groups);
1122                 if (!NT_STATUS_IS_OK(status)) {
1123                         goto done;
1124                 }
1125         }
1126
1127         *p_num_groups = (uint32)num_groups;
1128         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1129
1130         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1131                  sid_string_dbg(sid)));
1132 done:
1133         TALLOC_FREE(user_dn);
1134         ads_msgfree(ads, msg);
1135         return status;
1136 }
1137
1138 /* Lookup aliases a user is member of - use rpc methods */
1139 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1140                                    TALLOC_CTX *mem_ctx,
1141                                    uint32 num_sids, const struct dom_sid *sids,
1142                                    uint32 *num_aliases, uint32 **alias_rids)
1143 {
1144         return reconnect_methods.lookup_useraliases(domain, mem_ctx,
1145                                                     num_sids, sids,
1146                                                     num_aliases,
1147                                                     alias_rids);
1148 }
1149
1150 /*
1151   find the members of a group, given a group rid and domain
1152  */
1153 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1154                                 TALLOC_CTX *mem_ctx,
1155                                 const struct dom_sid *group_sid,
1156                                 enum lsa_SidType type,
1157                                 uint32 *num_names,
1158                                 struct dom_sid **sid_mem, char ***names,
1159                                 uint32 **name_types)
1160 {
1161         ADS_STATUS rc;
1162         ADS_STRUCT *ads = NULL;
1163         char *ldap_exp;
1164         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1165         char *sidbinstr;
1166         char **members = NULL;
1167         int i;
1168         size_t num_members = 0;
1169         ads_control args;
1170         struct dom_sid *sid_mem_nocache = NULL;
1171         char **names_nocache = NULL;
1172         enum lsa_SidType *name_types_nocache = NULL;
1173         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
1174         uint32 num_nocache = 0;
1175         TALLOC_CTX *tmp_ctx = NULL;
1176
1177         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1178                   sid_string_dbg(group_sid)));
1179
1180         *num_names = 0;
1181
1182         tmp_ctx = talloc_new(mem_ctx);
1183         if (!tmp_ctx) {
1184                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1185                 status = NT_STATUS_NO_MEMORY;
1186                 goto done;
1187         }
1188
1189         if ( !winbindd_can_contact_domain( domain ) ) {
1190                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1191                           domain->name));
1192                 return NT_STATUS_OK;
1193         }
1194
1195         ads = ads_cached_connection(domain);
1196
1197         if (!ads) {
1198                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1199                 goto done;
1200         }
1201
1202         if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1203                 status = NT_STATUS_NO_MEMORY;
1204                 goto done;
1205         }
1206
1207         /* search for all members of the group */
1208         ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1209         TALLOC_FREE(sidbinstr);
1210         if (ldap_exp == NULL) {
1211                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1212                 status = NT_STATUS_NO_MEMORY;
1213                 goto done;
1214         }
1215
1216         args.control = ADS_EXTENDED_DN_OID;
1217         args.val = ADS_EXTENDED_DN_HEX_STRING;
1218         args.critical = True;
1219
1220         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1221                                ldap_exp, &args, "member", &members, &num_members);
1222
1223         if (!ADS_ERR_OK(rc)) {
1224                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1225                 status = NT_STATUS_UNSUCCESSFUL;
1226                 goto done;
1227         }
1228
1229         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1230
1231         /* Now that we have a list of sids, we need to get the
1232          * lists of names and name_types belonging to these sids.
1233          * even though conceptually not quite clean,  we use the
1234          * RPC call lsa_lookup_sids for this since it can handle a
1235          * list of sids. ldap calls can just resolve one sid at a time.
1236          *
1237          * At this stage, the sids are still hidden in the exetended dn
1238          * member output format. We actually do a little better than
1239          * stated above: In extracting the sids from the member strings,
1240          * we try to resolve as many sids as possible from the
1241          * cache. Only the rest is passed to the lsa_lookup_sids call. */
1242
1243         if (num_members) {
1244                 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1245                 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1246                 (*name_types) = talloc_zero_array(mem_ctx, uint32, num_members);
1247                 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1248
1249                 if ((members == NULL) || (*sid_mem == NULL) ||
1250                     (*names == NULL) || (*name_types == NULL) ||
1251                     (sid_mem_nocache == NULL))
1252                 {
1253                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1254                         status = NT_STATUS_NO_MEMORY;
1255                         goto done;
1256                 }
1257         }
1258         else {
1259                 (*sid_mem) = NULL;
1260                 (*names) = NULL;
1261                 (*name_types) = NULL;
1262         }
1263
1264         for (i=0; i<num_members; i++) {
1265                 enum lsa_SidType name_type;
1266                 char *name, *domain_name;
1267                 struct dom_sid sid;
1268
1269                 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1270                     &sid);
1271                 if (!ADS_ERR_OK(rc)) {
1272                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1273                             NT_STATUS_NOT_FOUND)) {
1274                                 /* Group members can be objects, like Exchange
1275                                  * Public Folders, that don't have a SID.  Skip
1276                                  * them. */
1277                                 continue;
1278                         }
1279                         else {
1280                                 status = ads_ntstatus(rc);
1281                                 goto done;
1282                         }
1283                 }
1284                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1285                     &name_type)) {
1286                         DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1287                                   "cache\n", sid_string_dbg(&sid)));
1288                         sid_copy(&(*sid_mem)[*num_names], &sid);
1289                         (*names)[*num_names] = fill_domain_username_talloc(
1290                                                         *names,
1291                                                         domain_name,
1292                                                         name,
1293                                                         true);
1294
1295                         (*name_types)[*num_names] = name_type;
1296                         (*num_names)++;
1297                 }
1298                 else {
1299                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1300                                    "cache\n", sid_string_dbg(&sid)));
1301                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1302                         num_nocache++;
1303                 }
1304         }
1305
1306         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1307                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1308
1309         /* handle sids not resolved from cache by lsa_lookup_sids */
1310         if (num_nocache > 0) {
1311
1312                 status = winbindd_lookup_sids(tmp_ctx,
1313                                               domain,
1314                                               num_nocache,
1315                                               sid_mem_nocache,
1316                                               &domains_nocache,
1317                                               &names_nocache,
1318                                               &name_types_nocache);
1319
1320                 if (!(NT_STATUS_IS_OK(status) ||
1321                       NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1322                       NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1323                 {
1324                         DEBUG(1, ("lsa_lookupsids call failed with %s "
1325                                   "- retrying...\n", nt_errstr(status)));
1326
1327                         status = winbindd_lookup_sids(tmp_ctx,
1328                                                       domain,
1329                                                       num_nocache,
1330                                                       sid_mem_nocache,
1331                                                       &domains_nocache,
1332                                                       &names_nocache,
1333                                                       &name_types_nocache);
1334                 }
1335
1336                 if (NT_STATUS_IS_OK(status) ||
1337                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1338                 {
1339                         /* Copy the entries over from the "_nocache" arrays
1340                          * to the result arrays, skipping the gaps the
1341                          * lookup_sids call left. */
1342                         for (i=0; i < num_nocache; i++) {
1343                                 if (((names_nocache)[i] != NULL) &&
1344                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1345                                 {
1346                                         sid_copy(&(*sid_mem)[*num_names],
1347                                                  &sid_mem_nocache[i]);
1348                                         (*names)[*num_names] =
1349                                                 fill_domain_username_talloc(
1350                                                         *names,
1351                                                         domains_nocache[i],
1352                                                         names_nocache[i],
1353                                                         true);
1354                                         (*name_types)[*num_names] = name_types_nocache[i];
1355                                         (*num_names)++;
1356                                 }
1357                         }
1358                 }
1359                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1360                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1361                                    "not map any SIDs at all.\n"));
1362                         /* Don't handle this as an error here.
1363                          * There is nothing left to do with respect to the 
1364                          * overall result... */
1365                 }
1366                 else if (!NT_STATUS_IS_OK(status)) {
1367                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
1368                                    "sids via rpc_lsa_lookup_sids: %s\n",
1369                                    (int)num_members, nt_errstr(status)));
1370                         goto done;
1371                 }
1372         }
1373
1374         status = NT_STATUS_OK;
1375         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1376                  sid_string_dbg(group_sid)));
1377
1378 done:
1379
1380         TALLOC_FREE(tmp_ctx);
1381
1382         return status;
1383 }
1384
1385 /* find the sequence number for a domain */
1386 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1387 {
1388         ADS_STRUCT *ads = NULL;
1389         ADS_STATUS rc;
1390
1391         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1392
1393         if ( !winbindd_can_contact_domain( domain ) ) {
1394                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1395                           domain->name));
1396                 *seq = time(NULL);              
1397                 return NT_STATUS_OK;
1398         }
1399
1400         *seq = DOM_SEQUENCE_NONE;
1401
1402         ads = ads_cached_connection(domain);
1403
1404         if (!ads) {
1405                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1406                 return NT_STATUS_UNSUCCESSFUL;
1407         }
1408
1409         rc = ads_USN(ads, seq);
1410
1411         if (!ADS_ERR_OK(rc)) {
1412
1413                 /* its a dead connection, destroy it */
1414
1415                 if (domain->private_data) {
1416                         ads = (ADS_STRUCT *)domain->private_data;
1417                         ads->is_mine = True;
1418                         ads_destroy(&ads);
1419                         ads_kdestroy(WINBIND_CCACHE_NAME);
1420                         domain->private_data = NULL;
1421                 }
1422         }
1423         return ads_ntstatus(rc);
1424 }
1425
1426 /* find the lockout policy of a domain - use rpc methods */
1427 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1428                                TALLOC_CTX *mem_ctx,
1429                                struct samr_DomInfo12 *policy)
1430 {
1431         return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1432 }
1433
1434 /* find the password policy of a domain - use rpc methods */
1435 static NTSTATUS password_policy(struct winbindd_domain *domain,
1436                                 TALLOC_CTX *mem_ctx,
1437                                 struct samr_DomInfo1 *policy)
1438 {
1439         return reconnect_methods.password_policy(domain, mem_ctx, policy);
1440 }
1441
1442 /* get a list of trusted domains */
1443 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1444                                 TALLOC_CTX *mem_ctx,
1445                                 struct netr_DomainTrustList *trusts)
1446 {
1447         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1448         WERROR werr;
1449         int                     i;
1450         uint32                  flags;  
1451         struct rpc_pipe_client *cli;
1452         int ret_count;
1453         struct dcerpc_binding_handle *b;
1454
1455         DEBUG(3,("ads: trusted_domains\n"));
1456
1457         ZERO_STRUCTP(trusts);
1458
1459         /* If this is our primary domain or a root in our forest,
1460            query for all trusts.  If not, then just look for domain
1461            trusts in the target forest */
1462
1463         if (domain->primary || domain_is_forest_root(domain)) {
1464                 flags = NETR_TRUST_FLAG_OUTBOUND |
1465                         NETR_TRUST_FLAG_INBOUND |
1466                         NETR_TRUST_FLAG_IN_FOREST;
1467         } else {
1468                 flags = NETR_TRUST_FLAG_IN_FOREST;
1469         }       
1470
1471         result = cm_connect_netlogon(domain, &cli);
1472
1473         if (!NT_STATUS_IS_OK(result)) {
1474                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1475                           "for PIPE_NETLOGON (%s)\n", 
1476                           domain->name, nt_errstr(result)));
1477                 return NT_STATUS_UNSUCCESSFUL;
1478         }
1479
1480         b = cli->binding_handle;
1481
1482         result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1483                                                       cli->desthost,
1484                                                       flags,
1485                                                       trusts,
1486                                                       &werr);
1487         if (!NT_STATUS_IS_OK(result)) {
1488                 return result;
1489         }
1490
1491         if (!W_ERROR_IS_OK(werr)) {
1492                 return werror_to_ntstatus(werr);
1493         }
1494         if (trusts->count == 0) {
1495                 return NT_STATUS_OK;
1496         }
1497
1498         /* Copy across names and sids */
1499
1500         ret_count = 0;
1501         for (i = 0; i < trusts->count; i++) {
1502                 struct netr_DomainTrust *trust = &trusts->array[i];
1503                 struct winbindd_domain d;
1504
1505                 ZERO_STRUCT(d);
1506
1507                 /*
1508                  * drop external trusts if this is not our primary
1509                  * domain.  This means that the returned number of
1510                  * domains may be less that the ones actually trusted
1511                  * by the DC.
1512                  */
1513
1514                 if ((trust->trust_attributes
1515                      == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1516                     !domain->primary )
1517                 {
1518                         DEBUG(10,("trusted_domains: Skipping external trusted "
1519                                   "domain %s because it is outside of our "
1520                                   "primary domain\n",
1521                                   trust->netbios_name));
1522                         continue;
1523                 }
1524
1525                 /* add to the trusted domain cache */
1526
1527                 d.name = discard_const_p(char, trust->netbios_name);
1528                 d.alt_name = discard_const_p(char, trust->dns_name);
1529
1530                 if (trust->sid) {
1531                         sid_copy(&d.sid, trust->sid);
1532                 } else {
1533                         sid_copy(&d.sid, &global_sid_NULL);
1534                 }
1535
1536                 if ( domain->primary ) {
1537                         DEBUG(10,("trusted_domains(ads):  Searching "
1538                                   "trusted domain list of %s and storing "
1539                                   "trust flags for domain %s\n",
1540                                   domain->name, d.alt_name));
1541
1542                         d.domain_flags = trust->trust_flags;
1543                         d.domain_type = trust->trust_type;
1544                         d.domain_trust_attribs = trust->trust_attributes;
1545
1546                         wcache_tdc_add_domain( &d );
1547                         ret_count++;
1548                 } else if (domain_is_forest_root(domain)) {
1549                         /* Check if we already have this record. If
1550                          * we are following our forest root that is not
1551                          * our primary domain, we want to keep trust
1552                          * flags from the perspective of our primary
1553                          * domain not our forest root. */
1554                         struct winbindd_tdc_domain *exist = NULL;
1555
1556                         exist = wcache_tdc_fetch_domain(
1557                                 talloc_tos(), trust->netbios_name);
1558                         if (!exist) {
1559                                 DEBUG(10,("trusted_domains(ads):  Searching "
1560                                           "trusted domain list of %s and "
1561                                           "storing trust flags for domain "
1562                                           "%s\n", domain->name, d.alt_name));
1563                                 d.domain_flags = trust->trust_flags;
1564                                 d.domain_type = trust->trust_type;
1565                                 d.domain_trust_attribs =
1566                                         trust->trust_attributes;
1567
1568                                 wcache_tdc_add_domain( &d );
1569                                 ret_count++;
1570                         }
1571                         TALLOC_FREE(exist);
1572                 } else {
1573                         /* This gets a little tricky.  If we are
1574                            following a transitive forest trust, then
1575                            innerit the flags, type, and attribs from
1576                            the domain we queried to make sure we don't
1577                            record the view of the trust from the wrong
1578                            side.  Always view it from the side of our
1579                            primary domain.   --jerry */
1580                         struct winbindd_tdc_domain *parent = NULL;
1581
1582                         DEBUG(10,("trusted_domains(ads):  Searching "
1583                                   "trusted domain list of %s and inheriting "
1584                                   "trust flags for domain %s\n",
1585                                   domain->name, d.alt_name));
1586
1587                         parent = wcache_tdc_fetch_domain(talloc_tos(),
1588                                                          domain->name);
1589                         if (parent) {
1590                                 d.domain_flags = parent->trust_flags;
1591                                 d.domain_type  = parent->trust_type;
1592                                 d.domain_trust_attribs = parent->trust_attribs;
1593                         } else {
1594                                 d.domain_flags = domain->domain_flags;
1595                                 d.domain_type  = domain->domain_type;
1596                                 d.domain_trust_attribs =
1597                                         domain->domain_trust_attribs;
1598                         }
1599                         TALLOC_FREE(parent);
1600
1601                         wcache_tdc_add_domain( &d );
1602                         ret_count++;
1603                 }
1604         }
1605         return result;
1606 }
1607
1608 /* the ADS backend methods are exposed via this structure */
1609 struct winbindd_methods ads_methods = {
1610         True,
1611         query_user_list,
1612         enum_dom_groups,
1613         enum_local_groups,
1614         name_to_sid,
1615         sid_to_name,
1616         rids_to_names,
1617         query_user,
1618         lookup_usergroups,
1619         lookup_useraliases,
1620         lookup_groupmem,
1621         sequence_number,
1622         lockout_policy,
1623         password_policy,
1624         trusted_domains,
1625 };
1626
1627 #endif