Added ability to remove id mappings in wbinfo and libwbclient.
[tprouty/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
27 #ifdef HAVE_ADS
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_WINBIND
31
32 extern struct winbindd_methods reconnect_methods;
33
34 /*
35   return our ads connections structure for a domain. We keep the connection
36   open to make things faster
37 */
38 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
39 {
40         ADS_STRUCT *ads;
41         ADS_STATUS status;
42         fstring dc_name;
43         struct sockaddr_storage dc_ss;
44
45         DEBUG(10,("ads_cached_connection\n"));
46
47         if (domain->private_data) {
48
49                 time_t expire;
50                 time_t now = time(NULL);
51
52                 /* check for a valid structure */
53                 ads = (ADS_STRUCT *)domain->private_data;
54
55                 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
56
57                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
58                           (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
59
60                 if ( ads->config.realm && (expire > now)) {
61                         return ads;
62                 } else {
63                         /* we own this ADS_STRUCT so make sure it goes away */
64                         DEBUG(7,("Deleting expired krb5 credential cache\n"));
65                         ads->is_mine = True;
66                         ads_destroy( &ads );
67                         ads_kdestroy("MEMORY:winbind_ccache");
68                         domain->private_data = NULL;
69                 }
70         }
71
72         /* we don't want this to affect the users ccache */
73         setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
74
75         ads = ads_init(domain->alt_name, domain->name, NULL);
76         if (!ads) {
77                 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
78                 return NULL;
79         }
80
81         /* the machine acct password might have change - fetch it every time */
82
83         SAFE_FREE(ads->auth.password);
84         SAFE_FREE(ads->auth.realm);
85
86         if ( IS_DC ) {
87                 DOM_SID sid;
88                 time_t last_set_time;
89
90                 if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, &sid, &last_set_time ) ) {
91                         ads_destroy( &ads );
92                         return NULL;
93                 }
94                 ads->auth.realm = SMB_STRDUP( ads->server.realm );
95                 strupper_m( ads->auth.realm );
96         }
97         else {
98                 struct winbindd_domain *our_domain = domain;
99
100                 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
101
102                 /* always give preference to the alt_name in our
103                    primary domain if possible */
104
105                 if ( !domain->primary )
106                         our_domain = find_our_domain();
107
108                 if ( our_domain->alt_name[0] != '\0' ) {
109                         ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
110                         strupper_m( ads->auth.realm );
111                 }
112                 else
113                         ads->auth.realm = SMB_STRDUP( lp_realm() );
114         }
115
116         ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
117
118         /* Setup the server affinity cache.  We don't reaally care
119            about the name.  Just setup affinity and the KRB5_CONFIG
120            file. */
121
122         get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
123
124         status = ads_connect(ads);
125         if (!ADS_ERR_OK(status) || !ads->config.realm) {
126                 DEBUG(1,("ads_connect for domain %s failed: %s\n",
127                          domain->name, ads_errstr(status)));
128                 ads_destroy(&ads);
129
130                 /* if we get ECONNREFUSED then it might be a NT4
131                    server, fall back to MSRPC */
132                 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
133                     status.err.rc == ECONNREFUSED) {
134                         /* 'reconnect_methods' is the MS-RPC backend. */
135                         DEBUG(1,("Trying MSRPC methods\n"));
136                         domain->backend = &reconnect_methods;
137                 }
138                 return NULL;
139         }
140
141         /* set the flag that says we don't own the memory even
142            though we do so that ads_destroy() won't destroy the
143            structure we pass back by reference */
144
145         ads->is_mine = False;
146
147         domain->private_data = (void *)ads;
148         return ads;
149 }
150
151
152 /* Query display info for a realm. This is the basic user list fn */
153 static NTSTATUS query_user_list(struct winbindd_domain *domain,
154                                TALLOC_CTX *mem_ctx,
155                                uint32 *num_entries, 
156                                WINBIND_USERINFO **info)
157 {
158         ADS_STRUCT *ads = NULL;
159         const char *attrs[] = { "*", NULL };
160         int i, count;
161         ADS_STATUS rc;
162         LDAPMessage *res = NULL;
163         LDAPMessage *msg = NULL;
164         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
165
166         *num_entries = 0;
167
168         DEBUG(3,("ads: query_user_list\n"));
169
170         if ( !winbindd_can_contact_domain( domain ) ) {
171                 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
172                           domain->name));               
173                 return NT_STATUS_OK;
174         }
175
176         ads = ads_cached_connection(domain);
177         
178         if (!ads) {
179                 domain->last_status = NT_STATUS_SERVER_DISABLED;
180                 goto done;
181         }
182
183         rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
184         if (!ADS_ERR_OK(rc) || !res) {
185                 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
186                 goto done;
187         }
188
189         count = ads_count_replies(ads, res);
190         if (count == 0) {
191                 DEBUG(1,("query_user_list: No users found\n"));
192                 goto done;
193         }
194
195         (*info) = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, count);
196         if (!*info) {
197                 status = NT_STATUS_NO_MEMORY;
198                 goto done;
199         }
200
201         i = 0;
202
203         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
204                 char *name, *gecos = NULL;
205                 char *homedir = NULL;
206                 char *shell = NULL;
207                 uint32 group;
208                 uint32 atype;
209                 DOM_SID user_sid;
210                 gid_t primary_gid = (gid_t)-1;
211
212                 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
213                     ads_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                 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 /* If you are looking for "dn_lookup": Yes, it used to be here!
405  * It has gone now since it was a major speed bottleneck in
406  * lookup_groupmem (its only use). It has been replaced by
407  * an rpc lookup sids call... R.I.P. */
408
409 /* Lookup user information from a rid */
410 static NTSTATUS query_user(struct winbindd_domain *domain, 
411                            TALLOC_CTX *mem_ctx, 
412                            const DOM_SID *sid, 
413                            WINBIND_USERINFO *info)
414 {
415         ADS_STRUCT *ads = NULL;
416         const char *attrs[] = { "*", NULL };
417         ADS_STATUS rc;
418         int count;
419         LDAPMessage *msg = NULL;
420         char *ldap_exp;
421         char *sidstr;
422         uint32 group_rid;
423         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
424         struct netr_SamInfo3 *user = NULL;
425
426         DEBUG(3,("ads: query_user\n"));
427
428         info->homedir = NULL;
429         info->shell = NULL;
430         info->primary_gid = (gid_t)-1;
431
432         /* try netsamlogon cache first */
433                         
434         if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) 
435         {
436                                 
437                 DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
438                          sid_string_dbg(sid)));
439
440                 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
441                 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
442                                 
443                 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
444                 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
445                 
446                 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
447                               &info->homedir, &info->shell, &info->full_name, 
448                               &info->primary_gid );     
449
450                 TALLOC_FREE(user);
451                                 
452                 return NT_STATUS_OK;
453         }
454
455         if ( !winbindd_can_contact_domain(domain)) {
456                 DEBUG(8,("query_user: No incoming trust from domain %s\n",
457                          domain->name));
458
459                 /* We still need to generate some basic information
460                    about the user even if we cannot contact the 
461                    domain.  Most of this stuff we can deduce. */
462
463                 sid_copy( &info->user_sid, sid );
464
465                 /* Assume "Domain Users" for the primary group */
466
467                 sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS );
468
469                 /* Try to fill in what the nss_info backend can do */
470
471                 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
472                               &info->homedir, &info->shell, &info->full_name, 
473                               &info->primary_gid );
474
475                 status = NT_STATUS_OK;
476                 goto done;
477         }
478
479         /* no cache...do the query */
480
481         if ( (ads = ads_cached_connection(domain)) == NULL ) {
482                 domain->last_status = NT_STATUS_SERVER_DISABLED;
483                 goto done;
484         }
485
486         sidstr = sid_binstring(sid);
487         asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
488         rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
489         free(ldap_exp);
490         free(sidstr);
491         if (!ADS_ERR_OK(rc) || !msg) {
492                 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
493                          sid_string_dbg(sid), ads_errstr(rc)));
494                 goto done;
495         }
496
497         count = ads_count_replies(ads, msg);
498         if (count != 1) {
499                 DEBUG(1,("query_user(sid=%s): Not found\n",
500                          sid_string_dbg(sid)));
501                 goto done;
502         }
503
504         info->acct_name = ads_pull_username(ads, mem_ctx, msg);
505
506         nss_get_info_cached( domain, sid, mem_ctx, ads, msg, 
507                       &info->homedir, &info->shell, &info->full_name, 
508                       &info->primary_gid );     
509
510         if (info->full_name == NULL) {
511                 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
512         }
513
514         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
515                 DEBUG(1,("No primary group for %s !?\n",
516                          sid_string_dbg(sid)));
517                 goto done;
518         }
519
520         sid_copy(&info->user_sid, sid);
521         sid_compose(&info->group_sid, &domain->sid, group_rid);
522
523         status = NT_STATUS_OK;
524
525         DEBUG(3,("ads query_user gave %s\n", info->acct_name));
526 done:
527         if (msg) 
528                 ads_msgfree(ads, msg);
529
530         return status;
531 }
532
533 /* Lookup groups a user is a member of - alternate method, for when
534    tokenGroups are not available. */
535 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
536                                          TALLOC_CTX *mem_ctx,
537                                          const char *user_dn, 
538                                          DOM_SID *primary_group,
539                                          size_t *p_num_groups, DOM_SID **user_sids)
540 {
541         ADS_STATUS rc;
542         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
543         int count;
544         LDAPMessage *res = NULL;
545         LDAPMessage *msg = NULL;
546         char *ldap_exp;
547         ADS_STRUCT *ads;
548         const char *group_attrs[] = {"objectSid", NULL};
549         char *escaped_dn;
550         size_t num_groups = 0;
551
552         DEBUG(3,("ads: lookup_usergroups_member\n"));
553
554         if ( !winbindd_can_contact_domain( domain ) ) {
555                 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
556                           domain->name));               
557                 return NT_STATUS_OK;
558         }
559
560         ads = ads_cached_connection(domain);
561
562         if (!ads) {
563                 domain->last_status = NT_STATUS_SERVER_DISABLED;
564                 goto done;
565         }
566
567         if (!(escaped_dn = escape_ldap_string_alloc(user_dn))) {
568                 status = NT_STATUS_NO_MEMORY;
569                 goto done;
570         }
571
572         ldap_exp = talloc_asprintf(mem_ctx,
573                 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
574                 escaped_dn,
575                 ADS_LDAP_MATCHING_RULE_BIT_AND,
576                 GROUP_TYPE_SECURITY_ENABLED);
577         if (!ldap_exp) {
578                 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
579                 SAFE_FREE(escaped_dn);
580                 status = NT_STATUS_NO_MEMORY;
581                 goto done;
582         }
583
584         SAFE_FREE(escaped_dn);
585
586         rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
587         
588         if (!ADS_ERR_OK(rc) || !res) {
589                 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
590                 return ads_ntstatus(rc);
591         }
592         
593         count = ads_count_replies(ads, res);
594         
595         *user_sids = NULL;
596         num_groups = 0;
597
598         /* always add the primary group to the sid array */
599         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
600                                   &num_groups);
601         if (!NT_STATUS_IS_OK(status)) {
602                 goto done;
603         }
604
605         if (count > 0) {
606                 for (msg = ads_first_entry(ads, res); msg;
607                      msg = ads_next_entry(ads, msg)) {
608                         DOM_SID group_sid;
609                 
610                         if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
611                                 DEBUG(1,("No sid for this group ?!?\n"));
612                                 continue;
613                         }
614         
615                         /* ignore Builtin groups from ADS - Guenther */
616                         if (sid_check_is_in_builtin(&group_sid)) {
617                                 continue;
618                         }
619
620                         status = add_sid_to_array(mem_ctx, &group_sid,
621                                                   user_sids, &num_groups);
622                         if (!NT_STATUS_IS_OK(status)) {
623                                 goto done;
624                         }
625                 }
626
627         }
628
629         *p_num_groups = num_groups;
630         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
631
632         DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
633 done:
634         if (res) 
635                 ads_msgfree(ads, res);
636
637         return status;
638 }
639
640 /* Lookup groups a user is a member of - alternate method, for when
641    tokenGroups are not available. */
642 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
643                                            TALLOC_CTX *mem_ctx,
644                                            const char *user_dn,
645                                            DOM_SID *primary_group,
646                                            size_t *p_num_groups,
647                                            DOM_SID **user_sids)
648 {
649         ADS_STATUS rc;
650         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
651         ADS_STRUCT *ads;
652         const char *attrs[] = {"memberOf", NULL};
653         size_t num_groups = 0;
654         DOM_SID *group_sids = NULL;
655         int i;
656         char **strings = NULL;
657         size_t num_strings = 0, num_sids = 0;
658
659
660         DEBUG(3,("ads: lookup_usergroups_memberof\n"));
661
662         if ( !winbindd_can_contact_domain( domain ) ) {
663                 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
664                           "domain %s\n", domain->name));
665                 return NT_STATUS_OK;
666         }
667
668         ads = ads_cached_connection(domain);
669
670         if (!ads) {
671                 domain->last_status = NT_STATUS_SERVER_DISABLED;
672                 return NT_STATUS_UNSUCCESSFUL;
673         }
674
675         rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
676                                                  ADS_EXTENDED_DN_HEX_STRING,
677                                                  &strings, &num_strings);
678
679         if (!ADS_ERR_OK(rc)) {
680                 DEBUG(1,("lookup_usergroups_memberof ads_search "
681                         "member=%s: %s\n", user_dn, ads_errstr(rc)));
682                 return ads_ntstatus(rc);
683         }
684
685         *user_sids = NULL;
686         num_groups = 0;
687
688         /* always add the primary group to the sid array */
689         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
690                                   &num_groups);
691         if (!NT_STATUS_IS_OK(status)) {
692                 goto done;
693         }
694
695         group_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_strings + 1);
696         if (!group_sids) {
697                 status = NT_STATUS_NO_MEMORY;
698                 goto done;
699         }
700
701         for (i=0; i<num_strings; i++) {
702                 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
703                                                   ADS_EXTENDED_DN_HEX_STRING,
704                                                   &(group_sids)[i]);
705                 if (!ADS_ERR_OK(rc)) {
706                         /* ignore members without SIDs */
707                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
708                             NT_STATUS_NOT_FOUND)) {
709                                 continue;
710                         }
711                         else {
712                                 status = ads_ntstatus(rc);
713                                 goto done;
714                         }
715                 }
716                 num_sids++;
717         }
718
719         if (i == 0) {
720                 DEBUG(1,("No memberOf for this user?!?\n"));
721                 status = NT_STATUS_NO_MEMORY;
722                 goto done;
723         }
724
725         for (i=0; i<num_sids; i++) {
726
727                 /* ignore Builtin groups from ADS - Guenther */
728                 if (sid_check_is_in_builtin(&group_sids[i])) {
729                         continue;
730                 }
731
732                 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
733                                           &num_groups);
734                 if (!NT_STATUS_IS_OK(status)) {
735                         goto done;
736                 }
737
738         }
739
740         *p_num_groups = num_groups;
741         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
742
743         DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
744                 user_dn));
745
746 done:
747         TALLOC_FREE(strings);
748         TALLOC_FREE(group_sids);
749
750         return status;
751 }
752
753
754 /* Lookup groups a user is a member of. */
755 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
756                                   TALLOC_CTX *mem_ctx,
757                                   const DOM_SID *sid, 
758                                   uint32 *p_num_groups, DOM_SID **user_sids)
759 {
760         ADS_STRUCT *ads = NULL;
761         const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
762         ADS_STATUS rc;
763         int count;
764         LDAPMessage *msg = NULL;
765         char *user_dn = NULL;
766         DOM_SID *sids;
767         int i;
768         DOM_SID primary_group;
769         uint32 primary_group_rid;
770         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
771         size_t num_groups = 0;
772
773         DEBUG(3,("ads: lookup_usergroups\n"));
774         *p_num_groups = 0;
775
776         status = lookup_usergroups_cached(domain, mem_ctx, sid, 
777                                           p_num_groups, user_sids);
778         if (NT_STATUS_IS_OK(status)) {
779                 return NT_STATUS_OK;
780         }
781
782         if ( !winbindd_can_contact_domain( domain ) ) {
783                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
784                           domain->name));
785
786                 /* Tell the cache manager not to remember this one */
787
788                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
789         }
790
791         ads = ads_cached_connection(domain);
792         
793         if (!ads) {
794                 domain->last_status = NT_STATUS_SERVER_DISABLED;
795                 status = NT_STATUS_SERVER_DISABLED;
796                 goto done;
797         }
798
799         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
800
801         if (!ADS_ERR_OK(rc)) {
802                 status = ads_ntstatus(rc);
803                 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
804                           "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
805                 goto done;
806         }
807         
808         count = ads_count_replies(ads, msg);
809         if (count != 1) {
810                 status = NT_STATUS_UNSUCCESSFUL;
811                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
812                          "invalid number of results (count=%d)\n", 
813                          sid_string_dbg(sid), count));
814                 goto done;
815         }
816
817         if (!msg) {
818                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
819                          sid_string_dbg(sid)));
820                 status = NT_STATUS_UNSUCCESSFUL;
821                 goto done;
822         }
823
824         user_dn = ads_get_dn(ads, msg);
825         if (user_dn == NULL) {
826                 status = NT_STATUS_NO_MEMORY;
827                 goto done;
828         }
829
830         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
831                 DEBUG(1,("%s: No primary group for sid=%s !?\n", 
832                          domain->name, sid_string_dbg(sid)));
833                 goto done;
834         }
835
836         sid_copy(&primary_group, &domain->sid);
837         sid_append_rid(&primary_group, primary_group_rid);
838
839         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
840
841         /* there must always be at least one group in the token, 
842            unless we are talking to a buggy Win2k server */
843
844         /* actually this only happens when the machine account has no read
845          * permissions on the tokenGroup attribute - gd */
846
847         if (count == 0) {
848
849                 /* no tokenGroups */
850                 
851                 /* lookup what groups this user is a member of by DN search on
852                  * "memberOf" */
853
854                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
855                                                     &primary_group,
856                                                     &num_groups, user_sids);
857                 *p_num_groups = (uint32)num_groups;
858                 if (NT_STATUS_IS_OK(status)) {
859                         goto done;
860                 }
861
862                 /* lookup what groups this user is a member of by DN search on
863                  * "member" */
864
865                 status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
866                                                   &primary_group,
867                                                   &num_groups, user_sids);
868                 *p_num_groups = (uint32)num_groups;
869                 goto done;
870         }
871
872         *user_sids = NULL;
873         num_groups = 0;
874
875         status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
876                                   &num_groups);
877         if (!NT_STATUS_IS_OK(status)) {
878                 goto done;
879         }
880         
881         for (i=0;i<count;i++) {
882
883                 /* ignore Builtin groups from ADS - Guenther */
884                 if (sid_check_is_in_builtin(&sids[i])) {
885                         continue;
886                 }
887
888                 status = add_sid_to_array_unique(mem_ctx, &sids[i],
889                                                  user_sids, &num_groups);
890                 if (!NT_STATUS_IS_OK(status)) {
891                         goto done;
892                 }
893         }
894
895         *p_num_groups = (uint32)num_groups;
896         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
897
898         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
899                  sid_string_dbg(sid)));
900 done:
901         ads_memfree(ads, user_dn);
902         ads_msgfree(ads, msg);
903         return status;
904 }
905
906 /*
907   find the members of a group, given a group rid and domain
908  */
909 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
910                                 TALLOC_CTX *mem_ctx,
911                                 const DOM_SID *group_sid, uint32 *num_names,
912                                 DOM_SID **sid_mem, char ***names,
913                                 uint32 **name_types)
914 {
915         ADS_STATUS rc;
916         ADS_STRUCT *ads = NULL;
917         char *ldap_exp;
918         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
919         char *sidbinstr;
920         char **members = NULL;
921         int i;
922         size_t num_members = 0;
923         ads_control args;
924         struct rpc_pipe_client *cli;
925         POLICY_HND lsa_policy;
926         DOM_SID *sid_mem_nocache = NULL;
927         char **names_nocache = NULL;
928         enum lsa_SidType *name_types_nocache = NULL;
929         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
930         uint32 num_nocache = 0;
931         TALLOC_CTX *tmp_ctx = NULL;
932
933         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
934                   sid_string_dbg(group_sid)));
935
936         *num_names = 0;
937
938         tmp_ctx = talloc_new(mem_ctx);
939         if (!tmp_ctx) {
940                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
941                 status = NT_STATUS_NO_MEMORY;
942                 goto done;
943         }
944
945         if ( !winbindd_can_contact_domain( domain ) ) {
946                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
947                           domain->name));
948                 return NT_STATUS_OK;
949         }
950
951         ads = ads_cached_connection(domain);
952
953         if (!ads) {
954                 domain->last_status = NT_STATUS_SERVER_DISABLED;
955                 goto done;
956         }
957
958         if ((sidbinstr = sid_binstring(group_sid)) == NULL) {
959                 status = NT_STATUS_NO_MEMORY;
960                 goto done;
961         }
962
963         /* search for all members of the group */
964         if (!(ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)",
965                                          sidbinstr)))
966         {
967                 SAFE_FREE(sidbinstr);
968                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
969                 status = NT_STATUS_NO_MEMORY;
970                 goto done;
971         }
972         SAFE_FREE(sidbinstr);
973
974         args.control = ADS_EXTENDED_DN_OID;
975         args.val = ADS_EXTENDED_DN_HEX_STRING;
976         args.critical = True;
977
978         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
979                                ldap_exp, &args, "member", &members, &num_members);
980
981         if (!ADS_ERR_OK(rc)) {
982                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
983                 status = NT_STATUS_UNSUCCESSFUL;
984                 goto done;
985         }
986
987         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
988
989         /* Now that we have a list of sids, we need to get the
990          * lists of names and name_types belonging to these sids.
991          * even though conceptually not quite clean,  we use the
992          * RPC call lsa_lookup_sids for this since it can handle a
993          * list of sids. ldap calls can just resolve one sid at a time.
994          *
995          * At this stage, the sids are still hidden in the exetended dn
996          * member output format. We actually do a little better than
997          * stated above: In extracting the sids from the member strings,
998          * we try to resolve as many sids as possible from the
999          * cache. Only the rest is passed to the lsa_lookup_sids call. */
1000
1001         if (num_members) {
1002                 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
1003                 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
1004                 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
1005                 (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, DOM_SID, num_members);
1006
1007                 if ((members == NULL) || (*sid_mem == NULL) ||
1008                     (*names == NULL) || (*name_types == NULL) ||
1009                     (sid_mem_nocache == NULL))
1010                 {
1011                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1012                         status = NT_STATUS_NO_MEMORY;
1013                         goto done;
1014                 }
1015         }
1016         else {
1017                 (*sid_mem) = NULL;
1018                 (*names) = NULL;
1019                 (*name_types) = NULL;
1020         }
1021
1022         for (i=0; i<num_members; i++) {
1023                 enum lsa_SidType name_type;
1024                 char *name, *domain_name;
1025                 DOM_SID sid;
1026
1027                 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1028                     &sid);
1029                 if (!ADS_ERR_OK(rc)) {
1030                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1031                             NT_STATUS_NOT_FOUND)) {
1032                                 /* Group members can be objects, like Exchange
1033                                  * Public Folders, that don't have a SID.  Skip
1034                                  * them. */
1035                                 continue;
1036                         }
1037                         else {
1038                                 status = ads_ntstatus(rc);
1039                                 goto done;
1040                         }
1041                 }
1042                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1043                     &name_type)) {
1044                         DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1045                                   "cache\n", sid_string_dbg(&sid)));
1046                         sid_copy(&(*sid_mem)[*num_names], &sid);
1047                         (*names)[*num_names] = fill_domain_username_talloc(
1048                                                         *names,
1049                                                         domain_name,
1050                                                         name,
1051                                                         true);
1052
1053                         (*name_types)[*num_names] = name_type;
1054                         (*num_names)++;
1055                 }
1056                 else {
1057                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1058                                    "cache\n", sid_string_dbg(&sid)));
1059                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1060                         num_nocache++;
1061                 }
1062         }
1063
1064         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1065                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1066
1067         /* handle sids not resolved from cache by lsa_lookup_sids */
1068         if (num_nocache > 0) {
1069
1070                 status = cm_connect_lsa(domain, tmp_ctx, &cli, &lsa_policy);
1071
1072                 if (!NT_STATUS_IS_OK(status)) {
1073                         goto done;
1074                 }
1075
1076                 status = rpccli_lsa_lookup_sids(cli, tmp_ctx,
1077                                                 &lsa_policy,
1078                                                 num_nocache,
1079                                                 sid_mem_nocache,
1080                                                 &domains_nocache,
1081                                                 &names_nocache,
1082                                                 &name_types_nocache);
1083
1084                 if (NT_STATUS_IS_OK(status) ||
1085                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1086                 {
1087                         /* Copy the entries over from the "_nocache" arrays
1088                          * to the result arrays, skipping the gaps the
1089                          * lookup_sids call left. */
1090                         for (i=0; i < num_nocache; i++) {
1091                                 if (((names_nocache)[i] != NULL) &&
1092                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1093                                 {
1094                                         sid_copy(&(*sid_mem)[*num_names],
1095                                                  &sid_mem_nocache[i]);
1096                                         (*names)[*num_names] =
1097                                                 fill_domain_username_talloc(
1098                                                         *names,
1099                                                         domains_nocache[i],
1100                                                         names_nocache[i],
1101                                                         true);
1102                                         (*name_types)[*num_names] = name_types_nocache[i];
1103                                         (*num_names)++;
1104                                 }
1105                         }
1106                 }
1107                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1108                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1109                                    "not map any SIDs at all.\n"));
1110                         /* Don't handle this as an error here.
1111                          * There is nothing left to do with respect to the 
1112                          * overall result... */
1113                 }
1114                 else if (!NT_STATUS_IS_OK(status)) {
1115                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
1116                                    "sids via rpc_lsa_lookup_sids: %s\n",
1117                                    (int)num_members, nt_errstr(status)));
1118                         goto done;
1119                 }
1120         }
1121
1122         status = NT_STATUS_OK;
1123         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1124                  sid_string_dbg(group_sid)));
1125
1126 done:
1127
1128         TALLOC_FREE(tmp_ctx);
1129
1130         return status;
1131 }
1132
1133 /* find the sequence number for a domain */
1134 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1135 {
1136         ADS_STRUCT *ads = NULL;
1137         ADS_STATUS rc;
1138
1139         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1140
1141         if ( !winbindd_can_contact_domain( domain ) ) {
1142                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1143                           domain->name));
1144                 *seq = time(NULL);              
1145                 return NT_STATUS_OK;
1146         }
1147
1148         *seq = DOM_SEQUENCE_NONE;
1149
1150         ads = ads_cached_connection(domain);
1151         
1152         if (!ads) {
1153                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1154                 return NT_STATUS_UNSUCCESSFUL;
1155         }
1156
1157         rc = ads_USN(ads, seq);
1158         
1159         if (!ADS_ERR_OK(rc)) {
1160         
1161                 /* its a dead connection, destroy it */
1162
1163                 if (domain->private_data) {
1164                         ads = (ADS_STRUCT *)domain->private_data;
1165                         ads->is_mine = True;
1166                         ads_destroy(&ads);
1167                         ads_kdestroy("MEMORY:winbind_ccache");
1168                         domain->private_data = NULL;
1169                 }
1170         }
1171         return ads_ntstatus(rc);
1172 }
1173
1174 /* get a list of trusted domains */
1175 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1176                                 TALLOC_CTX *mem_ctx,
1177                                 uint32 *num_domains,
1178                                 char ***names,
1179                                 char ***alt_names,
1180                                 DOM_SID **dom_sids)
1181 {
1182         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1183         struct netr_DomainTrustList trusts;
1184         int                     i;
1185         uint32                  flags;  
1186         struct rpc_pipe_client *cli;
1187         uint32                 fr_flags = (NETR_TRUST_FLAG_IN_FOREST | NETR_TRUST_FLAG_TREEROOT);
1188         int ret_count;
1189         
1190         DEBUG(3,("ads: trusted_domains\n"));
1191
1192         *num_domains = 0;
1193         *alt_names   = NULL;
1194         *names       = NULL;
1195         *dom_sids    = NULL;
1196
1197         /* If this is our primary domain or a root in our forest,
1198            query for all trusts.  If not, then just look for domain
1199            trusts in the target forest */
1200
1201         if ( domain->primary ||
1202                 ((domain->domain_flags&fr_flags) == fr_flags) ) 
1203         {
1204                 flags = NETR_TRUST_FLAG_OUTBOUND |
1205                         NETR_TRUST_FLAG_INBOUND |
1206                         NETR_TRUST_FLAG_IN_FOREST;
1207         } else {
1208                 flags = NETR_TRUST_FLAG_IN_FOREST;
1209         }       
1210
1211         result = cm_connect_netlogon(domain, &cli);
1212
1213         if (!NT_STATUS_IS_OK(result)) {
1214                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1215                           "for PIPE_NETLOGON (%s)\n", 
1216                           domain->name, nt_errstr(result)));
1217                 return NT_STATUS_UNSUCCESSFUL;
1218         }
1219
1220         result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
1221                                                       cli->desthost,
1222                                                       flags,
1223                                                       &trusts,
1224                                                       NULL);
1225         if ( NT_STATUS_IS_OK(result) && trusts.count) {
1226
1227                 /* Allocate memory for trusted domain names and sids */
1228
1229                 if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) {
1230                         DEBUG(0, ("trusted_domains: out of memory\n"));
1231                         return NT_STATUS_NO_MEMORY;
1232                 }
1233
1234                 if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) {
1235                         DEBUG(0, ("trusted_domains: out of memory\n"));
1236                         return NT_STATUS_NO_MEMORY;
1237                 }
1238
1239                 if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, trusts.count)) ) {
1240                         DEBUG(0, ("trusted_domains: out of memory\n"));
1241                         return NT_STATUS_NO_MEMORY;
1242                 }
1243
1244                 /* Copy across names and sids */
1245
1246
1247                 ret_count = 0;          
1248                 for (i = 0; i < trusts.count; i++) {
1249                         struct winbindd_domain d;
1250                         
1251                         ZERO_STRUCT(d);
1252
1253                         /* drop external trusts if this is not our primary 
1254                            domain.  This means that the returned number of 
1255                            domains may be less that the ones actually trusted
1256                            by the DC. */
1257
1258                         if ( (trusts.array[i].trust_attributes == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1259                              !domain->primary ) 
1260                         {
1261                                 DEBUG(10,("trusted_domains: Skipping external trusted domain "
1262                                           "%s because it is outside of our primary domain\n",
1263                                           trusts.array[i].netbios_name));
1264                                 continue;                               
1265                         }
1266                         
1267                         (*names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].netbios_name);
1268                         (*alt_names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].dns_name);
1269                         if (trusts.array[i].sid) {
1270                                 sid_copy(&(*dom_sids)[ret_count], trusts.array[i].sid);
1271                         } else {
1272                                 sid_copy(&(*dom_sids)[ret_count], &global_sid_NULL);
1273                         }
1274
1275                         /* add to the trusted domain cache */
1276
1277                         fstrcpy( d.name,  trusts.array[i].netbios_name);
1278                         fstrcpy( d.alt_name, trusts.array[i].dns_name);
1279                         if (trusts.array[i].sid) {
1280                                 sid_copy( &d.sid, trusts.array[i].sid);
1281                         } else {
1282                                 sid_copy(&d.sid, &global_sid_NULL);
1283                         }
1284
1285                         if ( domain->primary ) {
1286                                 DEBUG(10,("trusted_domains(ads):  Searching "
1287                                           "trusted domain list of %s and storing "
1288                                           "trust flags for domain %s\n", 
1289                                           domain->name, d.alt_name));
1290
1291                                 d.domain_flags = trusts.array[i].trust_flags;
1292                                 d.domain_type = trusts.array[i].trust_type;
1293                                 d.domain_trust_attribs = trusts.array[i].trust_attributes;
1294
1295                                 wcache_tdc_add_domain( &d );
1296                                 ret_count++;
1297                         } else if ( (domain->domain_flags&fr_flags) == fr_flags ) {
1298                                 /* Check if we already have this record. If
1299                                  * we are following our forest root that is not
1300                                  * our primary domain, we want to keep trust
1301                                  * flags from the perspective of our primary
1302                                  * domain not our forest root. */
1303                                 struct winbindd_tdc_domain *exist = NULL;
1304
1305                                 exist = 
1306                                     wcache_tdc_fetch_domain(NULL, trusts.array[i].netbios_name);
1307                                 if (!exist) {
1308                                         DEBUG(10,("trusted_domains(ads):  Searching "
1309                                                   "trusted domain list of %s and storing "
1310                                                   "trust flags for domain %s\n", 
1311                                                   domain->name, d.alt_name));
1312                                         d.domain_flags = trusts.array[i].trust_flags;
1313                                         d.domain_type = trusts.array[i].trust_type;
1314                                         d.domain_trust_attribs = trusts.array[i].trust_attributes;
1315
1316                                         wcache_tdc_add_domain( &d );
1317                                         ret_count++;
1318                                 }
1319                                 TALLOC_FREE(exist);
1320                         } else {
1321                                 /* This gets a little tricky.  If we are
1322                                    following a transitive forest trust, then
1323                                    innerit the flags, type, and attribs from
1324                                    the domain we queried to make sure we don't
1325                                    record the view of the trust from the wrong
1326                                    side.  Always view it from the side of our
1327                                    primary domain.   --jerry */
1328                                 struct winbindd_tdc_domain *parent = NULL;
1329
1330                                 DEBUG(10,("trusted_domains(ads):  Searching "
1331                                           "trusted domain list of %s and inheriting "
1332                                           "trust flags for domain %s\n", 
1333                                           domain->name, d.alt_name));
1334
1335                                 parent = wcache_tdc_fetch_domain(NULL, domain->name);
1336                                 if (parent) {
1337                                         d.domain_flags = parent->trust_flags;
1338                                         d.domain_type  = parent->trust_type;
1339                                         d.domain_trust_attribs = parent->trust_attribs;
1340                                 } else {
1341                                         d.domain_flags = domain->domain_flags;
1342                                         d.domain_type  = domain->domain_type;
1343                                         d.domain_trust_attribs = domain->domain_trust_attribs;
1344                                 }
1345                                 TALLOC_FREE(parent);
1346                                 
1347                                 wcache_tdc_add_domain( &d );
1348                                 ret_count++;
1349                         }
1350                 }
1351
1352                 *num_domains = ret_count;       
1353         }
1354
1355         return result;
1356 }
1357
1358 /* the ADS backend methods are exposed via this structure */
1359 struct winbindd_methods ads_methods = {
1360         True,
1361         query_user_list,
1362         enum_dom_groups,
1363         enum_local_groups,
1364         msrpc_name_to_sid,
1365         msrpc_sid_to_name,
1366         msrpc_rids_to_names,
1367         query_user,
1368         lookup_usergroups,
1369         msrpc_lookup_useraliases,
1370         lookup_groupmem,
1371         sequence_number,
1372         msrpc_lockout_policy,
1373         msrpc_password_policy,
1374         trusted_domains,
1375 };
1376
1377 #endif