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 0 : 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 account 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 0 : ADS_STRUCT *ads;
104 0 : ADS_STATUS status;
105 0 : struct sockaddr_storage dc_ss;
106 0 : fstring dc_name;
107 0 : 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 : ADS_TALLOC_CONST_FREE(ads->auth.password);
129 0 : ADS_TALLOC_CONST_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 0 : 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 name 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 0 : 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 0 : int count;
371 0 : uint32_t *rids = NULL;
372 0 : 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 0 : struct dom_sid user_sid;
417 0 : uint32_t atype;
418 0 : 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 0 : 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 : } else {
453 0 : TALLOC_FREE(rids);
454 : }
455 :
456 0 : status = NT_STATUS_OK;
457 :
458 0 : DBG_NOTICE("ads query_user_list gave %d entries\n", count);
459 :
460 0 : done:
461 0 : ads_msgfree(ads, res);
462 0 : return status;
463 : }
464 :
465 : /* list all domain groups */
466 0 : static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
467 : TALLOC_CTX *mem_ctx,
468 : uint32_t *num_entries,
469 : struct wb_acct_info **info)
470 : {
471 0 : ADS_STRUCT *ads = NULL;
472 0 : const char *attrs[] = {"userPrincipalName", "sAMAccountName",
473 : "name", "objectSid", NULL};
474 0 : int i, count;
475 0 : ADS_STATUS rc;
476 0 : LDAPMessage *res = NULL;
477 0 : LDAPMessage *msg = NULL;
478 0 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
479 0 : const char *filter;
480 0 : bool enum_dom_local_groups = False;
481 :
482 0 : *num_entries = 0;
483 :
484 0 : DEBUG(3,("ads: enum_dom_groups\n"));
485 :
486 0 : if ( !winbindd_can_contact_domain( domain ) ) {
487 0 : DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
488 : domain->name));
489 0 : return NT_STATUS_OK;
490 : }
491 :
492 : /* only grab domain local groups for our domain */
493 0 : if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
494 0 : enum_dom_local_groups = True;
495 : }
496 :
497 : /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
498 : * rollup-fixes:
499 : *
500 : * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
501 : * default value, it MUST be absent. In case of extensible matching the
502 : * "dnattr" boolean defaults to FALSE and so it must be only be present
503 : * when set to TRUE.
504 : *
505 : * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
506 : * filter using bitwise matching rule then the buggy AD fails to decode
507 : * the extensible match. As a workaround set it to TRUE and thereby add
508 : * the dnAttributes "dn" field to cope with those older AD versions.
509 : * It should not harm and won't put any additional load on the AD since
510 : * none of the dn components have a bitmask-attribute.
511 : *
512 : * Thanks to Ralf Haferkamp for input and testing - Guenther */
513 :
514 0 : filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)"
515 : "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d)"
516 : "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))))",
517 : GROUP_TYPE_SECURITY_ENABLED,
518 : enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
519 :
520 0 : if (filter == NULL) {
521 0 : status = NT_STATUS_NO_MEMORY;
522 0 : goto done;
523 : }
524 :
525 0 : rc = ads_cached_connection(domain, &ads);
526 0 : if (!ADS_ERR_OK(rc)) {
527 0 : domain->last_status = NT_STATUS_SERVER_DISABLED;
528 0 : goto done;
529 : }
530 :
531 0 : rc = ads_search_retry(ads, &res, filter, attrs);
532 0 : if (!ADS_ERR_OK(rc)) {
533 0 : status = ads_ntstatus(rc);
534 0 : DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
535 0 : goto done;
536 0 : } else if (!res) {
537 0 : DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
538 0 : goto done;
539 : }
540 :
541 0 : count = ads_count_replies(ads, res);
542 0 : if (count == 0) {
543 0 : DEBUG(1,("enum_dom_groups: No groups found\n"));
544 0 : goto done;
545 : }
546 :
547 0 : (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
548 0 : if (!*info) {
549 0 : status = NT_STATUS_NO_MEMORY;
550 0 : goto done;
551 : }
552 :
553 0 : i = 0;
554 :
555 0 : for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
556 0 : char *name, *gecos;
557 0 : struct dom_sid sid;
558 0 : uint32_t rid;
559 :
560 0 : name = ads_pull_username(ads, (*info), msg);
561 0 : gecos = ads_pull_string(ads, (*info), msg, "name");
562 0 : if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
563 0 : DEBUG(1,("No sid for %s !?\n", name));
564 0 : continue;
565 : }
566 :
567 0 : if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
568 0 : DEBUG(1,("No rid for %s !?\n", name));
569 0 : continue;
570 : }
571 :
572 0 : (*info)[i].acct_name = name;
573 0 : (*info)[i].acct_desc = gecos;
574 0 : (*info)[i].rid = rid;
575 0 : i++;
576 : }
577 :
578 0 : (*num_entries) = i;
579 :
580 0 : status = NT_STATUS_OK;
581 :
582 0 : DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
583 :
584 0 : done:
585 0 : if (res)
586 0 : ads_msgfree(ads, res);
587 :
588 0 : return status;
589 : }
590 :
591 : /* list all domain local groups */
592 0 : static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
593 : TALLOC_CTX *mem_ctx,
594 : uint32_t *num_entries,
595 : struct wb_acct_info **info)
596 : {
597 : /*
598 : * This is a stub function only as we returned the domain
599 : * local groups in enum_dom_groups() if the domain->native field
600 : * was true. This is a simple performance optimization when
601 : * using LDAP.
602 : *
603 : * if we ever need to enumerate domain local groups separately,
604 : * then this optimization in enum_dom_groups() will need
605 : * to be split out
606 : */
607 0 : *num_entries = 0;
608 :
609 0 : return NT_STATUS_OK;
610 : }
611 :
612 : /* convert a single name to a sid in a domain - use rpc methods */
613 0 : static NTSTATUS name_to_sid(struct winbindd_domain *domain,
614 : TALLOC_CTX *mem_ctx,
615 : const char *domain_name,
616 : const char *name,
617 : uint32_t flags,
618 : const char **pdom_name,
619 : struct dom_sid *sid,
620 : enum lsa_SidType *type)
621 : {
622 0 : return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
623 : flags, pdom_name, sid, type);
624 : }
625 :
626 : /* convert a domain SID to a user or group name - use rpc methods */
627 0 : static NTSTATUS sid_to_name(struct winbindd_domain *domain,
628 : TALLOC_CTX *mem_ctx,
629 : const struct dom_sid *sid,
630 : char **domain_name,
631 : char **name,
632 : enum lsa_SidType *type)
633 : {
634 0 : return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
635 : domain_name, name, type);
636 : }
637 :
638 : /* convert a list of rids to names - use rpc methods */
639 0 : static NTSTATUS rids_to_names(struct winbindd_domain *domain,
640 : TALLOC_CTX *mem_ctx,
641 : const struct dom_sid *sid,
642 : uint32_t *rids,
643 : size_t num_rids,
644 : char **domain_name,
645 : char ***names,
646 : enum lsa_SidType **types)
647 : {
648 0 : return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
649 : rids, num_rids,
650 : domain_name, names, types);
651 : }
652 :
653 : /* Lookup groups a user is a member of - alternate method, for when
654 : tokenGroups are not available. */
655 0 : static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
656 : TALLOC_CTX *mem_ctx,
657 : const char *user_dn,
658 : struct dom_sid *primary_group,
659 : uint32_t *p_num_groups, struct dom_sid **user_sids)
660 : {
661 0 : ADS_STATUS rc;
662 0 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
663 0 : int count;
664 0 : LDAPMessage *res = NULL;
665 0 : LDAPMessage *msg = NULL;
666 0 : char *ldap_exp;
667 0 : ADS_STRUCT *ads = NULL;
668 0 : const char *group_attrs[] = {"objectSid", NULL};
669 0 : char *escaped_dn;
670 0 : uint32_t num_groups = 0;
671 :
672 0 : DEBUG(3,("ads: lookup_usergroups_member\n"));
673 :
674 0 : if ( !winbindd_can_contact_domain( domain ) ) {
675 0 : DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
676 : domain->name));
677 0 : return NT_STATUS_OK;
678 : }
679 :
680 0 : rc = ads_cached_connection(domain, &ads);
681 0 : if (!ADS_ERR_OK(rc)) {
682 0 : domain->last_status = NT_STATUS_SERVER_DISABLED;
683 0 : goto done;
684 : }
685 :
686 0 : if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
687 0 : status = NT_STATUS_NO_MEMORY;
688 0 : goto done;
689 : }
690 :
691 0 : ldap_exp = talloc_asprintf(mem_ctx,
692 : "(&(member=%s)(objectCategory=group)"
693 : "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))",
694 : escaped_dn,
695 : GROUP_TYPE_SECURITY_ENABLED);
696 0 : if (!ldap_exp) {
697 0 : DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
698 0 : TALLOC_FREE(escaped_dn);
699 0 : status = NT_STATUS_NO_MEMORY;
700 0 : goto done;
701 : }
702 :
703 0 : TALLOC_FREE(escaped_dn);
704 :
705 0 : rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
706 :
707 0 : if (!ADS_ERR_OK(rc)) {
708 0 : DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
709 0 : return ads_ntstatus(rc);
710 0 : } else if (!res) {
711 0 : DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
712 0 : return NT_STATUS_INTERNAL_ERROR;
713 : }
714 :
715 :
716 0 : count = ads_count_replies(ads, res);
717 :
718 0 : *user_sids = NULL;
719 0 : num_groups = 0;
720 :
721 : /* always add the primary group to the sid array */
722 0 : status = add_sid_to_array(mem_ctx, primary_group, user_sids,
723 : &num_groups);
724 0 : if (!NT_STATUS_IS_OK(status)) {
725 0 : goto done;
726 : }
727 :
728 0 : if (count > 0) {
729 0 : for (msg = ads_first_entry(ads, res); msg;
730 0 : msg = ads_next_entry(ads, msg)) {
731 0 : struct dom_sid group_sid;
732 :
733 0 : if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
734 0 : DEBUG(1,("No sid for this group ?!?\n"));
735 0 : continue;
736 : }
737 :
738 : /* ignore Builtin groups from ADS - Guenther */
739 0 : if (sid_check_is_in_builtin(&group_sid)) {
740 0 : continue;
741 : }
742 :
743 0 : status = add_sid_to_array(mem_ctx, &group_sid,
744 : user_sids, &num_groups);
745 0 : if (!NT_STATUS_IS_OK(status)) {
746 0 : goto done;
747 : }
748 : }
749 :
750 : }
751 :
752 0 : *p_num_groups = num_groups;
753 0 : status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
754 :
755 0 : DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
756 0 : done:
757 0 : if (res)
758 0 : ads_msgfree(ads, res);
759 :
760 0 : return status;
761 : }
762 :
763 : /* Lookup groups a user is a member of - alternate method, for when
764 : tokenGroups are not available. */
765 0 : static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
766 : TALLOC_CTX *mem_ctx,
767 : const char *user_dn,
768 : struct dom_sid *primary_group,
769 : uint32_t *p_num_groups,
770 : struct dom_sid **user_sids)
771 : {
772 0 : ADS_STATUS rc;
773 0 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
774 0 : ADS_STRUCT *ads = NULL;
775 0 : const char *attrs[] = {"memberOf", NULL};
776 0 : uint32_t num_groups = 0;
777 0 : struct dom_sid *group_sids = NULL;
778 0 : size_t i;
779 0 : char **strings = NULL;
780 0 : size_t num_strings = 0, num_sids = 0;
781 :
782 :
783 0 : DEBUG(3,("ads: lookup_usergroups_memberof\n"));
784 :
785 0 : if ( !winbindd_can_contact_domain( domain ) ) {
786 0 : DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
787 : "domain %s\n", domain->name));
788 0 : return NT_STATUS_OK;
789 : }
790 :
791 0 : rc = ads_cached_connection(domain, &ads);
792 0 : if (!ADS_ERR_OK(rc)) {
793 0 : domain->last_status = NT_STATUS_SERVER_DISABLED;
794 0 : return NT_STATUS_UNSUCCESSFUL;
795 : }
796 :
797 0 : rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
798 : ADS_EXTENDED_DN_HEX_STRING,
799 : &strings, &num_strings);
800 :
801 0 : if (!ADS_ERR_OK(rc)) {
802 0 : DEBUG(1,("lookup_usergroups_memberof ads_search "
803 : "member=%s: %s\n", user_dn, ads_errstr(rc)));
804 0 : return ads_ntstatus(rc);
805 : }
806 :
807 0 : *user_sids = NULL;
808 0 : num_groups = 0;
809 :
810 : /* always add the primary group to the sid array */
811 0 : status = add_sid_to_array(mem_ctx, primary_group, user_sids,
812 : &num_groups);
813 0 : if (!NT_STATUS_IS_OK(status)) {
814 0 : goto done;
815 : }
816 :
817 0 : group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
818 0 : if (!group_sids) {
819 0 : status = NT_STATUS_NO_MEMORY;
820 0 : goto done;
821 : }
822 :
823 0 : for (i=0; i<num_strings; i++) {
824 0 : rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
825 : ADS_EXTENDED_DN_HEX_STRING,
826 0 : &(group_sids)[i]);
827 0 : if (!ADS_ERR_OK(rc)) {
828 : /* ignore members without SIDs */
829 0 : if (NT_STATUS_EQUAL(ads_ntstatus(rc),
830 : NT_STATUS_NOT_FOUND)) {
831 0 : continue;
832 : }
833 : else {
834 0 : status = ads_ntstatus(rc);
835 0 : goto done;
836 : }
837 : }
838 0 : num_sids++;
839 : }
840 :
841 0 : if (i == 0) {
842 0 : DEBUG(1,("No memberOf for this user?!?\n"));
843 0 : status = NT_STATUS_NO_MEMORY;
844 0 : goto done;
845 : }
846 :
847 0 : for (i=0; i<num_sids; i++) {
848 :
849 : /* ignore Builtin groups from ADS - Guenther */
850 0 : if (sid_check_is_in_builtin(&group_sids[i])) {
851 0 : continue;
852 : }
853 :
854 0 : status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
855 : &num_groups);
856 0 : if (!NT_STATUS_IS_OK(status)) {
857 0 : goto done;
858 : }
859 :
860 : }
861 :
862 0 : *p_num_groups = num_groups;
863 0 : status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
864 :
865 0 : DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
866 : user_dn));
867 :
868 0 : done:
869 0 : TALLOC_FREE(strings);
870 0 : TALLOC_FREE(group_sids);
871 :
872 0 : return status;
873 : }
874 :
875 :
876 : /* Lookup groups a user is a member of. */
877 0 : static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
878 : TALLOC_CTX *mem_ctx,
879 : const struct dom_sid *sid,
880 : uint32_t *p_num_groups, struct dom_sid **user_sids)
881 : {
882 0 : ADS_STRUCT *ads = NULL;
883 0 : const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
884 0 : ADS_STATUS rc;
885 0 : int count;
886 0 : LDAPMessage *msg = NULL;
887 0 : char *user_dn = NULL;
888 0 : struct dom_sid *sids;
889 0 : int i;
890 0 : struct dom_sid primary_group;
891 0 : uint32_t primary_group_rid;
892 0 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
893 0 : uint32_t num_groups = 0;
894 0 : struct dom_sid_buf buf;
895 :
896 0 : DEBUG(3,("ads: lookup_usergroups\n"));
897 0 : *p_num_groups = 0;
898 :
899 0 : status = lookup_usergroups_cached(mem_ctx, sid,
900 : p_num_groups, user_sids);
901 0 : if (NT_STATUS_IS_OK(status)) {
902 0 : return NT_STATUS_OK;
903 : }
904 :
905 0 : if ( !winbindd_can_contact_domain( domain ) ) {
906 0 : DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
907 : domain->name));
908 :
909 : /* Tell the cache manager not to remember this one */
910 :
911 0 : return NT_STATUS_SYNCHRONIZATION_REQUIRED;
912 : }
913 :
914 0 : rc = ads_cached_connection(domain, &ads);
915 0 : if (!ADS_ERR_OK(rc)) {
916 0 : domain->last_status = NT_STATUS_SERVER_DISABLED;
917 0 : status = NT_STATUS_SERVER_DISABLED;
918 0 : goto done;
919 : }
920 :
921 0 : rc = ads_search_retry_sid(ads, &msg, sid, attrs);
922 :
923 0 : if (!ADS_ERR_OK(rc)) {
924 0 : status = ads_ntstatus(rc);
925 0 : DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
926 : "%s\n",
927 : dom_sid_str_buf(sid, &buf),
928 : ads_errstr(rc)));
929 0 : goto done;
930 : }
931 :
932 0 : count = ads_count_replies(ads, msg);
933 0 : if (count != 1) {
934 0 : status = NT_STATUS_UNSUCCESSFUL;
935 0 : DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
936 : "invalid number of results (count=%d)\n",
937 : dom_sid_str_buf(sid, &buf),
938 : count));
939 0 : goto done;
940 : }
941 :
942 0 : if (!msg) {
943 0 : DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
944 : dom_sid_str_buf(sid, &buf)));
945 0 : status = NT_STATUS_UNSUCCESSFUL;
946 0 : goto done;
947 : }
948 :
949 0 : user_dn = ads_get_dn(ads, mem_ctx, msg);
950 0 : if (user_dn == NULL) {
951 0 : status = NT_STATUS_NO_MEMORY;
952 0 : goto done;
953 : }
954 :
955 0 : if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
956 0 : DEBUG(1,("%s: No primary group for sid=%s !?\n",
957 : domain->name,
958 : dom_sid_str_buf(sid, &buf)));
959 0 : goto done;
960 : }
961 :
962 0 : sid_compose(&primary_group, &domain->sid, primary_group_rid);
963 :
964 0 : count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
965 :
966 : /* there must always be at least one group in the token,
967 : unless we are talking to a buggy Win2k server */
968 :
969 : /* actually this only happens when the machine account has no read
970 : * permissions on the tokenGroup attribute - gd */
971 :
972 0 : if (count == 0) {
973 :
974 : /* no tokenGroups */
975 :
976 : /* lookup what groups this user is a member of by DN search on
977 : * "memberOf" */
978 :
979 0 : status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
980 : &primary_group,
981 : &num_groups, user_sids);
982 0 : *p_num_groups = num_groups;
983 0 : if (NT_STATUS_IS_OK(status)) {
984 0 : goto done;
985 : }
986 :
987 : /* lookup what groups this user is a member of by DN search on
988 : * "member" */
989 :
990 0 : status = lookup_usergroups_member(domain, mem_ctx, user_dn,
991 : &primary_group,
992 : &num_groups, user_sids);
993 0 : *p_num_groups = num_groups;
994 0 : goto done;
995 : }
996 :
997 0 : *user_sids = NULL;
998 0 : num_groups = 0;
999 :
1000 0 : status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1001 : &num_groups);
1002 0 : if (!NT_STATUS_IS_OK(status)) {
1003 0 : goto done;
1004 : }
1005 :
1006 0 : for (i=0;i<count;i++) {
1007 :
1008 : /* ignore Builtin groups from ADS - Guenther */
1009 0 : if (sid_check_is_in_builtin(&sids[i])) {
1010 0 : continue;
1011 : }
1012 :
1013 0 : status = add_sid_to_array_unique(mem_ctx, &sids[i],
1014 : user_sids, &num_groups);
1015 0 : if (!NT_STATUS_IS_OK(status)) {
1016 0 : goto done;
1017 : }
1018 : }
1019 :
1020 0 : *p_num_groups = (uint32_t)num_groups;
1021 0 : status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1022 :
1023 0 : DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1024 : dom_sid_str_buf(sid, &buf)));
1025 0 : done:
1026 0 : TALLOC_FREE(user_dn);
1027 0 : ads_msgfree(ads, msg);
1028 0 : return status;
1029 : }
1030 :
1031 : /* Lookup aliases a user is member of - use rpc methods */
1032 0 : static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1033 : TALLOC_CTX *mem_ctx,
1034 : uint32_t num_sids, const struct dom_sid *sids,
1035 : uint32_t *num_aliases, uint32_t **alias_rids)
1036 : {
1037 0 : return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
1038 : num_aliases, alias_rids);
1039 : }
1040 :
1041 0 : static NTSTATUS add_primary_group_members(
1042 : ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, const char *domname,
1043 : char ***all_members, size_t *num_all_members)
1044 : {
1045 0 : char *filter;
1046 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1047 0 : ADS_STATUS rc;
1048 0 : const char *attrs[] = { "dn", NULL };
1049 0 : LDAPMessage *res = NULL;
1050 0 : LDAPMessage *msg;
1051 0 : char **members;
1052 0 : size_t num_members;
1053 0 : ads_control args;
1054 0 : bool all_groupmem = idmap_config_bool(domname, "all_groupmem", false);
1055 :
1056 0 : filter = talloc_asprintf(
1057 : mem_ctx,
1058 : "(&(objectCategory=user)(primaryGroupID=%u)%s)",
1059 : (unsigned)rid,
1060 : all_groupmem ? "" : "(uidNumber=*)(!(uidNumber=0))");
1061 0 : if (filter == NULL) {
1062 0 : goto done;
1063 : }
1064 :
1065 0 : args.control = ADS_EXTENDED_DN_OID;
1066 0 : args.val = ADS_EXTENDED_DN_HEX_STRING;
1067 0 : args.critical = True;
1068 :
1069 0 : rc = ads_do_search_all_args(ads, ads->config.bind_path,
1070 : LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1071 : &res);
1072 :
1073 0 : if (!ADS_ERR_OK(rc)) {
1074 0 : status = ads_ntstatus(rc);
1075 0 : DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1076 0 : goto done;
1077 : }
1078 0 : if (res == NULL) {
1079 0 : DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1080 0 : goto done;
1081 : }
1082 :
1083 0 : num_members = ads_count_replies(ads, res);
1084 :
1085 0 : DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1086 : (uintmax_t)num_members));
1087 :
1088 0 : if (num_members == 0) {
1089 0 : status = NT_STATUS_OK;
1090 0 : goto done;
1091 : }
1092 :
1093 0 : members = talloc_realloc(mem_ctx, *all_members, char *,
1094 : *num_all_members + num_members);
1095 0 : if (members == NULL) {
1096 0 : DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1097 0 : goto done;
1098 : }
1099 0 : *all_members = members;
1100 :
1101 0 : for (msg = ads_first_entry(ads, res); msg != NULL;
1102 0 : msg = ads_next_entry(ads, msg)) {
1103 0 : char *dn;
1104 :
1105 0 : dn = ads_get_dn(ads, members, msg);
1106 0 : if (dn == NULL) {
1107 0 : DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1108 0 : continue;
1109 : }
1110 :
1111 0 : members[*num_all_members] = dn;
1112 0 : *num_all_members += 1;
1113 : }
1114 :
1115 0 : status = NT_STATUS_OK;
1116 0 : done:
1117 0 : if (res != NULL) {
1118 0 : ads_msgfree(ads, res);
1119 : }
1120 0 : TALLOC_FREE(filter);
1121 0 : return status;
1122 : }
1123 :
1124 : /*
1125 : find the members of a group, given a group rid and domain
1126 : */
1127 0 : static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1128 : TALLOC_CTX *mem_ctx,
1129 : const struct dom_sid *group_sid,
1130 : enum lsa_SidType type,
1131 : uint32_t *num_names,
1132 : struct dom_sid **sid_mem, char ***names,
1133 : uint32_t **name_types)
1134 : {
1135 0 : ADS_STATUS rc;
1136 0 : ADS_STRUCT *ads = NULL;
1137 0 : char *ldap_exp;
1138 0 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1139 0 : char *sidbinstr;
1140 0 : char **members = NULL;
1141 0 : size_t i;
1142 0 : size_t num_members = 0;
1143 0 : ads_control args;
1144 0 : struct dom_sid *sid_mem_nocache = NULL;
1145 0 : char **names_nocache = NULL;
1146 0 : enum lsa_SidType *name_types_nocache = NULL;
1147 0 : char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1148 0 : uint32_t num_nocache = 0;
1149 0 : TALLOC_CTX *tmp_ctx = NULL;
1150 0 : uint32_t rid;
1151 0 : struct dom_sid_buf buf;
1152 :
1153 0 : DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1154 : dom_sid_str_buf(group_sid, &buf)));
1155 :
1156 0 : *num_names = 0;
1157 :
1158 0 : tmp_ctx = talloc_new(mem_ctx);
1159 0 : if (!tmp_ctx) {
1160 0 : DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1161 0 : status = NT_STATUS_NO_MEMORY;
1162 0 : goto done;
1163 : }
1164 :
1165 0 : if (!sid_peek_rid(group_sid, &rid)) {
1166 0 : DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1167 0 : status = NT_STATUS_INVALID_PARAMETER;
1168 0 : goto done;
1169 : }
1170 :
1171 0 : if ( !winbindd_can_contact_domain( domain ) ) {
1172 0 : DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1173 : domain->name));
1174 0 : return NT_STATUS_OK;
1175 : }
1176 :
1177 0 : rc = ads_cached_connection(domain, &ads);
1178 0 : if (!ADS_ERR_OK(rc)) {
1179 0 : domain->last_status = NT_STATUS_SERVER_DISABLED;
1180 0 : goto done;
1181 : }
1182 :
1183 0 : if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1184 0 : status = NT_STATUS_NO_MEMORY;
1185 0 : goto done;
1186 : }
1187 :
1188 : /* search for all members of the group */
1189 0 : ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1190 0 : TALLOC_FREE(sidbinstr);
1191 0 : if (ldap_exp == NULL) {
1192 0 : DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1193 0 : status = NT_STATUS_NO_MEMORY;
1194 0 : goto done;
1195 : }
1196 :
1197 0 : args.control = ADS_EXTENDED_DN_OID;
1198 0 : args.val = ADS_EXTENDED_DN_HEX_STRING;
1199 0 : args.critical = True;
1200 :
1201 0 : rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1202 : ldap_exp, &args, "member", &members, &num_members);
1203 :
1204 0 : if (!ADS_ERR_OK(rc)) {
1205 0 : DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1206 0 : status = NT_STATUS_UNSUCCESSFUL;
1207 0 : goto done;
1208 : }
1209 :
1210 0 : DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1211 :
1212 0 : status = add_primary_group_members(ads, mem_ctx, rid, domain->name,
1213 : &members, &num_members);
1214 0 : if (!NT_STATUS_IS_OK(status)) {
1215 0 : DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1216 : __func__, nt_errstr(status)));
1217 0 : goto done;
1218 : }
1219 :
1220 0 : DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1221 : __func__, (int)num_members));
1222 :
1223 : /* Now that we have a list of sids, we need to get the
1224 : * lists of names and name_types belonging to these sids.
1225 : * even though conceptually not quite clean, we use the
1226 : * RPC call lsa_lookup_sids for this since it can handle a
1227 : * list of sids. ldap calls can just resolve one sid at a time.
1228 : *
1229 : * At this stage, the sids are still hidden in the exetended dn
1230 : * member output format. We actually do a little better than
1231 : * stated above: In extracting the sids from the member strings,
1232 : * we try to resolve as many sids as possible from the
1233 : * cache. Only the rest is passed to the lsa_lookup_sids call. */
1234 :
1235 0 : if (num_members) {
1236 0 : (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1237 0 : (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1238 0 : (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1239 0 : (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1240 :
1241 0 : if ((members == NULL) || (*sid_mem == NULL) ||
1242 0 : (*names == NULL) || (*name_types == NULL) ||
1243 : (sid_mem_nocache == NULL))
1244 : {
1245 0 : DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1246 0 : status = NT_STATUS_NO_MEMORY;
1247 0 : goto done;
1248 : }
1249 : }
1250 : else {
1251 0 : (*sid_mem) = NULL;
1252 0 : (*names) = NULL;
1253 0 : (*name_types) = NULL;
1254 : }
1255 :
1256 0 : for (i=0; i<num_members; i++) {
1257 0 : enum lsa_SidType name_type;
1258 0 : char *name, *domain_name;
1259 0 : struct dom_sid sid;
1260 :
1261 0 : rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1262 : &sid);
1263 0 : if (!ADS_ERR_OK(rc)) {
1264 0 : if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1265 : NT_STATUS_NOT_FOUND)) {
1266 : /* Group members can be objects, like Exchange
1267 : * Public Folders, that don't have a SID. Skip
1268 : * them. */
1269 0 : continue;
1270 : }
1271 : else {
1272 0 : status = ads_ntstatus(rc);
1273 0 : goto done;
1274 : }
1275 : }
1276 0 : if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1277 : &name_type)) {
1278 0 : DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1279 : "cache\n",
1280 : dom_sid_str_buf(&sid, &buf)));
1281 0 : sid_copy(&(*sid_mem)[*num_names], &sid);
1282 0 : (*names)[*num_names] = fill_domain_username_talloc(
1283 : *names,
1284 : domain_name,
1285 : name,
1286 : true);
1287 :
1288 0 : (*name_types)[*num_names] = name_type;
1289 0 : (*num_names)++;
1290 : }
1291 : else {
1292 0 : DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1293 : "cache\n",
1294 : dom_sid_str_buf(&sid, &buf)));
1295 0 : sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1296 0 : num_nocache++;
1297 : }
1298 : }
1299 :
1300 0 : DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1301 : "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1302 :
1303 : /* handle sids not resolved from cache by lsa_lookup_sids */
1304 0 : if (num_nocache > 0) {
1305 :
1306 0 : status = winbindd_lookup_sids(tmp_ctx,
1307 : domain,
1308 : num_nocache,
1309 : sid_mem_nocache,
1310 : &domains_nocache,
1311 : &names_nocache,
1312 : &name_types_nocache);
1313 :
1314 0 : if (!(NT_STATUS_IS_OK(status) ||
1315 0 : NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1316 0 : NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1317 : {
1318 0 : DEBUG(1, ("lsa_lookupsids call failed with %s "
1319 : "- retrying...\n", nt_errstr(status)));
1320 :
1321 0 : status = winbindd_lookup_sids(tmp_ctx,
1322 : domain,
1323 : num_nocache,
1324 : sid_mem_nocache,
1325 : &domains_nocache,
1326 : &names_nocache,
1327 : &name_types_nocache);
1328 : }
1329 :
1330 0 : if (NT_STATUS_IS_OK(status) ||
1331 0 : NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1332 : {
1333 : /* Copy the entries over from the "_nocache" arrays
1334 : * to the result arrays, skipping the gaps the
1335 : * lookup_sids call left. */
1336 0 : for (i=0; i < num_nocache; i++) {
1337 0 : if (((names_nocache)[i] != NULL) &&
1338 0 : ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1339 : {
1340 0 : sid_copy(&(*sid_mem)[*num_names],
1341 0 : &sid_mem_nocache[i]);
1342 0 : (*names)[*num_names] =
1343 0 : fill_domain_username_talloc(
1344 : *names,
1345 0 : domains_nocache[i],
1346 0 : names_nocache[i],
1347 : true);
1348 0 : (*name_types)[*num_names] = name_types_nocache[i];
1349 0 : (*num_names)++;
1350 : }
1351 : }
1352 : }
1353 0 : else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1354 0 : DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1355 : "not map any SIDs at all.\n"));
1356 : /* Don't handle this as an error here.
1357 : * There is nothing left to do with respect to the
1358 : * overall result... */
1359 : }
1360 0 : else if (!NT_STATUS_IS_OK(status)) {
1361 0 : DEBUG(10, ("lookup_groupmem: Error looking up %d "
1362 : "sids via rpc_lsa_lookup_sids: %s\n",
1363 : (int)num_members, nt_errstr(status)));
1364 0 : goto done;
1365 : }
1366 : }
1367 :
1368 0 : status = NT_STATUS_OK;
1369 0 : DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1370 : dom_sid_str_buf(group_sid, &buf)));
1371 :
1372 0 : done:
1373 :
1374 0 : TALLOC_FREE(tmp_ctx);
1375 :
1376 0 : return status;
1377 : }
1378 :
1379 0 : static NTSTATUS lookup_aliasmem(struct winbindd_domain *domain,
1380 : TALLOC_CTX *mem_ctx,
1381 : const struct dom_sid *sid,
1382 : enum lsa_SidType type,
1383 : uint32_t *num_sids,
1384 : struct dom_sid **sids)
1385 : {
1386 0 : char **names = NULL;
1387 0 : uint32_t *name_types = NULL;
1388 0 : struct dom_sid_buf buf;
1389 :
1390 0 : DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
1391 : domain->name,
1392 : dom_sid_str_buf(sid, &buf));
1393 : /* Search for alias and group membership uses the same LDAP command. */
1394 0 : return lookup_groupmem(domain,
1395 : mem_ctx,
1396 : sid,
1397 : type,
1398 : num_sids,
1399 : sids,
1400 : &names,
1401 : &name_types);
1402 : }
1403 :
1404 : /* find the lockout policy of a domain - use rpc methods */
1405 0 : static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1406 : TALLOC_CTX *mem_ctx,
1407 : struct samr_DomInfo12 *policy)
1408 : {
1409 0 : return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1410 : }
1411 :
1412 : /* find the password policy of a domain - use rpc methods */
1413 0 : static NTSTATUS password_policy(struct winbindd_domain *domain,
1414 : TALLOC_CTX *mem_ctx,
1415 : struct samr_DomInfo1 *policy)
1416 : {
1417 0 : return msrpc_methods.password_policy(domain, mem_ctx, policy);
1418 : }
1419 :
1420 : /* get a list of trusted domains */
1421 0 : static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1422 : TALLOC_CTX *mem_ctx,
1423 : struct netr_DomainTrustList *trusts)
1424 : {
1425 0 : NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1426 0 : WERROR werr;
1427 0 : uint32_t i;
1428 0 : uint32_t flags;
1429 0 : struct rpc_pipe_client *cli;
1430 0 : struct dcerpc_binding_handle *b;
1431 :
1432 0 : DEBUG(3,("ads: trusted_domains\n"));
1433 :
1434 0 : ZERO_STRUCTP(trusts);
1435 :
1436 : /* If this is our primary domain or a root in our forest,
1437 : query for all trusts. If not, then just look for domain
1438 : trusts in the target forest */
1439 :
1440 0 : if (domain->primary || domain_is_forest_root(domain)) {
1441 0 : flags = NETR_TRUST_FLAG_OUTBOUND |
1442 : NETR_TRUST_FLAG_INBOUND |
1443 : NETR_TRUST_FLAG_IN_FOREST;
1444 : } else {
1445 0 : flags = NETR_TRUST_FLAG_IN_FOREST;
1446 : }
1447 :
1448 0 : result = cm_connect_netlogon(domain, &cli);
1449 :
1450 0 : if (!NT_STATUS_IS_OK(result)) {
1451 0 : DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1452 : "for PIPE_NETLOGON (%s)\n",
1453 : domain->name, nt_errstr(result)));
1454 0 : return NT_STATUS_UNSUCCESSFUL;
1455 : }
1456 :
1457 0 : b = cli->binding_handle;
1458 :
1459 0 : result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1460 0 : cli->desthost,
1461 : flags,
1462 : trusts,
1463 : &werr);
1464 0 : if (!NT_STATUS_IS_OK(result)) {
1465 0 : return result;
1466 : }
1467 :
1468 0 : if (!W_ERROR_IS_OK(werr)) {
1469 0 : return werror_to_ntstatus(werr);
1470 : }
1471 0 : if (trusts->count == 0) {
1472 0 : return NT_STATUS_OK;
1473 : }
1474 :
1475 : /* Copy across names and sids */
1476 :
1477 0 : for (i = 0; i < trusts->count; i++) {
1478 0 : struct netr_DomainTrust *trust = &trusts->array[i];
1479 0 : struct winbindd_domain d;
1480 :
1481 0 : ZERO_STRUCT(d);
1482 :
1483 : /*
1484 : * drop external trusts if this is not our primary
1485 : * domain. This means that the returned number of
1486 : * domains may be less that the ones actually trusted
1487 : * by the DC.
1488 : */
1489 :
1490 0 : if ((trust->trust_attributes
1491 0 : & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1492 0 : !domain->primary )
1493 : {
1494 0 : DEBUG(10,("trusted_domains: Skipping external trusted "
1495 : "domain %s because it is outside of our "
1496 : "primary domain\n",
1497 : trust->netbios_name));
1498 0 : continue;
1499 : }
1500 :
1501 : /* add to the trusted domain cache */
1502 :
1503 0 : d.name = discard_const_p(char, trust->netbios_name);
1504 0 : d.alt_name = discard_const_p(char, trust->dns_name);
1505 :
1506 0 : if (trust->sid) {
1507 0 : sid_copy(&d.sid, trust->sid);
1508 : } else {
1509 0 : sid_copy(&d.sid, &global_sid_NULL);
1510 : }
1511 :
1512 0 : if ( domain->primary ) {
1513 0 : DEBUG(10,("trusted_domains(ads): Searching "
1514 : "trusted domain list of %s and storing "
1515 : "trust flags for domain %s\n",
1516 : domain->name, d.alt_name));
1517 :
1518 0 : d.domain_flags = trust->trust_flags;
1519 0 : d.domain_type = trust->trust_type;
1520 0 : d.domain_trust_attribs = trust->trust_attributes;
1521 :
1522 0 : wcache_tdc_add_domain( &d );
1523 0 : } else if (domain_is_forest_root(domain)) {
1524 : /* Check if we already have this record. If
1525 : * we are following our forest root that is not
1526 : * our primary domain, we want to keep trust
1527 : * flags from the perspective of our primary
1528 : * domain not our forest root. */
1529 0 : struct winbindd_tdc_domain *exist = NULL;
1530 :
1531 0 : exist = wcache_tdc_fetch_domain(
1532 : talloc_tos(), trust->netbios_name);
1533 0 : if (!exist) {
1534 0 : DEBUG(10,("trusted_domains(ads): Searching "
1535 : "trusted domain list of %s and "
1536 : "storing trust flags for domain "
1537 : "%s\n", domain->name, d.alt_name));
1538 0 : d.domain_flags = trust->trust_flags;
1539 0 : d.domain_type = trust->trust_type;
1540 0 : d.domain_trust_attribs =
1541 0 : trust->trust_attributes;
1542 :
1543 0 : wcache_tdc_add_domain( &d );
1544 : }
1545 0 : TALLOC_FREE(exist);
1546 : } else {
1547 : /* This gets a little tricky. If we are
1548 : following a transitive forest trust, then
1549 : innerit the flags, type, and attribs from
1550 : the domain we queried to make sure we don't
1551 : record the view of the trust from the wrong
1552 : side. Always view it from the side of our
1553 : primary domain. --jerry */
1554 0 : struct winbindd_tdc_domain *parent = NULL;
1555 :
1556 0 : DEBUG(10,("trusted_domains(ads): Searching "
1557 : "trusted domain list of %s and inheriting "
1558 : "trust flags for domain %s\n",
1559 : domain->name, d.alt_name));
1560 :
1561 0 : parent = wcache_tdc_fetch_domain(talloc_tos(),
1562 0 : domain->name);
1563 0 : if (parent) {
1564 0 : d.domain_flags = parent->trust_flags;
1565 0 : d.domain_type = parent->trust_type;
1566 0 : d.domain_trust_attribs = parent->trust_attribs;
1567 : } else {
1568 0 : d.domain_flags = domain->domain_flags;
1569 0 : d.domain_type = domain->domain_type;
1570 0 : d.domain_trust_attribs =
1571 0 : domain->domain_trust_attribs;
1572 : }
1573 0 : TALLOC_FREE(parent);
1574 :
1575 : /*
1576 : * We need to pass the modified properties
1577 : * to the caller.
1578 : */
1579 0 : trust->trust_flags = d.domain_flags;
1580 0 : trust->trust_type = d.domain_type;
1581 0 : trust->trust_attributes = d.domain_trust_attribs;
1582 :
1583 0 : wcache_tdc_add_domain( &d );
1584 : }
1585 : }
1586 0 : return result;
1587 : }
1588 :
1589 : /* the ADS backend methods are exposed via this structure */
1590 : struct winbindd_methods ads_methods = {
1591 : True,
1592 : query_user_list,
1593 : enum_dom_groups,
1594 : enum_local_groups,
1595 : name_to_sid,
1596 : sid_to_name,
1597 : rids_to_names,
1598 : lookup_usergroups,
1599 : lookup_useraliases,
1600 : lookup_groupmem,
1601 : lookup_aliasmem,
1602 : lockout_policy,
1603 : password_policy,
1604 : trusted_domains,
1605 : };
1606 :
1607 : #endif
|