b350bf0c565a7b45c5d64d5ab66884c0bb4dc4d7
[nivanova/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         int 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
839         DEBUG(3,("ads: lookup_usergroups\n"));
840         *p_num_groups = 0;
841
842         status = lookup_usergroups_cached(mem_ctx, sid,
843                                           p_num_groups, user_sids);
844         if (NT_STATUS_IS_OK(status)) {
845                 return NT_STATUS_OK;
846         }
847
848         if ( !winbindd_can_contact_domain( domain ) ) {
849                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
850                           domain->name));
851
852                 /* Tell the cache manager not to remember this one */
853
854                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
855         }
856
857         ads = ads_cached_connection(domain);
858
859         if (!ads) {
860                 domain->last_status = NT_STATUS_SERVER_DISABLED;
861                 status = NT_STATUS_SERVER_DISABLED;
862                 goto done;
863         }
864
865         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
866
867         if (!ADS_ERR_OK(rc)) {
868                 status = ads_ntstatus(rc);
869                 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
870                           "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
871                 goto done;
872         }
873
874         count = ads_count_replies(ads, msg);
875         if (count != 1) {
876                 status = NT_STATUS_UNSUCCESSFUL;
877                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
878                          "invalid number of results (count=%d)\n", 
879                          sid_string_dbg(sid), count));
880                 goto done;
881         }
882
883         if (!msg) {
884                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
885                          sid_string_dbg(sid)));
886                 status = NT_STATUS_UNSUCCESSFUL;
887                 goto done;
888         }
889
890         user_dn = ads_get_dn(ads, mem_ctx, msg);
891         if (user_dn == NULL) {
892                 status = NT_STATUS_NO_MEMORY;
893                 goto done;
894         }
895
896         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
897                 DEBUG(1,("%s: No primary group for sid=%s !?\n", 
898                          domain->name, sid_string_dbg(sid)));
899                 goto done;
900         }
901
902         sid_compose(&primary_group, &domain->sid, primary_group_rid);
903
904         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
905
906         /* there must always be at least one group in the token, 
907            unless we are talking to a buggy Win2k server */
908
909         /* actually this only happens when the machine account has no read
910          * permissions on the tokenGroup attribute - gd */
911
912         if (count == 0) {
913
914                 /* no tokenGroups */
915
916                 /* lookup what groups this user is a member of by DN search on
917                  * "memberOf" */
918
919                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
920                                                     &primary_group,
921                                                     &num_groups, user_sids);
922                 *p_num_groups = num_groups;
923                 if (NT_STATUS_IS_OK(status)) {
924                         goto done;
925                 }
926
927                 /* lookup what groups this user is a member of by DN search on
928                  * "member" */
929
930                 status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
931                                                   &primary_group,
932                                                   &num_groups, user_sids);
933                 *p_num_groups = num_groups;
934                 goto done;
935         }
936
937         *user_sids = NULL;
938         num_groups = 0;
939
940         status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
941                                   &num_groups);
942         if (!NT_STATUS_IS_OK(status)) {
943                 goto done;
944         }
945
946         for (i=0;i<count;i++) {
947
948                 /* ignore Builtin groups from ADS - Guenther */
949                 if (sid_check_is_in_builtin(&sids[i])) {
950                         continue;
951                 }
952
953                 status = add_sid_to_array_unique(mem_ctx, &sids[i],
954                                                  user_sids, &num_groups);
955                 if (!NT_STATUS_IS_OK(status)) {
956                         goto done;
957                 }
958         }
959
960         *p_num_groups = (uint32_t)num_groups;
961         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
962
963         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
964                  sid_string_dbg(sid)));
965 done:
966         TALLOC_FREE(user_dn);
967         ads_msgfree(ads, msg);
968         return status;
969 }
970
971 /* Lookup aliases a user is member of - use rpc methods */
972 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
973                                    TALLOC_CTX *mem_ctx,
974                                    uint32_t num_sids, const struct dom_sid *sids,
975                                    uint32_t *num_aliases, uint32_t **alias_rids)
976 {
977         return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
978                                                 num_aliases, alias_rids);
979 }
980
981 static NTSTATUS add_primary_group_members(
982         ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
983         char ***all_members, size_t *num_all_members)
984 {
985         char *filter;
986         NTSTATUS status = NT_STATUS_NO_MEMORY;
987         ADS_STATUS rc;
988         const char *attrs[] = { "dn", NULL };
989         LDAPMessage *res = NULL;
990         LDAPMessage *msg;
991         char **members;
992         size_t num_members;
993         ads_control args;
994
995         filter = talloc_asprintf(
996                 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
997                 (unsigned)rid);
998         if (filter == NULL) {
999                 goto done;
1000         }
1001
1002         args.control = ADS_EXTENDED_DN_OID;
1003         args.val = ADS_EXTENDED_DN_HEX_STRING;
1004         args.critical = True;
1005
1006         rc = ads_do_search_all_args(ads, ads->config.bind_path,
1007                                     LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1008                                     &res);
1009
1010         if (!ADS_ERR_OK(rc)) {
1011                 status = ads_ntstatus(rc);
1012                 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1013                 goto done;
1014         }
1015         if (res == NULL) {
1016                 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1017                 goto done;
1018         }
1019
1020         num_members = ads_count_replies(ads, res);
1021
1022         DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1023                    (uintmax_t)num_members));
1024
1025         if (num_members == 0) {
1026                 status = NT_STATUS_OK;
1027                 goto done;
1028         }
1029
1030         members = talloc_realloc(mem_ctx, *all_members, char *,
1031                                  *num_all_members + num_members);
1032         if (members == NULL) {
1033                 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1034                 goto done;
1035         }
1036         *all_members = members;
1037
1038         for (msg = ads_first_entry(ads, res); msg != NULL;
1039              msg = ads_next_entry(ads, msg)) {
1040                 char *dn;
1041
1042                 dn = ads_get_dn(ads, members, msg);
1043                 if (dn == NULL) {
1044                         DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1045                         continue;
1046                 }
1047
1048                 members[*num_all_members] = dn;
1049                 *num_all_members += 1;
1050         }
1051
1052         status = NT_STATUS_OK;
1053 done:
1054         if (res != NULL) {
1055                 ads_msgfree(ads, res);
1056         }
1057         TALLOC_FREE(filter);
1058         return status;
1059 }
1060
1061 /*
1062   find the members of a group, given a group rid and domain
1063  */
1064 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1065                                 TALLOC_CTX *mem_ctx,
1066                                 const struct dom_sid *group_sid,
1067                                 enum lsa_SidType type,
1068                                 uint32_t *num_names,
1069                                 struct dom_sid **sid_mem, char ***names,
1070                                 uint32_t **name_types)
1071 {
1072         ADS_STATUS rc;
1073         ADS_STRUCT *ads = NULL;
1074         char *ldap_exp;
1075         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1076         char *sidbinstr;
1077         char **members = NULL;
1078         int i;
1079         size_t num_members = 0;
1080         ads_control args;
1081         struct dom_sid *sid_mem_nocache = NULL;
1082         char **names_nocache = NULL;
1083         enum lsa_SidType *name_types_nocache = NULL;
1084         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
1085         uint32_t num_nocache = 0;
1086         TALLOC_CTX *tmp_ctx = NULL;
1087         uint32_t rid;
1088
1089         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1090                   sid_string_dbg(group_sid)));
1091
1092         *num_names = 0;
1093
1094         tmp_ctx = talloc_new(mem_ctx);
1095         if (!tmp_ctx) {
1096                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1097                 status = NT_STATUS_NO_MEMORY;
1098                 goto done;
1099         }
1100
1101         if (!sid_peek_rid(group_sid, &rid)) {
1102                 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1103                 status = NT_STATUS_INVALID_PARAMETER;
1104                 goto done;
1105         }
1106
1107         if ( !winbindd_can_contact_domain( domain ) ) {
1108                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1109                           domain->name));
1110                 return NT_STATUS_OK;
1111         }
1112
1113         ads = ads_cached_connection(domain);
1114
1115         if (!ads) {
1116                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1117                 goto done;
1118         }
1119
1120         if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1121                 status = NT_STATUS_NO_MEMORY;
1122                 goto done;
1123         }
1124
1125         /* search for all members of the group */
1126         ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1127         TALLOC_FREE(sidbinstr);
1128         if (ldap_exp == NULL) {
1129                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1130                 status = NT_STATUS_NO_MEMORY;
1131                 goto done;
1132         }
1133
1134         args.control = ADS_EXTENDED_DN_OID;
1135         args.val = ADS_EXTENDED_DN_HEX_STRING;
1136         args.critical = True;
1137
1138         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1139                                ldap_exp, &args, "member", &members, &num_members);
1140
1141         if (!ADS_ERR_OK(rc)) {
1142                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1143                 status = NT_STATUS_UNSUCCESSFUL;
1144                 goto done;
1145         }
1146
1147         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1148
1149         status = add_primary_group_members(ads, mem_ctx, rid,
1150                                            &members, &num_members);
1151         if (!NT_STATUS_IS_OK(status)) {
1152                 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1153                            __func__, nt_errstr(status)));
1154                 goto done;
1155         }
1156
1157         DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1158                    __func__, (int)num_members));
1159
1160         /* Now that we have a list of sids, we need to get the
1161          * lists of names and name_types belonging to these sids.
1162          * even though conceptually not quite clean,  we use the
1163          * RPC call lsa_lookup_sids for this since it can handle a
1164          * list of sids. ldap calls can just resolve one sid at a time.
1165          *
1166          * At this stage, the sids are still hidden in the exetended dn
1167          * member output format. We actually do a little better than
1168          * stated above: In extracting the sids from the member strings,
1169          * we try to resolve as many sids as possible from the
1170          * cache. Only the rest is passed to the lsa_lookup_sids call. */
1171
1172         if (num_members) {
1173                 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1174                 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1175                 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1176                 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1177
1178                 if ((members == NULL) || (*sid_mem == NULL) ||
1179                     (*names == NULL) || (*name_types == NULL) ||
1180                     (sid_mem_nocache == NULL))
1181                 {
1182                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1183                         status = NT_STATUS_NO_MEMORY;
1184                         goto done;
1185                 }
1186         }
1187         else {
1188                 (*sid_mem) = NULL;
1189                 (*names) = NULL;
1190                 (*name_types) = NULL;
1191         }
1192
1193         for (i=0; i<num_members; i++) {
1194                 enum lsa_SidType name_type;
1195                 char *name, *domain_name;
1196                 struct dom_sid sid;
1197
1198                 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1199                     &sid);
1200                 if (!ADS_ERR_OK(rc)) {
1201                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1202                             NT_STATUS_NOT_FOUND)) {
1203                                 /* Group members can be objects, like Exchange
1204                                  * Public Folders, that don't have a SID.  Skip
1205                                  * them. */
1206                                 continue;
1207                         }
1208                         else {
1209                                 status = ads_ntstatus(rc);
1210                                 goto done;
1211                         }
1212                 }
1213                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1214                     &name_type)) {
1215                         DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1216                                   "cache\n", sid_string_dbg(&sid)));
1217                         sid_copy(&(*sid_mem)[*num_names], &sid);
1218                         (*names)[*num_names] = fill_domain_username_talloc(
1219                                                         *names,
1220                                                         domain_name,
1221                                                         name,
1222                                                         true);
1223
1224                         (*name_types)[*num_names] = name_type;
1225                         (*num_names)++;
1226                 }
1227                 else {
1228                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1229                                    "cache\n", sid_string_dbg(&sid)));
1230                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1231                         num_nocache++;
1232                 }
1233         }
1234
1235         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1236                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1237
1238         /* handle sids not resolved from cache by lsa_lookup_sids */
1239         if (num_nocache > 0) {
1240
1241                 status = winbindd_lookup_sids(tmp_ctx,
1242                                               domain,
1243                                               num_nocache,
1244                                               sid_mem_nocache,
1245                                               &domains_nocache,
1246                                               &names_nocache,
1247                                               &name_types_nocache);
1248
1249                 if (!(NT_STATUS_IS_OK(status) ||
1250                       NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1251                       NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1252                 {
1253                         DEBUG(1, ("lsa_lookupsids call failed with %s "
1254                                   "- retrying...\n", nt_errstr(status)));
1255
1256                         status = winbindd_lookup_sids(tmp_ctx,
1257                                                       domain,
1258                                                       num_nocache,
1259                                                       sid_mem_nocache,
1260                                                       &domains_nocache,
1261                                                       &names_nocache,
1262                                                       &name_types_nocache);
1263                 }
1264
1265                 if (NT_STATUS_IS_OK(status) ||
1266                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1267                 {
1268                         /* Copy the entries over from the "_nocache" arrays
1269                          * to the result arrays, skipping the gaps the
1270                          * lookup_sids call left. */
1271                         for (i=0; i < num_nocache; i++) {
1272                                 if (((names_nocache)[i] != NULL) &&
1273                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1274                                 {
1275                                         sid_copy(&(*sid_mem)[*num_names],
1276                                                  &sid_mem_nocache[i]);
1277                                         (*names)[*num_names] =
1278                                                 fill_domain_username_talloc(
1279                                                         *names,
1280                                                         domains_nocache[i],
1281                                                         names_nocache[i],
1282                                                         true);
1283                                         (*name_types)[*num_names] = name_types_nocache[i];
1284                                         (*num_names)++;
1285                                 }
1286                         }
1287                 }
1288                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1289                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1290                                    "not map any SIDs at all.\n"));
1291                         /* Don't handle this as an error here.
1292                          * There is nothing left to do with respect to the 
1293                          * overall result... */
1294                 }
1295                 else if (!NT_STATUS_IS_OK(status)) {
1296                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
1297                                    "sids via rpc_lsa_lookup_sids: %s\n",
1298                                    (int)num_members, nt_errstr(status)));
1299                         goto done;
1300                 }
1301         }
1302
1303         status = NT_STATUS_OK;
1304         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1305                  sid_string_dbg(group_sid)));
1306
1307 done:
1308
1309         TALLOC_FREE(tmp_ctx);
1310
1311         return status;
1312 }
1313
1314 /* find the sequence number for a domain */
1315 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1316 {
1317         ADS_STRUCT *ads = NULL;
1318         ADS_STATUS rc;
1319
1320         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1321
1322         if ( !winbindd_can_contact_domain( domain ) ) {
1323                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1324                           domain->name));
1325                 *seq = time(NULL);              
1326                 return NT_STATUS_OK;
1327         }
1328
1329         if (IS_AD_DC) {
1330                 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1331                           domain->name));
1332                 *seq = time(NULL);
1333                 return NT_STATUS_OK;
1334         }
1335
1336         *seq = DOM_SEQUENCE_NONE;
1337
1338         ads = ads_cached_connection(domain);
1339
1340         if (!ads) {
1341                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1342                 return NT_STATUS_UNSUCCESSFUL;
1343         }
1344
1345         rc = ads_USN(ads, seq);
1346
1347         if (!ADS_ERR_OK(rc)) {
1348
1349                 /* its a dead connection, destroy it */
1350
1351                 if (domain->private_data) {
1352                         ads = (ADS_STRUCT *)domain->private_data;
1353                         ads->is_mine = True;
1354                         ads_destroy(&ads);
1355                         ads_kdestroy(WINBIND_CCACHE_NAME);
1356                         domain->private_data = NULL;
1357                 }
1358         }
1359         return ads_ntstatus(rc);
1360 }
1361
1362 /* find the lockout policy of a domain - use rpc methods */
1363 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1364                                TALLOC_CTX *mem_ctx,
1365                                struct samr_DomInfo12 *policy)
1366 {
1367         return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1368 }
1369
1370 /* find the password policy of a domain - use rpc methods */
1371 static NTSTATUS password_policy(struct winbindd_domain *domain,
1372                                 TALLOC_CTX *mem_ctx,
1373                                 struct samr_DomInfo1 *policy)
1374 {
1375         return msrpc_methods.password_policy(domain, mem_ctx, policy);
1376 }
1377
1378 /* get a list of trusted domains */
1379 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1380                                 TALLOC_CTX *mem_ctx,
1381                                 struct netr_DomainTrustList *trusts)
1382 {
1383         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1384         WERROR werr;
1385         int                     i;
1386         uint32_t                flags;
1387         struct rpc_pipe_client *cli;
1388         int ret_count;
1389         struct dcerpc_binding_handle *b;
1390
1391         DEBUG(3,("ads: trusted_domains\n"));
1392
1393         ZERO_STRUCTP(trusts);
1394
1395         /* If this is our primary domain or a root in our forest,
1396            query for all trusts.  If not, then just look for domain
1397            trusts in the target forest */
1398
1399         if (domain->primary || domain_is_forest_root(domain)) {
1400                 flags = NETR_TRUST_FLAG_OUTBOUND |
1401                         NETR_TRUST_FLAG_INBOUND |
1402                         NETR_TRUST_FLAG_IN_FOREST;
1403         } else {
1404                 flags = NETR_TRUST_FLAG_IN_FOREST;
1405         }       
1406
1407         result = cm_connect_netlogon(domain, &cli);
1408
1409         if (!NT_STATUS_IS_OK(result)) {
1410                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1411                           "for PIPE_NETLOGON (%s)\n", 
1412                           domain->name, nt_errstr(result)));
1413                 return NT_STATUS_UNSUCCESSFUL;
1414         }
1415
1416         b = cli->binding_handle;
1417
1418         result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1419                                                       cli->desthost,
1420                                                       flags,
1421                                                       trusts,
1422                                                       &werr);
1423         if (!NT_STATUS_IS_OK(result)) {
1424                 return result;
1425         }
1426
1427         if (!W_ERROR_IS_OK(werr)) {
1428                 return werror_to_ntstatus(werr);
1429         }
1430         if (trusts->count == 0) {
1431                 return NT_STATUS_OK;
1432         }
1433
1434         /* Copy across names and sids */
1435
1436         ret_count = 0;
1437         for (i = 0; i < trusts->count; i++) {
1438                 struct netr_DomainTrust *trust = &trusts->array[i];
1439                 struct winbindd_domain d;
1440
1441                 ZERO_STRUCT(d);
1442
1443                 /*
1444                  * drop external trusts if this is not our primary
1445                  * domain.  This means that the returned number of
1446                  * domains may be less that the ones actually trusted
1447                  * by the DC.
1448                  */
1449
1450                 if ((trust->trust_attributes
1451                      == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1452                     !domain->primary )
1453                 {
1454                         DEBUG(10,("trusted_domains: Skipping external trusted "
1455                                   "domain %s because it is outside of our "
1456                                   "primary domain\n",
1457                                   trust->netbios_name));
1458                         continue;
1459                 }
1460
1461                 /* add to the trusted domain cache */
1462
1463                 d.name = discard_const_p(char, trust->netbios_name);
1464                 d.alt_name = discard_const_p(char, trust->dns_name);
1465
1466                 if (trust->sid) {
1467                         sid_copy(&d.sid, trust->sid);
1468                 } else {
1469                         sid_copy(&d.sid, &global_sid_NULL);
1470                 }
1471
1472                 if ( domain->primary ) {
1473                         DEBUG(10,("trusted_domains(ads):  Searching "
1474                                   "trusted domain list of %s and storing "
1475                                   "trust flags for domain %s\n",
1476                                   domain->name, d.alt_name));
1477
1478                         d.domain_flags = trust->trust_flags;
1479                         d.domain_type = trust->trust_type;
1480                         d.domain_trust_attribs = trust->trust_attributes;
1481
1482                         wcache_tdc_add_domain( &d );
1483                         ret_count++;
1484                 } else if (domain_is_forest_root(domain)) {
1485                         /* Check if we already have this record. If
1486                          * we are following our forest root that is not
1487                          * our primary domain, we want to keep trust
1488                          * flags from the perspective of our primary
1489                          * domain not our forest root. */
1490                         struct winbindd_tdc_domain *exist = NULL;
1491
1492                         exist = wcache_tdc_fetch_domain(
1493                                 talloc_tos(), trust->netbios_name);
1494                         if (!exist) {
1495                                 DEBUG(10,("trusted_domains(ads):  Searching "
1496                                           "trusted domain list of %s and "
1497                                           "storing trust flags for domain "
1498                                           "%s\n", domain->name, d.alt_name));
1499                                 d.domain_flags = trust->trust_flags;
1500                                 d.domain_type = trust->trust_type;
1501                                 d.domain_trust_attribs =
1502                                         trust->trust_attributes;
1503
1504                                 wcache_tdc_add_domain( &d );
1505                                 ret_count++;
1506                         }
1507                         TALLOC_FREE(exist);
1508                 } else {
1509                         /* This gets a little tricky.  If we are
1510                            following a transitive forest trust, then
1511                            innerit the flags, type, and attribs from
1512                            the domain we queried to make sure we don't
1513                            record the view of the trust from the wrong
1514                            side.  Always view it from the side of our
1515                            primary domain.   --jerry */
1516                         struct winbindd_tdc_domain *parent = NULL;
1517
1518                         DEBUG(10,("trusted_domains(ads):  Searching "
1519                                   "trusted domain list of %s and inheriting "
1520                                   "trust flags for domain %s\n",
1521                                   domain->name, d.alt_name));
1522
1523                         parent = wcache_tdc_fetch_domain(talloc_tos(),
1524                                                          domain->name);
1525                         if (parent) {
1526                                 d.domain_flags = parent->trust_flags;
1527                                 d.domain_type  = parent->trust_type;
1528                                 d.domain_trust_attribs = parent->trust_attribs;
1529                         } else {
1530                                 d.domain_flags = domain->domain_flags;
1531                                 d.domain_type  = domain->domain_type;
1532                                 d.domain_trust_attribs =
1533                                         domain->domain_trust_attribs;
1534                         }
1535                         TALLOC_FREE(parent);
1536
1537                         /*
1538                          * We need to pass the modified properties
1539                          * to the caller.
1540                          */
1541                         trust->trust_flags = d.domain_flags;
1542                         trust->trust_type = d.domain_type;
1543                         trust->trust_attributes = d.domain_trust_attribs;
1544
1545                         wcache_tdc_add_domain( &d );
1546                         ret_count++;
1547                 }
1548         }
1549         return result;
1550 }
1551
1552 /* the ADS backend methods are exposed via this structure */
1553 struct winbindd_methods ads_methods = {
1554         True,
1555         query_user_list,
1556         enum_dom_groups,
1557         enum_local_groups,
1558         name_to_sid,
1559         sid_to_name,
1560         rids_to_names,
1561         lookup_usergroups,
1562         lookup_useraliases,
1563         lookup_groupmem,
1564         sequence_number,
1565         lockout_policy,
1566         password_policy,
1567         trusted_domains,
1568 };
1569
1570 #endif