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