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