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