s3:winbindd: fix endless forest trust scan
[metze/samba/wip.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.flags |= ADS_AUTH_ALLOW_NTLMSSP;
124
125         ads->auth.realm = SMB_STRDUP(auth_realm);
126         if (!strupper_m(ads->auth.realm)) {
127                 ads_destroy(&ads);
128                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
129         }
130
131         /* Setup the server affinity cache.  We don't reaally care
132            about the name.  Just setup affinity and the KRB5_CONFIG
133            file. */
134         get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
135
136         status = ads_connect(ads);
137         if (!ADS_ERR_OK(status)) {
138                 DEBUG(1,("ads_connect for domain %s failed: %s\n",
139                          target_dom_name, ads_errstr(status)));
140                 ads_destroy(&ads);
141                 return status;
142         }
143
144         /* set the flag that says we don't own the memory even
145            though we do so that ads_destroy() won't destroy the
146            structure we pass back by reference */
147
148         ads->is_mine = False;
149
150         *adsp = ads;
151
152         return status;
153 }
154
155 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
156 {
157         char *ldap_server, *realm, *password;
158         struct winbindd_domain *wb_dom;
159         ADS_STATUS status;
160
161         ads_cached_connection_reuse(adsp);
162         if (*adsp != NULL) {
163                 return ADS_SUCCESS;
164         }
165
166         /*
167          * At this point we only have the NetBIOS domain name.
168          * Check if we can get server nam and realm from SAF cache
169          * and the domain list.
170          */
171         ldap_server = saf_fetch(talloc_tos(), dom_name);
172         DEBUG(10, ("ldap_server from saf cache: '%s'\n",
173                    ldap_server ? ldap_server : ""));
174
175         wb_dom = find_domain_from_name(dom_name);
176         if (wb_dom == NULL) {
177                 DEBUG(10, ("could not find domain '%s'\n", dom_name));
178                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
179         }
180
181         DEBUG(10, ("find_domain_from_name found realm '%s' for "
182                           " domain '%s'\n", wb_dom->alt_name, dom_name));
183
184         if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
185                 TALLOC_FREE(ldap_server);
186                 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
187         }
188
189         if (IS_DC) {
190                 SMB_ASSERT(wb_dom->alt_name != NULL);
191                 realm = SMB_STRDUP(wb_dom->alt_name);
192         } else {
193                 struct winbindd_domain *our_domain = wb_dom;
194
195                 /* always give preference to the alt_name in our
196                    primary domain if possible */
197
198                 if (!wb_dom->primary) {
199                         our_domain = find_our_domain();
200                 }
201
202                 if (our_domain->alt_name != NULL) {
203                         realm = SMB_STRDUP(our_domain->alt_name);
204                 } else {
205                         realm = SMB_STRDUP(lp_realm());
206                 }
207         }
208
209         status = ads_cached_connection_connect(
210                 adsp,                   /* Returns ads struct. */
211                 wb_dom->alt_name,       /* realm to connect to. */
212                 dom_name,               /* 'workgroup' name for ads_init */
213                 ldap_server,            /* DNS name to connect to. */
214                 password,               /* password for auth realm. */
215                 realm,                  /* realm used for krb5 ticket. */
216                 0);                     /* renewable ticket time. */
217
218         SAFE_FREE(realm);
219         TALLOC_FREE(ldap_server);
220
221         return status;
222 }
223
224 /*
225   return our ads connections structure for a domain. We keep the connection
226   open to make things faster
227 */
228 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
229 {
230         ADS_STATUS status;
231         char *password, *realm;
232
233         DEBUG(10,("ads_cached_connection\n"));
234         ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
235
236         if (domain->private_data) {
237                 return (ADS_STRUCT *)domain->private_data;
238         }
239
240         /* the machine acct password might have change - fetch it every time */
241
242         if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
243                 return NULL;
244         }
245
246         if ( IS_DC ) {
247                 SMB_ASSERT(domain->alt_name != NULL);
248                 realm = SMB_STRDUP(domain->alt_name);
249         }
250         else {
251                 struct winbindd_domain *our_domain = domain;
252
253
254                 /* always give preference to the alt_name in our
255                    primary domain if possible */
256
257                 if ( !domain->primary )
258                         our_domain = find_our_domain();
259
260                 if (our_domain->alt_name != NULL) {
261                         realm = SMB_STRDUP( our_domain->alt_name );
262                 }
263                 else
264                         realm = SMB_STRDUP( lp_realm() );
265         }
266
267         status = ads_cached_connection_connect(
268                                         (ADS_STRUCT **)&domain->private_data,
269                                         domain->alt_name,
270                                         domain->name, NULL,
271                                         password, realm,
272                                         WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
273         SAFE_FREE(realm);
274
275         if (!ADS_ERR_OK(status)) {
276                 /* if we get ECONNREFUSED then it might be a NT4
277                    server, fall back to MSRPC */
278                 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
279                     status.err.rc == ECONNREFUSED) {
280                         /* 'reconnect_methods' is the MS-RPC backend. */
281                         DEBUG(1,("Trying MSRPC methods\n"));
282                         domain->backend = &reconnect_methods;
283                 }
284                 return NULL;
285         }
286
287         return (ADS_STRUCT *)domain->private_data;
288 }
289
290 /* Query display info for a realm. This is the basic user list fn */
291 static NTSTATUS query_user_list(struct winbindd_domain *domain,
292                                TALLOC_CTX *mem_ctx,
293                                uint32_t **prids)
294 {
295         ADS_STRUCT *ads = NULL;
296         const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
297         int count;
298         uint32_t *rids = NULL;
299         ADS_STATUS rc;
300         LDAPMessage *res = NULL;
301         LDAPMessage *msg = NULL;
302         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
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         rids = talloc_zero_array(mem_ctx, uint32_t, count);
336         if (rids == NULL) {
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 dom_sid user_sid;
345                 uint32_t atype;
346                 bool ok;
347
348                 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
349                 if (!ok) {
350                         DBG_INFO("Object lacks sAMAccountType attribute\n");
351                         continue;
352                 }
353                 if (ds_atype_map(atype) != SID_NAME_USER) {
354                         DBG_INFO("Not a user account? atype=0x%x\n", atype);
355                         continue;
356                 }
357
358                 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
359                         char *dn = ads_get_dn(ads, talloc_tos(), msg);
360                         DBG_INFO("No sid for %s !?\n", dn);
361                         TALLOC_FREE(dn);
362                         continue;
363                 }
364
365                 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
366                         fstring sidstr, domstr;
367                         DBG_WARNING("Got sid %s in domain %s\n",
368                                     sid_to_fstring(sidstr, &user_sid),
369                                     sid_to_fstring(domstr, &domain->sid));
370                         continue;
371                 }
372
373                 sid_split_rid(&user_sid, &rids[count]);
374                 count += 1;
375         }
376
377         rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
378         if (prids != NULL) {
379                 *prids = rids;
380         }
381
382         status = NT_STATUS_OK;
383
384         DBG_NOTICE("ads query_user_list gave %d entries\n", count);
385
386 done:
387         return status;
388 }
389
390 /* list all domain groups */
391 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
392                                 TALLOC_CTX *mem_ctx,
393                                 uint32_t *num_entries,
394                                 struct wb_acct_info **info)
395 {
396         ADS_STRUCT *ads = NULL;
397         const char *attrs[] = {"userPrincipalName", "sAMAccountName",
398                                "name", "objectSid", NULL};
399         int i, count;
400         ADS_STATUS rc;
401         LDAPMessage *res = NULL;
402         LDAPMessage *msg = NULL;
403         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
404         const char *filter;
405         bool enum_dom_local_groups = False;
406
407         *num_entries = 0;
408
409         DEBUG(3,("ads: enum_dom_groups\n"));
410
411         if ( !winbindd_can_contact_domain( domain ) ) {
412                 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
413                           domain->name));               
414                 return NT_STATUS_OK;
415         }
416
417         /* only grab domain local groups for our domain */
418         if ( domain->active_directory && strequal(lp_realm(), domain->alt_name)  ) {
419                 enum_dom_local_groups = True;
420         }
421
422         /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
423          * rollup-fixes:
424          *
425          * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
426          * default value, it MUST be absent. In case of extensible matching the
427          * "dnattr" boolean defaults to FALSE and so it must be only be present
428          * when set to TRUE. 
429          *
430          * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
431          * filter using bitwise matching rule then the buggy AD fails to decode
432          * the extensible match. As a workaround set it to TRUE and thereby add
433          * the dnAttributes "dn" field to cope with those older AD versions.
434          * It should not harm and won't put any additional load on the AD since
435          * none of the dn components have a bitmask-attribute.
436          *
437          * Thanks to Ralf Haferkamp for input and testing - Guenther */
438
439         filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
440                                  ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
441                                  ADS_LDAP_MATCHING_RULE_BIT_AND, 
442                                  enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
443
444         if (filter == NULL) {
445                 status = NT_STATUS_NO_MEMORY;
446                 goto done;
447         }
448
449         ads = ads_cached_connection(domain);
450
451         if (!ads) {
452                 domain->last_status = NT_STATUS_SERVER_DISABLED;
453                 goto done;
454         }
455
456         rc = ads_search_retry(ads, &res, filter, attrs);
457         if (!ADS_ERR_OK(rc)) {
458                 status = ads_ntstatus(rc);
459                 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
460                 goto done;
461         } else if (!res) {
462                 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
463                 goto done;
464         }
465
466         count = ads_count_replies(ads, res);
467         if (count == 0) {
468                 DEBUG(1,("enum_dom_groups: No groups found\n"));
469                 goto done;
470         }
471
472         (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
473         if (!*info) {
474                 status = NT_STATUS_NO_MEMORY;
475                 goto done;
476         }
477
478         i = 0;
479
480         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
481                 char *name, *gecos;
482                 struct dom_sid sid;
483                 uint32_t rid;
484
485                 name = ads_pull_username(ads, mem_ctx, msg);
486                 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
487                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
488                         DEBUG(1,("No sid for %s !?\n", name));
489                         continue;
490                 }
491
492                 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
493                         DEBUG(1,("No rid for %s !?\n", name));
494                         continue;
495                 }
496
497                 fstrcpy((*info)[i].acct_name, name);
498                 fstrcpy((*info)[i].acct_desc, gecos);
499                 (*info)[i].rid = rid;
500                 i++;
501         }
502
503         (*num_entries) = i;
504
505         status = NT_STATUS_OK;
506
507         DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
508
509 done:
510         if (res) 
511                 ads_msgfree(ads, res);
512
513         return status;
514 }
515
516 /* list all domain local groups */
517 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
518                                 TALLOC_CTX *mem_ctx,
519                                 uint32_t *num_entries,
520                                 struct wb_acct_info **info)
521 {
522         /*
523          * This is a stub function only as we returned the domain 
524          * local groups in enum_dom_groups() if the domain->native field
525          * was true.  This is a simple performance optimization when
526          * using LDAP.
527          *
528          * if we ever need to enumerate domain local groups separately, 
529          * then this optimization in enum_dom_groups() will need
530          * to be split out
531          */
532         *num_entries = 0;
533
534         return NT_STATUS_OK;
535 }
536
537 /* convert a single name to a sid in a domain - use rpc methods */
538 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
539                             TALLOC_CTX *mem_ctx,
540                             const char *domain_name,
541                             const char *name,
542                             uint32_t flags,
543                             struct dom_sid *sid,
544                             enum lsa_SidType *type)
545 {
546         return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
547                                          flags, sid, type);
548 }
549
550 /* convert a domain SID to a user or group name - use rpc methods */
551 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
552                             TALLOC_CTX *mem_ctx,
553                             const struct dom_sid *sid,
554                             char **domain_name,
555                             char **name,
556                             enum lsa_SidType *type)
557 {
558         return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
559                                          domain_name, name, type);
560 }
561
562 /* convert a list of rids to names - use rpc methods */
563 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
564                               TALLOC_CTX *mem_ctx,
565                               const struct dom_sid *sid,
566                               uint32_t *rids,
567                               size_t num_rids,
568                               char **domain_name,
569                               char ***names,
570                               enum lsa_SidType **types)
571 {
572         return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
573                                            rids, num_rids,
574                                            domain_name, names, types);
575 }
576
577 /* Lookup aliases a user is member of - use rpc methods */
578 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
579                                    TALLOC_CTX *mem_ctx,
580                                    uint32_t num_sids, const struct dom_sid *sids,
581                                    uint32_t *num_aliases, uint32_t **alias_rids)
582 {
583         return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
584                                                 num_aliases, alias_rids);
585 }
586
587 static NTSTATUS add_primary_group_members(
588         ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
589         char ***all_members, size_t *num_all_members)
590 {
591         char *filter;
592         NTSTATUS status = NT_STATUS_NO_MEMORY;
593         ADS_STATUS rc;
594         const char *attrs[] = { "dn", NULL };
595         LDAPMessage *res = NULL;
596         LDAPMessage *msg;
597         char **members;
598         size_t num_members;
599         ads_control args;
600
601         filter = talloc_asprintf(
602                 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
603                 (unsigned)rid);
604         if (filter == NULL) {
605                 goto done;
606         }
607
608         args.control = ADS_EXTENDED_DN_OID;
609         args.val = ADS_EXTENDED_DN_HEX_STRING;
610         args.critical = True;
611
612         rc = ads_do_search_all_args(ads, ads->config.bind_path,
613                                     LDAP_SCOPE_SUBTREE, filter, attrs, &args,
614                                     &res);
615
616         if (!ADS_ERR_OK(rc)) {
617                 status = ads_ntstatus(rc);
618                 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
619                 goto done;
620         }
621         if (res == NULL) {
622                 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
623                 goto done;
624         }
625
626         num_members = ads_count_replies(ads, res);
627
628         DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
629                    (uintmax_t)num_members));
630
631         if (num_members == 0) {
632                 status = NT_STATUS_OK;
633                 goto done;
634         }
635
636         members = talloc_realloc(mem_ctx, *all_members, char *,
637                                  *num_all_members + num_members);
638         if (members == NULL) {
639                 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
640                 goto done;
641         }
642         *all_members = members;
643
644         for (msg = ads_first_entry(ads, res); msg != NULL;
645              msg = ads_next_entry(ads, msg)) {
646                 char *dn;
647
648                 dn = ads_get_dn(ads, members, msg);
649                 if (dn == NULL) {
650                         DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
651                         continue;
652                 }
653
654                 members[*num_all_members] = dn;
655                 *num_all_members += 1;
656         }
657
658         status = NT_STATUS_OK;
659 done:
660         if (res != NULL) {
661                 ads_msgfree(ads, res);
662         }
663         TALLOC_FREE(filter);
664         return status;
665 }
666
667 /*
668   find the members of a group, given a group rid and domain
669  */
670 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
671                                 TALLOC_CTX *mem_ctx,
672                                 const struct dom_sid *group_sid,
673                                 enum lsa_SidType type,
674                                 uint32_t *num_names,
675                                 struct dom_sid **sid_mem, char ***names,
676                                 uint32_t **name_types)
677 {
678         ADS_STATUS rc;
679         ADS_STRUCT *ads = NULL;
680         char *ldap_exp;
681         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
682         char *sidbinstr;
683         char **members = NULL;
684         int i;
685         size_t num_members = 0;
686         ads_control args;
687         struct dom_sid *sid_mem_nocache = NULL;
688         char **names_nocache = NULL;
689         enum lsa_SidType *name_types_nocache = NULL;
690         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
691         uint32_t num_nocache = 0;
692         TALLOC_CTX *tmp_ctx = NULL;
693         uint32_t rid;
694
695         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
696                   sid_string_dbg(group_sid)));
697
698         *num_names = 0;
699
700         tmp_ctx = talloc_new(mem_ctx);
701         if (!tmp_ctx) {
702                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
703                 status = NT_STATUS_NO_MEMORY;
704                 goto done;
705         }
706
707         if (!sid_peek_rid(group_sid, &rid)) {
708                 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
709                 status = NT_STATUS_INVALID_PARAMETER;
710                 goto done;
711         }
712
713         if ( !winbindd_can_contact_domain( domain ) ) {
714                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
715                           domain->name));
716                 return NT_STATUS_OK;
717         }
718
719         ads = ads_cached_connection(domain);
720
721         if (!ads) {
722                 domain->last_status = NT_STATUS_SERVER_DISABLED;
723                 goto done;
724         }
725
726         if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
727                 status = NT_STATUS_NO_MEMORY;
728                 goto done;
729         }
730
731         /* search for all members of the group */
732         ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
733         TALLOC_FREE(sidbinstr);
734         if (ldap_exp == NULL) {
735                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
736                 status = NT_STATUS_NO_MEMORY;
737                 goto done;
738         }
739
740         args.control = ADS_EXTENDED_DN_OID;
741         args.val = ADS_EXTENDED_DN_HEX_STRING;
742         args.critical = True;
743
744         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
745                                ldap_exp, &args, "member", &members, &num_members);
746
747         if (!ADS_ERR_OK(rc)) {
748                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
749                 status = NT_STATUS_UNSUCCESSFUL;
750                 goto done;
751         }
752
753         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
754
755         status = add_primary_group_members(ads, mem_ctx, rid,
756                                            &members, &num_members);
757         if (!NT_STATUS_IS_OK(status)) {
758                 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
759                            __func__, nt_errstr(status)));
760                 goto done;
761         }
762
763         DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
764                    __func__, (int)num_members));
765
766         /* Now that we have a list of sids, we need to get the
767          * lists of names and name_types belonging to these sids.
768          * even though conceptually not quite clean,  we use the
769          * RPC call lsa_lookup_sids for this since it can handle a
770          * list of sids. ldap calls can just resolve one sid at a time.
771          *
772          * At this stage, the sids are still hidden in the exetended dn
773          * member output format. We actually do a little better than
774          * stated above: In extracting the sids from the member strings,
775          * we try to resolve as many sids as possible from the
776          * cache. Only the rest is passed to the lsa_lookup_sids call. */
777
778         if (num_members) {
779                 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
780                 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
781                 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
782                 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
783
784                 if ((members == NULL) || (*sid_mem == NULL) ||
785                     (*names == NULL) || (*name_types == NULL) ||
786                     (sid_mem_nocache == NULL))
787                 {
788                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
789                         status = NT_STATUS_NO_MEMORY;
790                         goto done;
791                 }
792         }
793         else {
794                 (*sid_mem) = NULL;
795                 (*names) = NULL;
796                 (*name_types) = NULL;
797         }
798
799         for (i=0; i<num_members; i++) {
800                 enum lsa_SidType name_type;
801                 char *name, *domain_name;
802                 struct dom_sid sid;
803
804                 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
805                     &sid);
806                 if (!ADS_ERR_OK(rc)) {
807                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
808                             NT_STATUS_NOT_FOUND)) {
809                                 /* Group members can be objects, like Exchange
810                                  * Public Folders, that don't have a SID.  Skip
811                                  * them. */
812                                 continue;
813                         }
814                         else {
815                                 status = ads_ntstatus(rc);
816                                 goto done;
817                         }
818                 }
819                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
820                     &name_type)) {
821                         DEBUG(10,("ads: lookup_groupmem: got sid %s from "
822                                   "cache\n", sid_string_dbg(&sid)));
823                         sid_copy(&(*sid_mem)[*num_names], &sid);
824                         (*names)[*num_names] = fill_domain_username_talloc(
825                                                         *names,
826                                                         domain_name,
827                                                         name,
828                                                         true);
829
830                         (*name_types)[*num_names] = name_type;
831                         (*num_names)++;
832                 }
833                 else {
834                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
835                                    "cache\n", sid_string_dbg(&sid)));
836                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
837                         num_nocache++;
838                 }
839         }
840
841         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
842                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
843
844         /* handle sids not resolved from cache by lsa_lookup_sids */
845         if (num_nocache > 0) {
846
847                 status = winbindd_lookup_sids(tmp_ctx,
848                                               domain,
849                                               num_nocache,
850                                               sid_mem_nocache,
851                                               &domains_nocache,
852                                               &names_nocache,
853                                               &name_types_nocache);
854
855                 if (!(NT_STATUS_IS_OK(status) ||
856                       NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
857                       NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
858                 {
859                         DEBUG(1, ("lsa_lookupsids call failed with %s "
860                                   "- retrying...\n", nt_errstr(status)));
861
862                         status = winbindd_lookup_sids(tmp_ctx,
863                                                       domain,
864                                                       num_nocache,
865                                                       sid_mem_nocache,
866                                                       &domains_nocache,
867                                                       &names_nocache,
868                                                       &name_types_nocache);
869                 }
870
871                 if (NT_STATUS_IS_OK(status) ||
872                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
873                 {
874                         /* Copy the entries over from the "_nocache" arrays
875                          * to the result arrays, skipping the gaps the
876                          * lookup_sids call left. */
877                         for (i=0; i < num_nocache; i++) {
878                                 if (((names_nocache)[i] != NULL) &&
879                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
880                                 {
881                                         sid_copy(&(*sid_mem)[*num_names],
882                                                  &sid_mem_nocache[i]);
883                                         (*names)[*num_names] =
884                                                 fill_domain_username_talloc(
885                                                         *names,
886                                                         domains_nocache[i],
887                                                         names_nocache[i],
888                                                         true);
889                                         (*name_types)[*num_names] = name_types_nocache[i];
890                                         (*num_names)++;
891                                 }
892                         }
893                 }
894                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
895                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
896                                    "not map any SIDs at all.\n"));
897                         /* Don't handle this as an error here.
898                          * There is nothing left to do with respect to the 
899                          * overall result... */
900                 }
901                 else if (!NT_STATUS_IS_OK(status)) {
902                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
903                                    "sids via rpc_lsa_lookup_sids: %s\n",
904                                    (int)num_members, nt_errstr(status)));
905                         goto done;
906                 }
907         }
908
909         status = NT_STATUS_OK;
910         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
911                  sid_string_dbg(group_sid)));
912
913 done:
914
915         TALLOC_FREE(tmp_ctx);
916
917         return status;
918 }
919
920 /* find the sequence number for a domain */
921 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
922 {
923         ADS_STRUCT *ads = NULL;
924         ADS_STATUS rc;
925
926         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
927
928         if ( !winbindd_can_contact_domain( domain ) ) {
929                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
930                           domain->name));
931                 *seq = time(NULL);              
932                 return NT_STATUS_OK;
933         }
934
935         *seq = DOM_SEQUENCE_NONE;
936
937         ads = ads_cached_connection(domain);
938
939         if (!ads) {
940                 domain->last_status = NT_STATUS_SERVER_DISABLED;
941                 return NT_STATUS_UNSUCCESSFUL;
942         }
943
944         rc = ads_USN(ads, seq);
945
946         if (!ADS_ERR_OK(rc)) {
947
948                 /* its a dead connection, destroy it */
949
950                 if (domain->private_data) {
951                         ads = (ADS_STRUCT *)domain->private_data;
952                         ads->is_mine = True;
953                         ads_destroy(&ads);
954                         ads_kdestroy(WINBIND_CCACHE_NAME);
955                         domain->private_data = NULL;
956                 }
957         }
958         return ads_ntstatus(rc);
959 }
960
961 /* find the lockout policy of a domain - use rpc methods */
962 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
963                                TALLOC_CTX *mem_ctx,
964                                struct samr_DomInfo12 *policy)
965 {
966         return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
967 }
968
969 /* find the password policy of a domain - use rpc methods */
970 static NTSTATUS password_policy(struct winbindd_domain *domain,
971                                 TALLOC_CTX *mem_ctx,
972                                 struct samr_DomInfo1 *policy)
973 {
974         return msrpc_methods.password_policy(domain, mem_ctx, policy);
975 }
976
977 /* get a list of trusted domains */
978 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
979                                 TALLOC_CTX *mem_ctx,
980                                 struct netr_DomainTrustList *trusts)
981 {
982         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
983         WERROR werr;
984         int                     i;
985         uint32_t                flags;
986         struct rpc_pipe_client *cli;
987         int ret_count;
988         struct dcerpc_binding_handle *b;
989
990         DEBUG(3,("ads: trusted_domains\n"));
991
992         ZERO_STRUCTP(trusts);
993
994         /* If this is our primary domain or a root in our forest,
995            query for all trusts.  If not, then just look for domain
996            trusts in the target forest */
997
998         if (domain->primary || domain_is_forest_root(domain)) {
999                 flags = NETR_TRUST_FLAG_OUTBOUND |
1000                         NETR_TRUST_FLAG_INBOUND |
1001                         NETR_TRUST_FLAG_IN_FOREST;
1002         } else {
1003                 flags = NETR_TRUST_FLAG_IN_FOREST;
1004         }       
1005
1006         result = cm_connect_netlogon(domain, &cli);
1007
1008         if (!NT_STATUS_IS_OK(result)) {
1009                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1010                           "for PIPE_NETLOGON (%s)\n", 
1011                           domain->name, nt_errstr(result)));
1012                 return NT_STATUS_UNSUCCESSFUL;
1013         }
1014
1015         b = cli->binding_handle;
1016
1017         result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1018                                                       cli->desthost,
1019                                                       flags,
1020                                                       trusts,
1021                                                       &werr);
1022         if (!NT_STATUS_IS_OK(result)) {
1023                 return result;
1024         }
1025
1026         if (!W_ERROR_IS_OK(werr)) {
1027                 return werror_to_ntstatus(werr);
1028         }
1029         if (trusts->count == 0) {
1030                 return NT_STATUS_OK;
1031         }
1032
1033         /* Copy across names and sids */
1034
1035         ret_count = 0;
1036         for (i = 0; i < trusts->count; i++) {
1037                 struct netr_DomainTrust *trust = &trusts->array[i];
1038                 struct winbindd_domain d;
1039
1040                 ZERO_STRUCT(d);
1041
1042                 /*
1043                  * drop external trusts if this is not our primary
1044                  * domain.  This means that the returned number of
1045                  * domains may be less that the ones actually trusted
1046                  * by the DC.
1047                  */
1048
1049                 if ((trust->trust_attributes
1050                      == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1051                     !domain->primary )
1052                 {
1053                         DEBUG(10,("trusted_domains: Skipping external trusted "
1054                                   "domain %s because it is outside of our "
1055                                   "primary domain\n",
1056                                   trust->netbios_name));
1057                         continue;
1058                 }
1059
1060                 /* add to the trusted domain cache */
1061
1062                 d.name = discard_const_p(char, trust->netbios_name);
1063                 d.alt_name = discard_const_p(char, trust->dns_name);
1064
1065                 if (trust->sid) {
1066                         sid_copy(&d.sid, trust->sid);
1067                 } else {
1068                         sid_copy(&d.sid, &global_sid_NULL);
1069                 }
1070
1071                 if ( domain->primary ) {
1072                         DEBUG(10,("trusted_domains(ads):  Searching "
1073                                   "trusted domain list of %s and storing "
1074                                   "trust flags for domain %s\n",
1075                                   domain->name, d.alt_name));
1076
1077                         d.domain_flags = trust->trust_flags;
1078                         d.domain_type = trust->trust_type;
1079                         d.domain_trust_attribs = trust->trust_attributes;
1080
1081                         wcache_tdc_add_domain( &d );
1082                         ret_count++;
1083                 } else if (domain_is_forest_root(domain)) {
1084                         /* Check if we already have this record. If
1085                          * we are following our forest root that is not
1086                          * our primary domain, we want to keep trust
1087                          * flags from the perspective of our primary
1088                          * domain not our forest root. */
1089                         struct winbindd_tdc_domain *exist = NULL;
1090
1091                         exist = wcache_tdc_fetch_domain(
1092                                 talloc_tos(), trust->netbios_name);
1093                         if (!exist) {
1094                                 DEBUG(10,("trusted_domains(ads):  Searching "
1095                                           "trusted domain list of %s and "
1096                                           "storing trust flags for domain "
1097                                           "%s\n", domain->name, d.alt_name));
1098                                 d.domain_flags = trust->trust_flags;
1099                                 d.domain_type = trust->trust_type;
1100                                 d.domain_trust_attribs =
1101                                         trust->trust_attributes;
1102
1103                                 wcache_tdc_add_domain( &d );
1104                                 ret_count++;
1105                         }
1106                         TALLOC_FREE(exist);
1107                 } else {
1108                         /* This gets a little tricky.  If we are
1109                            following a transitive forest trust, then
1110                            innerit the flags, type, and attribs from
1111                            the domain we queried to make sure we don't
1112                            record the view of the trust from the wrong
1113                            side.  Always view it from the side of our
1114                            primary domain.   --jerry */
1115                         struct winbindd_tdc_domain *parent = NULL;
1116
1117                         DEBUG(10,("trusted_domains(ads):  Searching "
1118                                   "trusted domain list of %s and inheriting "
1119                                   "trust flags for domain %s\n",
1120                                   domain->name, d.alt_name));
1121
1122                         parent = wcache_tdc_fetch_domain(talloc_tos(),
1123                                                          domain->name);
1124                         if (parent) {
1125                                 d.domain_flags = parent->trust_flags;
1126                                 d.domain_type  = parent->trust_type;
1127                                 d.domain_trust_attribs = parent->trust_attribs;
1128                         } else {
1129                                 d.domain_flags = domain->domain_flags;
1130                                 d.domain_type  = domain->domain_type;
1131                                 d.domain_trust_attribs =
1132                                         domain->domain_trust_attribs;
1133                         }
1134                         TALLOC_FREE(parent);
1135
1136                         /*
1137                          * We need to pass the modified properties
1138                          * to the caller.
1139                          */
1140                         trust->trust_flags = d.domain_flags;
1141                         trust->trust_type = d.domain_type;
1142                         trust->trust_attributes = d.domain_trust_attribs;
1143
1144                         wcache_tdc_add_domain( &d );
1145                         ret_count++;
1146                 }
1147         }
1148         return result;
1149 }
1150
1151 /* the ADS backend methods are exposed via this structure */
1152 struct winbindd_methods ads_methods = {
1153         True,
1154         query_user_list,
1155         enum_dom_groups,
1156         enum_local_groups,
1157         name_to_sid,
1158         sid_to_name,
1159         rids_to_names,
1160         lookup_useraliases,
1161         lookup_groupmem,
1162         sequence_number,
1163         lockout_policy,
1164         password_policy,
1165         trusted_domains,
1166 };
1167
1168 #endif