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