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