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