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