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