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