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