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