b373be57698896caf7e6bf17d7d1a01d936cc4a5
[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
42 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
43
44 /**
45  * Check if cached connection can be reused. If the connection cannot
46  * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
47  */
48 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
49 {
50
51         ADS_STRUCT *ads = *adsp;
52
53         if (ads != NULL) {
54                 time_t expire;
55                 time_t now = time(NULL);
56
57                 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
58
59                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
60                           "is now %d)\n", (uint32_t)expire - (uint32_t)now,
61                           (uint32_t) expire, (uint32_t) now));
62
63                 if ( ads->config.realm && (expire > now)) {
64                         return;
65                 } else {
66                         /* we own this ADS_STRUCT so make sure it goes away */
67                         DEBUG(7,("Deleting expired krb5 credential cache\n"));
68                         ads->is_mine = True;
69                         ads_destroy( &ads );
70                         ads_kdestroy(WINBIND_CCACHE_NAME);
71                         *adsp = NULL;
72                 }
73         }
74 }
75
76 /**
77  * @brief Establish a connection to a DC
78  *
79  * @param[out]   adsp             ADS_STRUCT that will be created
80  * @param[in]    target_realm     Realm of domain to connect to
81  * @param[in]    target_dom_name  'workgroup' name of domain to connect to
82  * @param[in]    ldap_server      DNS name of server to connect to
83  * @param[in]    password         Our machine acount secret
84  * @param[in]    auth_realm       Realm of local domain for creating krb token
85  * @param[in]    renewable        Renewable ticket time
86  *
87  * @return ADS_STATUS
88  */
89 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
90                                                 const char *target_realm,
91                                                 const char *target_dom_name,
92                                                 const char *ldap_server,
93                                                 char *password,
94                                                 char *auth_realm,
95                                                 time_t renewable)
96 {
97         ADS_STRUCT *ads;
98         ADS_STATUS status;
99         struct sockaddr_storage dc_ss;
100         fstring dc_name;
101
102         if (auth_realm == NULL) {
103                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
104         }
105
106         /* we don't want this to affect the users ccache */
107         setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
108
109         ads = ads_init(target_realm, target_dom_name, ldap_server);
110         if (!ads) {
111                 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
112                 return ADS_ERROR(LDAP_NO_MEMORY);
113         }
114
115         SAFE_FREE(ads->auth.password);
116         SAFE_FREE(ads->auth.realm);
117
118         ads->auth.renewable = renewable;
119         ads->auth.password = password;
120
121         ads->auth.realm = SMB_STRDUP(auth_realm);
122         if (!strupper_m(ads->auth.realm)) {
123                 ads_destroy(&ads);
124                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
125         }
126
127         /* Setup the server affinity cache.  We don't reaally care
128            about the name.  Just setup affinity and the KRB5_CONFIG
129            file. */
130         get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
131
132         status = ads_connect(ads);
133         if (!ADS_ERR_OK(status)) {
134                 DEBUG(1,("ads_connect for domain %s failed: %s\n",
135                          target_dom_name, ads_errstr(status)));
136                 ads_destroy(&ads);
137                 return status;
138         }
139
140         /* set the flag that says we don't own the memory even
141            though we do so that ads_destroy() won't destroy the
142            structure we pass back by reference */
143
144         ads->is_mine = False;
145
146         *adsp = ads;
147
148         return status;
149 }
150
151 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
152 {
153         char *ldap_server, *realm, *password;
154         struct winbindd_domain *wb_dom;
155         ADS_STATUS status;
156
157         ads_cached_connection_reuse(adsp);
158         if (*adsp != NULL) {
159                 return ADS_SUCCESS;
160         }
161
162         /*
163          * At this point we only have the NetBIOS domain name.
164          * Check if we can get server nam and realm from SAF cache
165          * and the domain list.
166          */
167         ldap_server = saf_fetch(talloc_tos(), dom_name);
168         DEBUG(10, ("ldap_server from saf cache: '%s'\n",
169                    ldap_server ? ldap_server : ""));
170
171         wb_dom = find_domain_from_name(dom_name);
172         if (wb_dom == NULL) {
173                 DEBUG(10, ("could not find domain '%s'\n", dom_name));
174                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
175         }
176
177         DEBUG(10, ("find_domain_from_name found realm '%s' for "
178                           " domain '%s'\n", wb_dom->alt_name, dom_name));
179
180         if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
181                 TALLOC_FREE(ldap_server);
182                 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
183         }
184
185         if (IS_DC) {
186                 SMB_ASSERT(wb_dom->alt_name != NULL);
187                 realm = SMB_STRDUP(wb_dom->alt_name);
188         } else {
189                 struct winbindd_domain *our_domain = wb_dom;
190
191                 /* always give preference to the alt_name in our
192                    primary domain if possible */
193
194                 if (!wb_dom->primary) {
195                         our_domain = find_our_domain();
196                 }
197
198                 if (our_domain->alt_name != NULL) {
199                         realm = SMB_STRDUP(our_domain->alt_name);
200                 } else {
201                         realm = SMB_STRDUP(lp_realm());
202                 }
203         }
204
205         status = ads_cached_connection_connect(
206                 adsp,                   /* Returns ads struct. */
207                 wb_dom->alt_name,       /* realm to connect to. */
208                 dom_name,               /* 'workgroup' name for ads_init */
209                 ldap_server,            /* DNS name to connect to. */
210                 password,               /* password for auth realm. */
211                 realm,                  /* realm used for krb5 ticket. */
212                 0);                     /* renewable ticket time. */
213
214         SAFE_FREE(realm);
215         TALLOC_FREE(ldap_server);
216
217         return status;
218 }
219
220 /*
221   return our ads connections structure for a domain. We keep the connection
222   open to make things faster
223 */
224 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
225 {
226         ADS_STATUS status;
227         char *password, *realm;
228
229         DEBUG(10,("ads_cached_connection\n"));
230         ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
231
232         if (domain->private_data) {
233                 return (ADS_STRUCT *)domain->private_data;
234         }
235
236         /* the machine acct password might have change - fetch it every time */
237
238         if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
239                 return NULL;
240         }
241
242         if ( IS_DC ) {
243                 SMB_ASSERT(domain->alt_name != NULL);
244                 realm = SMB_STRDUP(domain->alt_name);
245         }
246         else {
247                 struct winbindd_domain *our_domain = domain;
248
249
250                 /* always give preference to the alt_name in our
251                    primary domain if possible */
252
253                 if ( !domain->primary )
254                         our_domain = find_our_domain();
255
256                 if (our_domain->alt_name != NULL) {
257                         realm = SMB_STRDUP( our_domain->alt_name );
258                 }
259                 else
260                         realm = SMB_STRDUP( lp_realm() );
261         }
262
263         status = ads_cached_connection_connect(
264                                         (ADS_STRUCT **)&domain->private_data,
265                                         domain->alt_name,
266                                         domain->name, NULL,
267                                         password, realm,
268                                         WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
269         SAFE_FREE(realm);
270
271         if (!ADS_ERR_OK(status)) {
272                 /* if we get ECONNREFUSED then it might be a NT4
273                    server, fall back to MSRPC */
274                 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
275                     status.err.rc == ECONNREFUSED) {
276                         /* 'reconnect_methods' is the MS-RPC backend. */
277                         DEBUG(1,("Trying MSRPC methods\n"));
278                         domain->backend = &reconnect_methods;
279                 }
280                 return NULL;
281         }
282
283         return (ADS_STRUCT *)domain->private_data;
284 }
285
286 /* Query display info for a realm. This is the basic user list fn */
287 static NTSTATUS query_user_list(struct winbindd_domain *domain,
288                                TALLOC_CTX *mem_ctx,
289                                uint32_t *num_entries,
290                                struct wbint_userinfo **pinfo)
291 {
292         ADS_STRUCT *ads = NULL;
293         const char *attrs[] = { "*", NULL };
294         int i, count;
295         ADS_STATUS rc;
296         LDAPMessage *res = NULL;
297         LDAPMessage *msg = NULL;
298         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
299
300         *num_entries = 0;
301
302         DEBUG(3,("ads: query_user_list\n"));
303
304         if ( !winbindd_can_contact_domain( domain ) ) {
305                 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
306                           domain->name));               
307                 return NT_STATUS_OK;
308         }
309
310         ads = ads_cached_connection(domain);
311
312         if (!ads) {
313                 domain->last_status = NT_STATUS_SERVER_DISABLED;
314                 goto done;
315         }
316
317         rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
318         if (!ADS_ERR_OK(rc)) {
319                 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
320                 status = ads_ntstatus(rc);
321                 goto done;
322         } else if (!res) {
323                 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
324                 goto done;
325         }
326
327         count = ads_count_replies(ads, res);
328         if (count == 0) {
329                 DEBUG(1,("query_user_list: No users found\n"));
330                 goto done;
331         }
332
333         (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
334         if (!*pinfo) {
335                 status = NT_STATUS_NO_MEMORY;
336                 goto done;
337         }
338
339         count = 0;
340
341         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
342                 struct wbint_userinfo *info = &((*pinfo)[count]);
343                 uint32_t group;
344                 uint32_t atype;
345
346                 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
347                     ds_atype_map(atype) != SID_NAME_USER) {
348                         DEBUG(1,("Not a user account? atype=0x%x\n", atype));
349                         continue;
350                 }
351
352                 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
353                 info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
354                 if (info->full_name == NULL) {
355                         info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
356                 }
357                 info->homedir = NULL;
358                 info->shell = NULL;
359                 info->primary_gid = (gid_t)-1;
360
361                 if (!ads_pull_sid(ads, msg, "objectSid",
362                                   &info->user_sid)) {
363                         DEBUG(1, ("No sid for %s !?\n", info->acct_name));
364                         continue;
365                 }
366
367                 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
368                         DEBUG(1, ("No primary group for %s !?\n",
369                                   info->acct_name));
370                         continue;
371                 }
372                 sid_compose(&info->group_sid, &domain->sid, group);
373
374                 count += 1;
375         }
376
377         (*num_entries) = count;
378         ads_msgfree(ads, res);
379
380         for (i=0; i<count; i++) {
381                 struct wbint_userinfo *info = &((*pinfo)[i]);
382                 const char *gecos = NULL;
383                 gid_t primary_gid = (gid_t)-1;
384
385                 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
386                                              &info->homedir, &info->shell,
387                                              &gecos, &primary_gid);
388                 if (!NT_STATUS_IS_OK(status)) {
389                         /*
390                          * Deliberately ignore this error, there might be more
391                          * users to fill
392                          */
393                         continue;
394                 }
395
396                 if (gecos != NULL) {
397                         info->full_name = gecos;
398                 }
399                 info->primary_gid = primary_gid;
400         }
401
402         status = NT_STATUS_OK;
403
404         DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
405
406 done:
407         return status;
408 }
409
410 /* list all domain groups */
411 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
412                                 TALLOC_CTX *mem_ctx,
413                                 uint32_t *num_entries,
414                                 struct wb_acct_info **info)
415 {
416         ADS_STRUCT *ads = NULL;
417         const char *attrs[] = {"userPrincipalName", "sAMAccountName",
418                                "name", "objectSid", NULL};
419         int i, count;
420         ADS_STATUS rc;
421         LDAPMessage *res = NULL;
422         LDAPMessage *msg = NULL;
423         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
424         const char *filter;
425         bool enum_dom_local_groups = False;
426
427         *num_entries = 0;
428
429         DEBUG(3,("ads: enum_dom_groups\n"));
430
431         if ( !winbindd_can_contact_domain( domain ) ) {
432                 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
433                           domain->name));               
434                 return NT_STATUS_OK;
435         }
436
437         /* only grab domain local groups for our domain */
438         if ( domain->active_directory && strequal(lp_realm(), domain->alt_name)  ) {
439                 enum_dom_local_groups = True;
440         }
441
442         /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
443          * rollup-fixes:
444          *
445          * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
446          * default value, it MUST be absent. In case of extensible matching the
447          * "dnattr" boolean defaults to FALSE and so it must be only be present
448          * when set to TRUE. 
449          *
450          * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
451          * filter using bitwise matching rule then the buggy AD fails to decode
452          * the extensible match. As a workaround set it to TRUE and thereby add
453          * the dnAttributes "dn" field to cope with those older AD versions.
454          * It should not harm and won't put any additional load on the AD since
455          * none of the dn components have a bitmask-attribute.
456          *
457          * Thanks to Ralf Haferkamp for input and testing - Guenther */
458
459         filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
460                                  ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
461                                  ADS_LDAP_MATCHING_RULE_BIT_AND, 
462                                  enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
463
464         if (filter == NULL) {
465                 status = NT_STATUS_NO_MEMORY;
466                 goto done;
467         }
468
469         ads = ads_cached_connection(domain);
470
471         if (!ads) {
472                 domain->last_status = NT_STATUS_SERVER_DISABLED;
473                 goto done;
474         }
475
476         rc = ads_search_retry(ads, &res, filter, attrs);
477         if (!ADS_ERR_OK(rc)) {
478                 status = ads_ntstatus(rc);
479                 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
480                 goto done;
481         } else if (!res) {
482                 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
483                 goto done;
484         }
485
486         count = ads_count_replies(ads, res);
487         if (count == 0) {
488                 DEBUG(1,("enum_dom_groups: No groups found\n"));
489                 goto done;
490         }
491
492         (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
493         if (!*info) {
494                 status = NT_STATUS_NO_MEMORY;
495                 goto done;
496         }
497
498         i = 0;
499
500         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
501                 char *name, *gecos;
502                 struct dom_sid sid;
503                 uint32_t rid;
504
505                 name = ads_pull_username(ads, mem_ctx, msg);
506                 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
507                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
508                         DEBUG(1,("No sid for %s !?\n", name));
509                         continue;
510                 }
511
512                 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
513                         DEBUG(1,("No rid for %s !?\n", name));
514                         continue;
515                 }
516
517                 fstrcpy((*info)[i].acct_name, name);
518                 fstrcpy((*info)[i].acct_desc, gecos);
519                 (*info)[i].rid = rid;
520                 i++;
521         }
522
523         (*num_entries) = i;
524
525         status = NT_STATUS_OK;
526
527         DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
528
529 done:
530         if (res) 
531                 ads_msgfree(ads, res);
532
533         return status;
534 }
535
536 /* list all domain local groups */
537 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
538                                 TALLOC_CTX *mem_ctx,
539                                 uint32_t *num_entries,
540                                 struct wb_acct_info **info)
541 {
542         /*
543          * This is a stub function only as we returned the domain 
544          * local groups in enum_dom_groups() if the domain->native field
545          * was true.  This is a simple performance optimization when
546          * using LDAP.
547          *
548          * if we ever need to enumerate domain local groups separately, 
549          * then this optimization in enum_dom_groups() will need
550          * to be split out
551          */
552         *num_entries = 0;
553
554         return NT_STATUS_OK;
555 }
556
557 /* convert a single name to a sid in a domain - use rpc methods */
558 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
559                             TALLOC_CTX *mem_ctx,
560                             const char *domain_name,
561                             const char *name,
562                             uint32_t flags,
563                             struct dom_sid *sid,
564                             enum lsa_SidType *type)
565 {
566         return reconnect_methods.name_to_sid(domain, mem_ctx,
567                                              domain_name, name, flags,
568                                              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 reconnect_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 reconnect_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 reconnect_methods.lookup_useraliases(domain, mem_ctx,
1146                                                     num_sids, sids,
1147                                                     num_aliases,
1148                                                     alias_rids);
1149 }
1150
1151 static NTSTATUS add_primary_group_members(
1152         ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
1153         char ***all_members, size_t *num_all_members)
1154 {
1155         char *filter;
1156         NTSTATUS status = NT_STATUS_NO_MEMORY;
1157         ADS_STATUS rc;
1158         const char *attrs[] = { "dn", NULL };
1159         LDAPMessage *res = NULL;
1160         LDAPMessage *msg;
1161         char **members;
1162         size_t num_members;
1163         ads_control args;
1164
1165         filter = talloc_asprintf(
1166                 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1167                 (unsigned)rid);
1168         if (filter == NULL) {
1169                 goto done;
1170         }
1171
1172         args.control = ADS_EXTENDED_DN_OID;
1173         args.val = ADS_EXTENDED_DN_HEX_STRING;
1174         args.critical = True;
1175
1176         rc = ads_do_search_all_args(ads, ads->config.bind_path,
1177                                     LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1178                                     &res);
1179
1180         if (!ADS_ERR_OK(rc)) {
1181                 status = ads_ntstatus(rc);
1182                 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1183                 goto done;
1184         }
1185         if (res == NULL) {
1186                 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1187                 goto done;
1188         }
1189
1190         num_members = ads_count_replies(ads, res);
1191
1192         DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1193                    (uintmax_t)num_members));
1194
1195         if (num_members == 0) {
1196                 status = NT_STATUS_OK;
1197                 goto done;
1198         }
1199
1200         members = talloc_realloc(mem_ctx, *all_members, char *,
1201                                  *num_all_members + num_members);
1202         if (members == NULL) {
1203                 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1204                 goto done;
1205         }
1206         *all_members = members;
1207
1208         for (msg = ads_first_entry(ads, res); msg != NULL;
1209              msg = ads_next_entry(ads, msg)) {
1210                 char *dn;
1211
1212                 dn = ads_get_dn(ads, members, msg);
1213                 if (dn == NULL) {
1214                         DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1215                         continue;
1216                 }
1217
1218                 members[*num_all_members] = dn;
1219                 *num_all_members += 1;
1220         }
1221
1222         status = NT_STATUS_OK;
1223 done:
1224         if (res != NULL) {
1225                 ads_msgfree(ads, res);
1226         }
1227         TALLOC_FREE(filter);
1228         return status;
1229 }
1230
1231 /*
1232   find the members of a group, given a group rid and domain
1233  */
1234 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1235                                 TALLOC_CTX *mem_ctx,
1236                                 const struct dom_sid *group_sid,
1237                                 enum lsa_SidType type,
1238                                 uint32_t *num_names,
1239                                 struct dom_sid **sid_mem, char ***names,
1240                                 uint32_t **name_types)
1241 {
1242         ADS_STATUS rc;
1243         ADS_STRUCT *ads = NULL;
1244         char *ldap_exp;
1245         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1246         char *sidbinstr;
1247         char **members = NULL;
1248         int i;
1249         size_t num_members = 0;
1250         ads_control args;
1251         struct dom_sid *sid_mem_nocache = NULL;
1252         char **names_nocache = NULL;
1253         enum lsa_SidType *name_types_nocache = NULL;
1254         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
1255         uint32_t num_nocache = 0;
1256         TALLOC_CTX *tmp_ctx = NULL;
1257         uint32_t rid;
1258
1259         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1260                   sid_string_dbg(group_sid)));
1261
1262         *num_names = 0;
1263
1264         tmp_ctx = talloc_new(mem_ctx);
1265         if (!tmp_ctx) {
1266                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1267                 status = NT_STATUS_NO_MEMORY;
1268                 goto done;
1269         }
1270
1271         if (!sid_peek_rid(group_sid, &rid)) {
1272                 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1273                 status = NT_STATUS_INVALID_PARAMETER;
1274                 goto done;
1275         }
1276
1277         if ( !winbindd_can_contact_domain( domain ) ) {
1278                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1279                           domain->name));
1280                 return NT_STATUS_OK;
1281         }
1282
1283         ads = ads_cached_connection(domain);
1284
1285         if (!ads) {
1286                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1287                 goto done;
1288         }
1289
1290         if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1291                 status = NT_STATUS_NO_MEMORY;
1292                 goto done;
1293         }
1294
1295         /* search for all members of the group */
1296         ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1297         TALLOC_FREE(sidbinstr);
1298         if (ldap_exp == NULL) {
1299                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1300                 status = NT_STATUS_NO_MEMORY;
1301                 goto done;
1302         }
1303
1304         args.control = ADS_EXTENDED_DN_OID;
1305         args.val = ADS_EXTENDED_DN_HEX_STRING;
1306         args.critical = True;
1307
1308         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1309                                ldap_exp, &args, "member", &members, &num_members);
1310
1311         if (!ADS_ERR_OK(rc)) {
1312                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1313                 status = NT_STATUS_UNSUCCESSFUL;
1314                 goto done;
1315         }
1316
1317         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1318
1319         status = add_primary_group_members(ads, mem_ctx, rid,
1320                                            &members, &num_members);
1321         if (!NT_STATUS_IS_OK(status)) {
1322                 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1323                            __func__, nt_errstr(status)));
1324                 goto done;
1325         }
1326
1327         DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1328                    __func__, (int)num_members));
1329
1330         /* Now that we have a list of sids, we need to get the
1331          * lists of names and name_types belonging to these sids.
1332          * even though conceptually not quite clean,  we use the
1333          * RPC call lsa_lookup_sids for this since it can handle a
1334          * list of sids. ldap calls can just resolve one sid at a time.
1335          *
1336          * At this stage, the sids are still hidden in the exetended dn
1337          * member output format. We actually do a little better than
1338          * stated above: In extracting the sids from the member strings,
1339          * we try to resolve as many sids as possible from the
1340          * cache. Only the rest is passed to the lsa_lookup_sids call. */
1341
1342         if (num_members) {
1343                 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1344                 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1345                 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1346                 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1347
1348                 if ((members == NULL) || (*sid_mem == NULL) ||
1349                     (*names == NULL) || (*name_types == NULL) ||
1350                     (sid_mem_nocache == NULL))
1351                 {
1352                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1353                         status = NT_STATUS_NO_MEMORY;
1354                         goto done;
1355                 }
1356         }
1357         else {
1358                 (*sid_mem) = NULL;
1359                 (*names) = NULL;
1360                 (*name_types) = NULL;
1361         }
1362
1363         for (i=0; i<num_members; i++) {
1364                 enum lsa_SidType name_type;
1365                 char *name, *domain_name;
1366                 struct dom_sid sid;
1367
1368                 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1369                     &sid);
1370                 if (!ADS_ERR_OK(rc)) {
1371                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1372                             NT_STATUS_NOT_FOUND)) {
1373                                 /* Group members can be objects, like Exchange
1374                                  * Public Folders, that don't have a SID.  Skip
1375                                  * them. */
1376                                 continue;
1377                         }
1378                         else {
1379                                 status = ads_ntstatus(rc);
1380                                 goto done;
1381                         }
1382                 }
1383                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1384                     &name_type)) {
1385                         DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1386                                   "cache\n", sid_string_dbg(&sid)));
1387                         sid_copy(&(*sid_mem)[*num_names], &sid);
1388                         (*names)[*num_names] = fill_domain_username_talloc(
1389                                                         *names,
1390                                                         domain_name,
1391                                                         name,
1392                                                         true);
1393
1394                         (*name_types)[*num_names] = name_type;
1395                         (*num_names)++;
1396                 }
1397                 else {
1398                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1399                                    "cache\n", sid_string_dbg(&sid)));
1400                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1401                         num_nocache++;
1402                 }
1403         }
1404
1405         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1406                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1407
1408         /* handle sids not resolved from cache by lsa_lookup_sids */
1409         if (num_nocache > 0) {
1410
1411                 status = winbindd_lookup_sids(tmp_ctx,
1412                                               domain,
1413                                               num_nocache,
1414                                               sid_mem_nocache,
1415                                               &domains_nocache,
1416                                               &names_nocache,
1417                                               &name_types_nocache);
1418
1419                 if (!(NT_STATUS_IS_OK(status) ||
1420                       NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1421                       NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1422                 {
1423                         DEBUG(1, ("lsa_lookupsids call failed with %s "
1424                                   "- retrying...\n", nt_errstr(status)));
1425
1426                         status = winbindd_lookup_sids(tmp_ctx,
1427                                                       domain,
1428                                                       num_nocache,
1429                                                       sid_mem_nocache,
1430                                                       &domains_nocache,
1431                                                       &names_nocache,
1432                                                       &name_types_nocache);
1433                 }
1434
1435                 if (NT_STATUS_IS_OK(status) ||
1436                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1437                 {
1438                         /* Copy the entries over from the "_nocache" arrays
1439                          * to the result arrays, skipping the gaps the
1440                          * lookup_sids call left. */
1441                         for (i=0; i < num_nocache; i++) {
1442                                 if (((names_nocache)[i] != NULL) &&
1443                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1444                                 {
1445                                         sid_copy(&(*sid_mem)[*num_names],
1446                                                  &sid_mem_nocache[i]);
1447                                         (*names)[*num_names] =
1448                                                 fill_domain_username_talloc(
1449                                                         *names,
1450                                                         domains_nocache[i],
1451                                                         names_nocache[i],
1452                                                         true);
1453                                         (*name_types)[*num_names] = name_types_nocache[i];
1454                                         (*num_names)++;
1455                                 }
1456                         }
1457                 }
1458                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1459                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1460                                    "not map any SIDs at all.\n"));
1461                         /* Don't handle this as an error here.
1462                          * There is nothing left to do with respect to the 
1463                          * overall result... */
1464                 }
1465                 else if (!NT_STATUS_IS_OK(status)) {
1466                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
1467                                    "sids via rpc_lsa_lookup_sids: %s\n",
1468                                    (int)num_members, nt_errstr(status)));
1469                         goto done;
1470                 }
1471         }
1472
1473         status = NT_STATUS_OK;
1474         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1475                  sid_string_dbg(group_sid)));
1476
1477 done:
1478
1479         TALLOC_FREE(tmp_ctx);
1480
1481         return status;
1482 }
1483
1484 /* find the sequence number for a domain */
1485 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1486 {
1487         ADS_STRUCT *ads = NULL;
1488         ADS_STATUS rc;
1489
1490         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1491
1492         if ( !winbindd_can_contact_domain( domain ) ) {
1493                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1494                           domain->name));
1495                 *seq = time(NULL);              
1496                 return NT_STATUS_OK;
1497         }
1498
1499         *seq = DOM_SEQUENCE_NONE;
1500
1501         ads = ads_cached_connection(domain);
1502
1503         if (!ads) {
1504                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1505                 return NT_STATUS_UNSUCCESSFUL;
1506         }
1507
1508         rc = ads_USN(ads, seq);
1509
1510         if (!ADS_ERR_OK(rc)) {
1511
1512                 /* its a dead connection, destroy it */
1513
1514                 if (domain->private_data) {
1515                         ads = (ADS_STRUCT *)domain->private_data;
1516                         ads->is_mine = True;
1517                         ads_destroy(&ads);
1518                         ads_kdestroy(WINBIND_CCACHE_NAME);
1519                         domain->private_data = NULL;
1520                 }
1521         }
1522         return ads_ntstatus(rc);
1523 }
1524
1525 /* find the lockout policy of a domain - use rpc methods */
1526 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1527                                TALLOC_CTX *mem_ctx,
1528                                struct samr_DomInfo12 *policy)
1529 {
1530         return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1531 }
1532
1533 /* find the password policy of a domain - use rpc methods */
1534 static NTSTATUS password_policy(struct winbindd_domain *domain,
1535                                 TALLOC_CTX *mem_ctx,
1536                                 struct samr_DomInfo1 *policy)
1537 {
1538         return reconnect_methods.password_policy(domain, mem_ctx, policy);
1539 }
1540
1541 /* get a list of trusted domains */
1542 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1543                                 TALLOC_CTX *mem_ctx,
1544                                 struct netr_DomainTrustList *trusts)
1545 {
1546         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1547         WERROR werr;
1548         int                     i;
1549         uint32_t                flags;
1550         struct rpc_pipe_client *cli;
1551         int ret_count;
1552         struct dcerpc_binding_handle *b;
1553
1554         DEBUG(3,("ads: trusted_domains\n"));
1555
1556         ZERO_STRUCTP(trusts);
1557
1558         /* If this is our primary domain or a root in our forest,
1559            query for all trusts.  If not, then just look for domain
1560            trusts in the target forest */
1561
1562         if (domain->primary || domain_is_forest_root(domain)) {
1563                 flags = NETR_TRUST_FLAG_OUTBOUND |
1564                         NETR_TRUST_FLAG_INBOUND |
1565                         NETR_TRUST_FLAG_IN_FOREST;
1566         } else {
1567                 flags = NETR_TRUST_FLAG_IN_FOREST;
1568         }       
1569
1570         result = cm_connect_netlogon(domain, &cli);
1571
1572         if (!NT_STATUS_IS_OK(result)) {
1573                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1574                           "for PIPE_NETLOGON (%s)\n", 
1575                           domain->name, nt_errstr(result)));
1576                 return NT_STATUS_UNSUCCESSFUL;
1577         }
1578
1579         b = cli->binding_handle;
1580
1581         result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1582                                                       cli->desthost,
1583                                                       flags,
1584                                                       trusts,
1585                                                       &werr);
1586         if (!NT_STATUS_IS_OK(result)) {
1587                 return result;
1588         }
1589
1590         if (!W_ERROR_IS_OK(werr)) {
1591                 return werror_to_ntstatus(werr);
1592         }
1593         if (trusts->count == 0) {
1594                 return NT_STATUS_OK;
1595         }
1596
1597         /* Copy across names and sids */
1598
1599         ret_count = 0;
1600         for (i = 0; i < trusts->count; i++) {
1601                 struct netr_DomainTrust *trust = &trusts->array[i];
1602                 struct winbindd_domain d;
1603
1604                 ZERO_STRUCT(d);
1605
1606                 /*
1607                  * drop external trusts if this is not our primary
1608                  * domain.  This means that the returned number of
1609                  * domains may be less that the ones actually trusted
1610                  * by the DC.
1611                  */
1612
1613                 if ((trust->trust_attributes
1614                      == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1615                     !domain->primary )
1616                 {
1617                         DEBUG(10,("trusted_domains: Skipping external trusted "
1618                                   "domain %s because it is outside of our "
1619                                   "primary domain\n",
1620                                   trust->netbios_name));
1621                         continue;
1622                 }
1623
1624                 /* add to the trusted domain cache */
1625
1626                 d.name = discard_const_p(char, trust->netbios_name);
1627                 d.alt_name = discard_const_p(char, trust->dns_name);
1628
1629                 if (trust->sid) {
1630                         sid_copy(&d.sid, trust->sid);
1631                 } else {
1632                         sid_copy(&d.sid, &global_sid_NULL);
1633                 }
1634
1635                 if ( domain->primary ) {
1636                         DEBUG(10,("trusted_domains(ads):  Searching "
1637                                   "trusted domain list of %s and storing "
1638                                   "trust flags for domain %s\n",
1639                                   domain->name, d.alt_name));
1640
1641                         d.domain_flags = trust->trust_flags;
1642                         d.domain_type = trust->trust_type;
1643                         d.domain_trust_attribs = trust->trust_attributes;
1644
1645                         wcache_tdc_add_domain( &d );
1646                         ret_count++;
1647                 } else if (domain_is_forest_root(domain)) {
1648                         /* Check if we already have this record. If
1649                          * we are following our forest root that is not
1650                          * our primary domain, we want to keep trust
1651                          * flags from the perspective of our primary
1652                          * domain not our forest root. */
1653                         struct winbindd_tdc_domain *exist = NULL;
1654
1655                         exist = wcache_tdc_fetch_domain(
1656                                 talloc_tos(), trust->netbios_name);
1657                         if (!exist) {
1658                                 DEBUG(10,("trusted_domains(ads):  Searching "
1659                                           "trusted domain list of %s and "
1660                                           "storing trust flags for domain "
1661                                           "%s\n", domain->name, d.alt_name));
1662                                 d.domain_flags = trust->trust_flags;
1663                                 d.domain_type = trust->trust_type;
1664                                 d.domain_trust_attribs =
1665                                         trust->trust_attributes;
1666
1667                                 wcache_tdc_add_domain( &d );
1668                                 ret_count++;
1669                         }
1670                         TALLOC_FREE(exist);
1671                 } else {
1672                         /* This gets a little tricky.  If we are
1673                            following a transitive forest trust, then
1674                            innerit the flags, type, and attribs from
1675                            the domain we queried to make sure we don't
1676                            record the view of the trust from the wrong
1677                            side.  Always view it from the side of our
1678                            primary domain.   --jerry */
1679                         struct winbindd_tdc_domain *parent = NULL;
1680
1681                         DEBUG(10,("trusted_domains(ads):  Searching "
1682                                   "trusted domain list of %s and inheriting "
1683                                   "trust flags for domain %s\n",
1684                                   domain->name, d.alt_name));
1685
1686                         parent = wcache_tdc_fetch_domain(talloc_tos(),
1687                                                          domain->name);
1688                         if (parent) {
1689                                 d.domain_flags = parent->trust_flags;
1690                                 d.domain_type  = parent->trust_type;
1691                                 d.domain_trust_attribs = parent->trust_attribs;
1692                         } else {
1693                                 d.domain_flags = domain->domain_flags;
1694                                 d.domain_type  = domain->domain_type;
1695                                 d.domain_trust_attribs =
1696                                         domain->domain_trust_attribs;
1697                         }
1698                         TALLOC_FREE(parent);
1699
1700                         wcache_tdc_add_domain( &d );
1701                         ret_count++;
1702                 }
1703         }
1704         return result;
1705 }
1706
1707 /* the ADS backend methods are exposed via this structure */
1708 struct winbindd_methods ads_methods = {
1709         True,
1710         query_user_list,
1711         enum_dom_groups,
1712         enum_local_groups,
1713         name_to_sid,
1714         sid_to_name,
1715         rids_to_names,
1716         query_user,
1717         lookup_usergroups,
1718         lookup_useraliases,
1719         lookup_groupmem,
1720         sequence_number,
1721         lockout_policy,
1722         password_policy,
1723         trusted_domains,
1724 };
1725
1726 #endif