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