s3:rpc_client: implement bind time feature negotiation
[metze/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                             const char **pdom_name,
562                             struct dom_sid *sid,
563                             enum lsa_SidType *type)
564 {
565         return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
566                                          flags, pdom_name, sid, type);
567 }
568
569 /* convert a domain SID to a user or group name - use rpc methods */
570 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
571                             TALLOC_CTX *mem_ctx,
572                             const struct dom_sid *sid,
573                             char **domain_name,
574                             char **name,
575                             enum lsa_SidType *type)
576 {
577         return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
578                                          domain_name, name, type);
579 }
580
581 /* convert a list of rids to names - use rpc methods */
582 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
583                               TALLOC_CTX *mem_ctx,
584                               const struct dom_sid *sid,
585                               uint32_t *rids,
586                               size_t num_rids,
587                               char **domain_name,
588                               char ***names,
589                               enum lsa_SidType **types)
590 {
591         return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
592                                            rids, num_rids,
593                                            domain_name, names, types);
594 }
595
596 /* Lookup groups a user is a member of - alternate method, for when
597    tokenGroups are not available. */
598 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
599                                          TALLOC_CTX *mem_ctx,
600                                          const char *user_dn, 
601                                          struct dom_sid *primary_group,
602                                          uint32_t *p_num_groups, struct dom_sid **user_sids)
603 {
604         ADS_STATUS rc;
605         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
606         int count;
607         LDAPMessage *res = NULL;
608         LDAPMessage *msg = NULL;
609         char *ldap_exp;
610         ADS_STRUCT *ads;
611         const char *group_attrs[] = {"objectSid", NULL};
612         char *escaped_dn;
613         uint32_t num_groups = 0;
614
615         DEBUG(3,("ads: lookup_usergroups_member\n"));
616
617         if ( !winbindd_can_contact_domain( domain ) ) {
618                 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
619                           domain->name));               
620                 return NT_STATUS_OK;
621         }
622
623         ads = ads_cached_connection(domain);
624
625         if (!ads) {
626                 domain->last_status = NT_STATUS_SERVER_DISABLED;
627                 goto done;
628         }
629
630         if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
631                 status = NT_STATUS_NO_MEMORY;
632                 goto done;
633         }
634
635         ldap_exp = talloc_asprintf(mem_ctx,
636                 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
637                 escaped_dn,
638                 ADS_LDAP_MATCHING_RULE_BIT_AND,
639                 GROUP_TYPE_SECURITY_ENABLED);
640         if (!ldap_exp) {
641                 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
642                 TALLOC_FREE(escaped_dn);
643                 status = NT_STATUS_NO_MEMORY;
644                 goto done;
645         }
646
647         TALLOC_FREE(escaped_dn);
648
649         rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
650
651         if (!ADS_ERR_OK(rc)) {
652                 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
653                 return ads_ntstatus(rc);
654         } else if (!res) {
655                 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
656                 return NT_STATUS_INTERNAL_ERROR;
657         }
658
659
660         count = ads_count_replies(ads, res);
661
662         *user_sids = NULL;
663         num_groups = 0;
664
665         /* always add the primary group to the sid array */
666         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
667                                   &num_groups);
668         if (!NT_STATUS_IS_OK(status)) {
669                 goto done;
670         }
671
672         if (count > 0) {
673                 for (msg = ads_first_entry(ads, res); msg;
674                      msg = ads_next_entry(ads, msg)) {
675                         struct dom_sid group_sid;
676
677                         if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
678                                 DEBUG(1,("No sid for this group ?!?\n"));
679                                 continue;
680                         }
681
682                         /* ignore Builtin groups from ADS - Guenther */
683                         if (sid_check_is_in_builtin(&group_sid)) {
684                                 continue;
685                         }
686
687                         status = add_sid_to_array(mem_ctx, &group_sid,
688                                                   user_sids, &num_groups);
689                         if (!NT_STATUS_IS_OK(status)) {
690                                 goto done;
691                         }
692                 }
693
694         }
695
696         *p_num_groups = num_groups;
697         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
698
699         DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
700 done:
701         if (res) 
702                 ads_msgfree(ads, res);
703
704         return status;
705 }
706
707 /* Lookup groups a user is a member of - alternate method, for when
708    tokenGroups are not available. */
709 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
710                                            TALLOC_CTX *mem_ctx,
711                                            const char *user_dn,
712                                            struct dom_sid *primary_group,
713                                            uint32_t *p_num_groups,
714                                            struct dom_sid **user_sids)
715 {
716         ADS_STATUS rc;
717         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
718         ADS_STRUCT *ads;
719         const char *attrs[] = {"memberOf", NULL};
720         uint32_t num_groups = 0;
721         struct dom_sid *group_sids = NULL;
722         size_t i;
723         char **strings = NULL;
724         size_t num_strings = 0, num_sids = 0;
725
726
727         DEBUG(3,("ads: lookup_usergroups_memberof\n"));
728
729         if ( !winbindd_can_contact_domain( domain ) ) {
730                 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
731                           "domain %s\n", domain->name));
732                 return NT_STATUS_OK;
733         }
734
735         ads = ads_cached_connection(domain);
736
737         if (!ads) {
738                 domain->last_status = NT_STATUS_SERVER_DISABLED;
739                 return NT_STATUS_UNSUCCESSFUL;
740         }
741
742         rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
743                                                  ADS_EXTENDED_DN_HEX_STRING,
744                                                  &strings, &num_strings);
745
746         if (!ADS_ERR_OK(rc)) {
747                 DEBUG(1,("lookup_usergroups_memberof ads_search "
748                         "member=%s: %s\n", user_dn, ads_errstr(rc)));
749                 return ads_ntstatus(rc);
750         }
751
752         *user_sids = NULL;
753         num_groups = 0;
754
755         /* always add the primary group to the sid array */
756         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
757                                   &num_groups);
758         if (!NT_STATUS_IS_OK(status)) {
759                 goto done;
760         }
761
762         group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
763         if (!group_sids) {
764                 status = NT_STATUS_NO_MEMORY;
765                 goto done;
766         }
767
768         for (i=0; i<num_strings; i++) {
769                 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
770                                                   ADS_EXTENDED_DN_HEX_STRING,
771                                                   &(group_sids)[i]);
772                 if (!ADS_ERR_OK(rc)) {
773                         /* ignore members without SIDs */
774                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
775                             NT_STATUS_NOT_FOUND)) {
776                                 continue;
777                         }
778                         else {
779                                 status = ads_ntstatus(rc);
780                                 goto done;
781                         }
782                 }
783                 num_sids++;
784         }
785
786         if (i == 0) {
787                 DEBUG(1,("No memberOf for this user?!?\n"));
788                 status = NT_STATUS_NO_MEMORY;
789                 goto done;
790         }
791
792         for (i=0; i<num_sids; i++) {
793
794                 /* ignore Builtin groups from ADS - Guenther */
795                 if (sid_check_is_in_builtin(&group_sids[i])) {
796                         continue;
797                 }
798
799                 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
800                                           &num_groups);
801                 if (!NT_STATUS_IS_OK(status)) {
802                         goto done;
803                 }
804
805         }
806
807         *p_num_groups = num_groups;
808         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
809
810         DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
811                 user_dn));
812
813 done:
814         TALLOC_FREE(strings);
815         TALLOC_FREE(group_sids);
816
817         return status;
818 }
819
820
821 /* Lookup groups a user is a member of. */
822 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
823                                   TALLOC_CTX *mem_ctx,
824                                   const struct dom_sid *sid,
825                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
826 {
827         ADS_STRUCT *ads = NULL;
828         const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
829         ADS_STATUS rc;
830         int count;
831         LDAPMessage *msg = NULL;
832         char *user_dn = NULL;
833         struct dom_sid *sids;
834         int i;
835         struct dom_sid primary_group;
836         uint32_t primary_group_rid;
837         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
838         uint32_t num_groups = 0;
839         struct dom_sid_buf buf;
840
841         DEBUG(3,("ads: lookup_usergroups\n"));
842         *p_num_groups = 0;
843
844         status = lookup_usergroups_cached(mem_ctx, sid,
845                                           p_num_groups, user_sids);
846         if (NT_STATUS_IS_OK(status)) {
847                 return NT_STATUS_OK;
848         }
849
850         if ( !winbindd_can_contact_domain( domain ) ) {
851                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
852                           domain->name));
853
854                 /* Tell the cache manager not to remember this one */
855
856                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
857         }
858
859         ads = ads_cached_connection(domain);
860
861         if (!ads) {
862                 domain->last_status = NT_STATUS_SERVER_DISABLED;
863                 status = NT_STATUS_SERVER_DISABLED;
864                 goto done;
865         }
866
867         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
868
869         if (!ADS_ERR_OK(rc)) {
870                 status = ads_ntstatus(rc);
871                 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
872                           "%s\n",
873                           dom_sid_str_buf(sid, &buf),
874                           ads_errstr(rc)));
875                 goto done;
876         }
877
878         count = ads_count_replies(ads, msg);
879         if (count != 1) {
880                 status = NT_STATUS_UNSUCCESSFUL;
881                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
882                          "invalid number of results (count=%d)\n", 
883                          dom_sid_str_buf(sid, &buf),
884                          count));
885                 goto done;
886         }
887
888         if (!msg) {
889                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
890                          dom_sid_str_buf(sid, &buf)));
891                 status = NT_STATUS_UNSUCCESSFUL;
892                 goto done;
893         }
894
895         user_dn = ads_get_dn(ads, mem_ctx, msg);
896         if (user_dn == NULL) {
897                 status = NT_STATUS_NO_MEMORY;
898                 goto done;
899         }
900
901         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
902                 DEBUG(1,("%s: No primary group for sid=%s !?\n", 
903                          domain->name,
904                          dom_sid_str_buf(sid, &buf)));
905                 goto done;
906         }
907
908         sid_compose(&primary_group, &domain->sid, primary_group_rid);
909
910         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
911
912         /* there must always be at least one group in the token, 
913            unless we are talking to a buggy Win2k server */
914
915         /* actually this only happens when the machine account has no read
916          * permissions on the tokenGroup attribute - gd */
917
918         if (count == 0) {
919
920                 /* no tokenGroups */
921
922                 /* lookup what groups this user is a member of by DN search on
923                  * "memberOf" */
924
925                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
926                                                     &primary_group,
927                                                     &num_groups, user_sids);
928                 *p_num_groups = num_groups;
929                 if (NT_STATUS_IS_OK(status)) {
930                         goto done;
931                 }
932
933                 /* lookup what groups this user is a member of by DN search on
934                  * "member" */
935
936                 status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
937                                                   &primary_group,
938                                                   &num_groups, user_sids);
939                 *p_num_groups = num_groups;
940                 goto done;
941         }
942
943         *user_sids = NULL;
944         num_groups = 0;
945
946         status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
947                                   &num_groups);
948         if (!NT_STATUS_IS_OK(status)) {
949                 goto done;
950         }
951
952         for (i=0;i<count;i++) {
953
954                 /* ignore Builtin groups from ADS - Guenther */
955                 if (sid_check_is_in_builtin(&sids[i])) {
956                         continue;
957                 }
958
959                 status = add_sid_to_array_unique(mem_ctx, &sids[i],
960                                                  user_sids, &num_groups);
961                 if (!NT_STATUS_IS_OK(status)) {
962                         goto done;
963                 }
964         }
965
966         *p_num_groups = (uint32_t)num_groups;
967         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
968
969         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
970                  dom_sid_str_buf(sid, &buf)));
971 done:
972         TALLOC_FREE(user_dn);
973         ads_msgfree(ads, msg);
974         return status;
975 }
976
977 /* Lookup aliases a user is member of - use rpc methods */
978 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
979                                    TALLOC_CTX *mem_ctx,
980                                    uint32_t num_sids, const struct dom_sid *sids,
981                                    uint32_t *num_aliases, uint32_t **alias_rids)
982 {
983         return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
984                                                 num_aliases, alias_rids);
985 }
986
987 static NTSTATUS add_primary_group_members(
988         ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
989         char ***all_members, size_t *num_all_members)
990 {
991         char *filter;
992         NTSTATUS status = NT_STATUS_NO_MEMORY;
993         ADS_STATUS rc;
994         const char *attrs[] = { "dn", NULL };
995         LDAPMessage *res = NULL;
996         LDAPMessage *msg;
997         char **members;
998         size_t num_members;
999         ads_control args;
1000
1001         filter = talloc_asprintf(
1002                 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1003                 (unsigned)rid);
1004         if (filter == NULL) {
1005                 goto done;
1006         }
1007
1008         args.control = ADS_EXTENDED_DN_OID;
1009         args.val = ADS_EXTENDED_DN_HEX_STRING;
1010         args.critical = True;
1011
1012         rc = ads_do_search_all_args(ads, ads->config.bind_path,
1013                                     LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1014                                     &res);
1015
1016         if (!ADS_ERR_OK(rc)) {
1017                 status = ads_ntstatus(rc);
1018                 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1019                 goto done;
1020         }
1021         if (res == NULL) {
1022                 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1023                 goto done;
1024         }
1025
1026         num_members = ads_count_replies(ads, res);
1027
1028         DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1029                    (uintmax_t)num_members));
1030
1031         if (num_members == 0) {
1032                 status = NT_STATUS_OK;
1033                 goto done;
1034         }
1035
1036         members = talloc_realloc(mem_ctx, *all_members, char *,
1037                                  *num_all_members + num_members);
1038         if (members == NULL) {
1039                 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1040                 goto done;
1041         }
1042         *all_members = members;
1043
1044         for (msg = ads_first_entry(ads, res); msg != NULL;
1045              msg = ads_next_entry(ads, msg)) {
1046                 char *dn;
1047
1048                 dn = ads_get_dn(ads, members, msg);
1049                 if (dn == NULL) {
1050                         DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1051                         continue;
1052                 }
1053
1054                 members[*num_all_members] = dn;
1055                 *num_all_members += 1;
1056         }
1057
1058         status = NT_STATUS_OK;
1059 done:
1060         if (res != NULL) {
1061                 ads_msgfree(ads, res);
1062         }
1063         TALLOC_FREE(filter);
1064         return status;
1065 }
1066
1067 /*
1068   find the members of a group, given a group rid and domain
1069  */
1070 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1071                                 TALLOC_CTX *mem_ctx,
1072                                 const struct dom_sid *group_sid,
1073                                 enum lsa_SidType type,
1074                                 uint32_t *num_names,
1075                                 struct dom_sid **sid_mem, char ***names,
1076                                 uint32_t **name_types)
1077 {
1078         ADS_STATUS rc;
1079         ADS_STRUCT *ads = NULL;
1080         char *ldap_exp;
1081         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1082         char *sidbinstr;
1083         char **members = NULL;
1084         size_t i;
1085         size_t num_members = 0;
1086         ads_control args;
1087         struct dom_sid *sid_mem_nocache = NULL;
1088         char **names_nocache = NULL;
1089         enum lsa_SidType *name_types_nocache = NULL;
1090         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
1091         uint32_t num_nocache = 0;
1092         TALLOC_CTX *tmp_ctx = NULL;
1093         uint32_t rid;
1094         struct dom_sid_buf buf;
1095
1096         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1097                   dom_sid_str_buf(group_sid, &buf)));
1098
1099         *num_names = 0;
1100
1101         tmp_ctx = talloc_new(mem_ctx);
1102         if (!tmp_ctx) {
1103                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1104                 status = NT_STATUS_NO_MEMORY;
1105                 goto done;
1106         }
1107
1108         if (!sid_peek_rid(group_sid, &rid)) {
1109                 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1110                 status = NT_STATUS_INVALID_PARAMETER;
1111                 goto done;
1112         }
1113
1114         if ( !winbindd_can_contact_domain( domain ) ) {
1115                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1116                           domain->name));
1117                 return NT_STATUS_OK;
1118         }
1119
1120         ads = ads_cached_connection(domain);
1121
1122         if (!ads) {
1123                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1124                 goto done;
1125         }
1126
1127         if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1128                 status = NT_STATUS_NO_MEMORY;
1129                 goto done;
1130         }
1131
1132         /* search for all members of the group */
1133         ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1134         TALLOC_FREE(sidbinstr);
1135         if (ldap_exp == NULL) {
1136                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1137                 status = NT_STATUS_NO_MEMORY;
1138                 goto done;
1139         }
1140
1141         args.control = ADS_EXTENDED_DN_OID;
1142         args.val = ADS_EXTENDED_DN_HEX_STRING;
1143         args.critical = True;
1144
1145         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1146                                ldap_exp, &args, "member", &members, &num_members);
1147
1148         if (!ADS_ERR_OK(rc)) {
1149                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1150                 status = NT_STATUS_UNSUCCESSFUL;
1151                 goto done;
1152         }
1153
1154         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1155
1156         status = add_primary_group_members(ads, mem_ctx, rid,
1157                                            &members, &num_members);
1158         if (!NT_STATUS_IS_OK(status)) {
1159                 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1160                            __func__, nt_errstr(status)));
1161                 goto done;
1162         }
1163
1164         DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1165                    __func__, (int)num_members));
1166
1167         /* Now that we have a list of sids, we need to get the
1168          * lists of names and name_types belonging to these sids.
1169          * even though conceptually not quite clean,  we use the
1170          * RPC call lsa_lookup_sids for this since it can handle a
1171          * list of sids. ldap calls can just resolve one sid at a time.
1172          *
1173          * At this stage, the sids are still hidden in the exetended dn
1174          * member output format. We actually do a little better than
1175          * stated above: In extracting the sids from the member strings,
1176          * we try to resolve as many sids as possible from the
1177          * cache. Only the rest is passed to the lsa_lookup_sids call. */
1178
1179         if (num_members) {
1180                 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1181                 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1182                 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1183                 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1184
1185                 if ((members == NULL) || (*sid_mem == NULL) ||
1186                     (*names == NULL) || (*name_types == NULL) ||
1187                     (sid_mem_nocache == NULL))
1188                 {
1189                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1190                         status = NT_STATUS_NO_MEMORY;
1191                         goto done;
1192                 }
1193         }
1194         else {
1195                 (*sid_mem) = NULL;
1196                 (*names) = NULL;
1197                 (*name_types) = NULL;
1198         }
1199
1200         for (i=0; i<num_members; i++) {
1201                 enum lsa_SidType name_type;
1202                 char *name, *domain_name;
1203                 struct dom_sid sid;
1204
1205                 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1206                     &sid);
1207                 if (!ADS_ERR_OK(rc)) {
1208                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1209                             NT_STATUS_NOT_FOUND)) {
1210                                 /* Group members can be objects, like Exchange
1211                                  * Public Folders, that don't have a SID.  Skip
1212                                  * them. */
1213                                 continue;
1214                         }
1215                         else {
1216                                 status = ads_ntstatus(rc);
1217                                 goto done;
1218                         }
1219                 }
1220                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1221                     &name_type)) {
1222                         DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1223                                   "cache\n",
1224                                   dom_sid_str_buf(&sid, &buf)));
1225                         sid_copy(&(*sid_mem)[*num_names], &sid);
1226                         (*names)[*num_names] = fill_domain_username_talloc(
1227                                                         *names,
1228                                                         domain_name,
1229                                                         name,
1230                                                         true);
1231
1232                         (*name_types)[*num_names] = name_type;
1233                         (*num_names)++;
1234                 }
1235                 else {
1236                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1237                                    "cache\n",
1238                                    dom_sid_str_buf(&sid, &buf)));
1239                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1240                         num_nocache++;
1241                 }
1242         }
1243
1244         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1245                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1246
1247         /* handle sids not resolved from cache by lsa_lookup_sids */
1248         if (num_nocache > 0) {
1249
1250                 status = winbindd_lookup_sids(tmp_ctx,
1251                                               domain,
1252                                               num_nocache,
1253                                               sid_mem_nocache,
1254                                               &domains_nocache,
1255                                               &names_nocache,
1256                                               &name_types_nocache);
1257
1258                 if (!(NT_STATUS_IS_OK(status) ||
1259                       NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1260                       NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1261                 {
1262                         DEBUG(1, ("lsa_lookupsids call failed with %s "
1263                                   "- retrying...\n", nt_errstr(status)));
1264
1265                         status = winbindd_lookup_sids(tmp_ctx,
1266                                                       domain,
1267                                                       num_nocache,
1268                                                       sid_mem_nocache,
1269                                                       &domains_nocache,
1270                                                       &names_nocache,
1271                                                       &name_types_nocache);
1272                 }
1273
1274                 if (NT_STATUS_IS_OK(status) ||
1275                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1276                 {
1277                         /* Copy the entries over from the "_nocache" arrays
1278                          * to the result arrays, skipping the gaps the
1279                          * lookup_sids call left. */
1280                         for (i=0; i < num_nocache; i++) {
1281                                 if (((names_nocache)[i] != NULL) &&
1282                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1283                                 {
1284                                         sid_copy(&(*sid_mem)[*num_names],
1285                                                  &sid_mem_nocache[i]);
1286                                         (*names)[*num_names] =
1287                                                 fill_domain_username_talloc(
1288                                                         *names,
1289                                                         domains_nocache[i],
1290                                                         names_nocache[i],
1291                                                         true);
1292                                         (*name_types)[*num_names] = name_types_nocache[i];
1293                                         (*num_names)++;
1294                                 }
1295                         }
1296                 }
1297                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1298                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1299                                    "not map any SIDs at all.\n"));
1300                         /* Don't handle this as an error here.
1301                          * There is nothing left to do with respect to the 
1302                          * overall result... */
1303                 }
1304                 else if (!NT_STATUS_IS_OK(status)) {
1305                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
1306                                    "sids via rpc_lsa_lookup_sids: %s\n",
1307                                    (int)num_members, nt_errstr(status)));
1308                         goto done;
1309                 }
1310         }
1311
1312         status = NT_STATUS_OK;
1313         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1314                  dom_sid_str_buf(group_sid, &buf)));
1315
1316 done:
1317
1318         TALLOC_FREE(tmp_ctx);
1319
1320         return status;
1321 }
1322
1323 /* find the sequence number for a domain */
1324 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1325 {
1326         ADS_STRUCT *ads = NULL;
1327         ADS_STATUS rc;
1328
1329         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1330
1331         if ( !winbindd_can_contact_domain( domain ) ) {
1332                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1333                           domain->name));
1334                 *seq = time(NULL);              
1335                 return NT_STATUS_OK;
1336         }
1337
1338         if (IS_AD_DC) {
1339                 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1340                           domain->name));
1341                 *seq = time(NULL);
1342                 return NT_STATUS_OK;
1343         }
1344
1345         *seq = DOM_SEQUENCE_NONE;
1346
1347         ads = ads_cached_connection(domain);
1348
1349         if (!ads) {
1350                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1351                 return NT_STATUS_UNSUCCESSFUL;
1352         }
1353
1354         rc = ads_USN(ads, seq);
1355
1356         if (!ADS_ERR_OK(rc)) {
1357
1358                 /* its a dead connection, destroy it */
1359
1360                 if (domain->private_data) {
1361                         ads = (ADS_STRUCT *)domain->private_data;
1362                         ads->is_mine = True;
1363                         ads_destroy(&ads);
1364                         ads_kdestroy(WINBIND_CCACHE_NAME);
1365                         domain->private_data = NULL;
1366                 }
1367         }
1368         return ads_ntstatus(rc);
1369 }
1370
1371 /* find the lockout policy of a domain - use rpc methods */
1372 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1373                                TALLOC_CTX *mem_ctx,
1374                                struct samr_DomInfo12 *policy)
1375 {
1376         return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1377 }
1378
1379 /* find the password policy of a domain - use rpc methods */
1380 static NTSTATUS password_policy(struct winbindd_domain *domain,
1381                                 TALLOC_CTX *mem_ctx,
1382                                 struct samr_DomInfo1 *policy)
1383 {
1384         return msrpc_methods.password_policy(domain, mem_ctx, policy);
1385 }
1386
1387 /* get a list of trusted domains */
1388 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1389                                 TALLOC_CTX *mem_ctx,
1390                                 struct netr_DomainTrustList *trusts)
1391 {
1392         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1393         WERROR werr;
1394         uint32_t                i;
1395         uint32_t                flags;
1396         struct rpc_pipe_client *cli;
1397         int ret_count;
1398         struct dcerpc_binding_handle *b;
1399
1400         DEBUG(3,("ads: trusted_domains\n"));
1401
1402         ZERO_STRUCTP(trusts);
1403
1404         /* If this is our primary domain or a root in our forest,
1405            query for all trusts.  If not, then just look for domain
1406            trusts in the target forest */
1407
1408         if (domain->primary || domain_is_forest_root(domain)) {
1409                 flags = NETR_TRUST_FLAG_OUTBOUND |
1410                         NETR_TRUST_FLAG_INBOUND |
1411                         NETR_TRUST_FLAG_IN_FOREST;
1412         } else {
1413                 flags = NETR_TRUST_FLAG_IN_FOREST;
1414         }       
1415
1416         result = cm_connect_netlogon(domain, &cli);
1417
1418         if (!NT_STATUS_IS_OK(result)) {
1419                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1420                           "for PIPE_NETLOGON (%s)\n", 
1421                           domain->name, nt_errstr(result)));
1422                 return NT_STATUS_UNSUCCESSFUL;
1423         }
1424
1425         b = cli->binding_handle;
1426
1427         result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1428                                                       cli->desthost,
1429                                                       flags,
1430                                                       trusts,
1431                                                       &werr);
1432         if (!NT_STATUS_IS_OK(result)) {
1433                 return result;
1434         }
1435
1436         if (!W_ERROR_IS_OK(werr)) {
1437                 return werror_to_ntstatus(werr);
1438         }
1439         if (trusts->count == 0) {
1440                 return NT_STATUS_OK;
1441         }
1442
1443         /* Copy across names and sids */
1444
1445         ret_count = 0;
1446         for (i = 0; i < trusts->count; i++) {
1447                 struct netr_DomainTrust *trust = &trusts->array[i];
1448                 struct winbindd_domain d;
1449
1450                 ZERO_STRUCT(d);
1451
1452                 /*
1453                  * drop external trusts if this is not our primary
1454                  * domain.  This means that the returned number of
1455                  * domains may be less that the ones actually trusted
1456                  * by the DC.
1457                  */
1458
1459                 if ((trust->trust_attributes
1460                      == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1461                     !domain->primary )
1462                 {
1463                         DEBUG(10,("trusted_domains: Skipping external trusted "
1464                                   "domain %s because it is outside of our "
1465                                   "primary domain\n",
1466                                   trust->netbios_name));
1467                         continue;
1468                 }
1469
1470                 /* add to the trusted domain cache */
1471
1472                 d.name = discard_const_p(char, trust->netbios_name);
1473                 d.alt_name = discard_const_p(char, trust->dns_name);
1474
1475                 if (trust->sid) {
1476                         sid_copy(&d.sid, trust->sid);
1477                 } else {
1478                         sid_copy(&d.sid, &global_sid_NULL);
1479                 }
1480
1481                 if ( domain->primary ) {
1482                         DEBUG(10,("trusted_domains(ads):  Searching "
1483                                   "trusted domain list of %s and storing "
1484                                   "trust flags for domain %s\n",
1485                                   domain->name, d.alt_name));
1486
1487                         d.domain_flags = trust->trust_flags;
1488                         d.domain_type = trust->trust_type;
1489                         d.domain_trust_attribs = trust->trust_attributes;
1490
1491                         wcache_tdc_add_domain( &d );
1492                         ret_count++;
1493                 } else if (domain_is_forest_root(domain)) {
1494                         /* Check if we already have this record. If
1495                          * we are following our forest root that is not
1496                          * our primary domain, we want to keep trust
1497                          * flags from the perspective of our primary
1498                          * domain not our forest root. */
1499                         struct winbindd_tdc_domain *exist = NULL;
1500
1501                         exist = wcache_tdc_fetch_domain(
1502                                 talloc_tos(), trust->netbios_name);
1503                         if (!exist) {
1504                                 DEBUG(10,("trusted_domains(ads):  Searching "
1505                                           "trusted domain list of %s and "
1506                                           "storing trust flags for domain "
1507                                           "%s\n", domain->name, d.alt_name));
1508                                 d.domain_flags = trust->trust_flags;
1509                                 d.domain_type = trust->trust_type;
1510                                 d.domain_trust_attribs =
1511                                         trust->trust_attributes;
1512
1513                                 wcache_tdc_add_domain( &d );
1514                                 ret_count++;
1515                         }
1516                         TALLOC_FREE(exist);
1517                 } else {
1518                         /* This gets a little tricky.  If we are
1519                            following a transitive forest trust, then
1520                            innerit the flags, type, and attribs from
1521                            the domain we queried to make sure we don't
1522                            record the view of the trust from the wrong
1523                            side.  Always view it from the side of our
1524                            primary domain.   --jerry */
1525                         struct winbindd_tdc_domain *parent = NULL;
1526
1527                         DEBUG(10,("trusted_domains(ads):  Searching "
1528                                   "trusted domain list of %s and inheriting "
1529                                   "trust flags for domain %s\n",
1530                                   domain->name, d.alt_name));
1531
1532                         parent = wcache_tdc_fetch_domain(talloc_tos(),
1533                                                          domain->name);
1534                         if (parent) {
1535                                 d.domain_flags = parent->trust_flags;
1536                                 d.domain_type  = parent->trust_type;
1537                                 d.domain_trust_attribs = parent->trust_attribs;
1538                         } else {
1539                                 d.domain_flags = domain->domain_flags;
1540                                 d.domain_type  = domain->domain_type;
1541                                 d.domain_trust_attribs =
1542                                         domain->domain_trust_attribs;
1543                         }
1544                         TALLOC_FREE(parent);
1545
1546                         /*
1547                          * We need to pass the modified properties
1548                          * to the caller.
1549                          */
1550                         trust->trust_flags = d.domain_flags;
1551                         trust->trust_type = d.domain_type;
1552                         trust->trust_attributes = d.domain_trust_attribs;
1553
1554                         wcache_tdc_add_domain( &d );
1555                         ret_count++;
1556                 }
1557         }
1558         return result;
1559 }
1560
1561 /* the ADS backend methods are exposed via this structure */
1562 struct winbindd_methods ads_methods = {
1563         True,
1564         query_user_list,
1565         enum_dom_groups,
1566         enum_local_groups,
1567         name_to_sid,
1568         sid_to_name,
1569         rids_to_names,
1570         lookup_usergroups,
1571         lookup_useraliases,
1572         lookup_groupmem,
1573         sequence_number,
1574         lockout_policy,
1575         password_policy,
1576         trusted_domains,
1577 };
1578
1579 #endif