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