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