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