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