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