source: branches/samba-3.5.x/source3/winbindd/winbindd_ads.c

Last change on this file was 736, checked in by Silvan Scherrer, 13 years ago

Samba Server 3.5: update branche to 3.5.16

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