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