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