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