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