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