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