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