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