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