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