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