Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * Winbind rpc backend functions
5 : *
6 : * Copyright (c) 2000-2003 Tim Potter
7 : * Copyright (c) 2001 Andrew Tridgell
8 : * Copyright (c) 2005 Volker Lendecke
9 : * Copyright (c) 2008 Guenther Deschner (pidl conversion)
10 : * Copyright (c) 2010 Andreas Schneider <asn@samba.org>
11 : *
12 : * This program is free software; you can redistribute it and/or modify
13 : * it under the terms of the GNU General Public License as published by
14 : * the Free Software Foundation; either version 3 of the License, or
15 : * (at your option) any later version.
16 : *
17 : * This program is distributed in the hope that it will be useful,
18 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : * GNU General Public License for more details.
21 : *
22 : * You should have received a copy of the GNU General Public License
23 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include "includes.h"
27 : #include "winbindd.h"
28 : #include "winbindd_rpc.h"
29 : #include "lib/util_unixsids.h"
30 : #include "rpc_client/rpc_client.h"
31 : #include "rpc_client/cli_pipe.h"
32 : #include "../librpc/gen_ndr/ndr_samr_c.h"
33 : #include "rpc_client/cli_samr.h"
34 : #include "../librpc/gen_ndr/ndr_lsa_c.h"
35 : #include "rpc_client/cli_lsarpc.h"
36 : #include "rpc_server/rpc_ncacn_np.h"
37 : #include "../libcli/security/security.h"
38 : #include "passdb/machine_sid.h"
39 : #include "auth.h"
40 : #include "source3/lib/global_contexts.h"
41 :
42 : #undef DBGC_CLASS
43 : #define DBGC_CLASS DBGC_WINBIND
44 :
45 : /*
46 : * The other end of this won't go away easily, so we can trust it
47 : *
48 : * It is either a long-lived process with the same lifetime as
49 : * winbindd or a part of this process
50 : */
51 : struct winbind_internal_pipes {
52 : struct tevent_timer *shutdown_timer;
53 : struct rpc_pipe_client *samr_pipe;
54 : struct policy_handle samr_domain_hnd;
55 : struct rpc_pipe_client *lsa_pipe;
56 : struct policy_handle lsa_hnd;
57 : };
58 :
59 :
60 0 : NTSTATUS open_internal_samr_conn(TALLOC_CTX *mem_ctx,
61 : struct winbindd_domain *domain,
62 : struct rpc_pipe_client **samr_pipe,
63 : struct policy_handle *samr_domain_hnd)
64 : {
65 : NTSTATUS status, result;
66 : struct policy_handle samr_connect_hnd;
67 : struct dcerpc_binding_handle *b;
68 :
69 0 : status = wb_open_internal_pipe(mem_ctx, &ndr_table_samr, samr_pipe);
70 0 : if (!NT_STATUS_IS_OK(status)) {
71 0 : DBG_ERR("Could not connect to %s pipe: %s\n",
72 : ndr_table_samr.name, nt_errstr(status));
73 0 : return status;
74 : }
75 :
76 0 : b = (*samr_pipe)->binding_handle;
77 :
78 0 : status = dcerpc_samr_Connect2(b, mem_ctx,
79 0 : (*samr_pipe)->desthost,
80 : SEC_FLAG_MAXIMUM_ALLOWED,
81 : &samr_connect_hnd,
82 : &result);
83 0 : if (!NT_STATUS_IS_OK(status)) {
84 0 : return status;
85 : }
86 0 : if (!NT_STATUS_IS_OK(result)) {
87 0 : return result;
88 : }
89 :
90 0 : status = dcerpc_samr_OpenDomain(b, mem_ctx,
91 : &samr_connect_hnd,
92 : SEC_FLAG_MAXIMUM_ALLOWED,
93 : &domain->sid,
94 : samr_domain_hnd,
95 : &result);
96 0 : if (!NT_STATUS_IS_OK(status)) {
97 0 : return status;
98 : }
99 :
100 0 : return result;
101 : }
102 :
103 0 : NTSTATUS open_internal_lsa_conn(TALLOC_CTX *mem_ctx,
104 : struct rpc_pipe_client **lsa_pipe,
105 : struct policy_handle *lsa_hnd)
106 : {
107 : NTSTATUS status;
108 :
109 0 : status = wb_open_internal_pipe(mem_ctx, &ndr_table_lsarpc, lsa_pipe);
110 0 : if (!NT_STATUS_IS_OK(status)) {
111 0 : DBG_ERR("Could not connect to %s pipe: %s\n",
112 : ndr_table_lsarpc.name, nt_errstr(status));
113 0 : return status;
114 : }
115 :
116 0 : status = rpccli_lsa_open_policy((*lsa_pipe),
117 : mem_ctx,
118 : true,
119 : SEC_FLAG_MAXIMUM_ALLOWED,
120 : lsa_hnd);
121 :
122 0 : return status;
123 : }
124 :
125 0 : static void cached_internal_pipe_close(
126 : struct tevent_context *ev,
127 : struct tevent_timer *te,
128 : struct timeval current_time,
129 : void *private_data)
130 : {
131 0 : struct winbindd_domain *domain = talloc_get_type_abort(
132 : private_data, struct winbindd_domain);
133 : /*
134 : * Freeing samr_pipes closes the cached pipes.
135 : *
136 : * We can do a hard close because at the time of this commit
137 : * we only use sychronous calls to external pipes. So we can't
138 : * have any outstanding requests. Also, we don't set
139 : * dcerpc_binding_handle_set_sync_ev in winbind, so we don't
140 : * get nested event loops. Once we start to get async in
141 : * winbind children, we need to check for outstanding calls
142 : */
143 0 : TALLOC_FREE(domain->backend_data.samr_pipes);
144 0 : }
145 :
146 0 : static NTSTATUS open_cached_internal_pipe_conn(
147 : struct winbindd_domain *domain,
148 : struct rpc_pipe_client **samr_pipe,
149 : struct policy_handle *samr_domain_hnd,
150 : struct rpc_pipe_client **lsa_pipe,
151 : struct policy_handle *lsa_hnd)
152 : {
153 0 : struct winbind_internal_pipes *internal_pipes =
154 : domain->backend_data.samr_pipes;
155 :
156 0 : if (internal_pipes == NULL) {
157 0 : TALLOC_CTX *frame = talloc_stackframe();
158 : NTSTATUS status;
159 :
160 0 : internal_pipes = talloc_zero(frame,
161 : struct winbind_internal_pipes);
162 :
163 0 : status = open_internal_samr_conn(
164 : internal_pipes,
165 : domain,
166 : &internal_pipes->samr_pipe,
167 : &internal_pipes->samr_domain_hnd);
168 0 : if (!NT_STATUS_IS_OK(status)) {
169 0 : TALLOC_FREE(frame);
170 0 : return status;
171 : }
172 :
173 0 : status = open_internal_lsa_conn(internal_pipes,
174 : &internal_pipes->lsa_pipe,
175 : &internal_pipes->lsa_hnd);
176 :
177 0 : if (!NT_STATUS_IS_OK(status)) {
178 0 : TALLOC_FREE(frame);
179 0 : return status;
180 : }
181 :
182 0 : internal_pipes->shutdown_timer = tevent_add_timer(
183 : global_event_context(),
184 : internal_pipes,
185 : timeval_current_ofs(5, 0),
186 : cached_internal_pipe_close,
187 : domain);
188 0 : if (internal_pipes->shutdown_timer == NULL) {
189 0 : TALLOC_FREE(frame);
190 0 : return NT_STATUS_NO_MEMORY;
191 : }
192 :
193 0 : domain->backend_data.samr_pipes =
194 0 : talloc_steal(domain, internal_pipes);
195 :
196 0 : TALLOC_FREE(frame);
197 : }
198 :
199 0 : if (samr_domain_hnd) {
200 0 : *samr_domain_hnd = internal_pipes->samr_domain_hnd;
201 : }
202 :
203 0 : if (samr_pipe) {
204 0 : *samr_pipe = internal_pipes->samr_pipe;
205 : }
206 :
207 0 : if (lsa_hnd) {
208 0 : *lsa_hnd = internal_pipes->lsa_hnd;
209 : }
210 :
211 0 : if (lsa_pipe) {
212 0 : *lsa_pipe = internal_pipes->lsa_pipe;
213 : }
214 :
215 0 : tevent_update_timer(
216 : internal_pipes->shutdown_timer,
217 : timeval_current_ofs(5, 0));
218 :
219 0 : return NT_STATUS_OK;
220 : }
221 :
222 0 : static bool reset_connection_on_error(struct winbindd_domain *domain,
223 : struct rpc_pipe_client *p,
224 : NTSTATUS status)
225 : {
226 0 : struct dcerpc_binding_handle *b = p->binding_handle;
227 :
228 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
229 0 : NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
230 : {
231 0 : TALLOC_FREE(domain->backend_data.samr_pipes);
232 0 : return true;
233 : }
234 :
235 0 : if (!dcerpc_binding_handle_is_connected(b)) {
236 0 : TALLOC_FREE(domain->backend_data.samr_pipes);
237 0 : return true;
238 : }
239 :
240 0 : return false;
241 : }
242 :
243 : /*********************************************************************
244 : SAM specific functions.
245 : *********************************************************************/
246 :
247 : /* List all domain groups */
248 0 : static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
249 : TALLOC_CTX *mem_ctx,
250 : uint32_t *pnum_info,
251 : struct wb_acct_info **pinfo)
252 : {
253 : struct rpc_pipe_client *samr_pipe;
254 0 : struct policy_handle dom_pol = { 0 };
255 0 : struct wb_acct_info *info = NULL;
256 0 : uint32_t num_info = 0;
257 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
258 : NTSTATUS status;
259 0 : bool retry = false;
260 :
261 0 : DEBUG(3,("sam_enum_dom_groups\n"));
262 :
263 0 : if (pnum_info) {
264 0 : *pnum_info = 0;
265 : }
266 :
267 0 : again:
268 0 : status = open_cached_internal_pipe_conn(domain,
269 : &samr_pipe,
270 : &dom_pol,
271 : NULL,
272 : NULL);
273 0 : if (!NT_STATUS_IS_OK(status)) {
274 0 : TALLOC_FREE(tmp_ctx);
275 0 : return status;
276 : }
277 :
278 0 : status = rpc_enum_dom_groups(tmp_ctx,
279 : samr_pipe,
280 : &dom_pol,
281 : &num_info,
282 : &info);
283 :
284 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
285 0 : retry = true;
286 0 : goto again;
287 : }
288 :
289 0 : if (!NT_STATUS_IS_OK(status)) {
290 0 : TALLOC_FREE(tmp_ctx);
291 0 : return status;
292 : }
293 :
294 0 : if (pnum_info) {
295 0 : *pnum_info = num_info;
296 : }
297 :
298 0 : if (pinfo) {
299 0 : *pinfo = talloc_move(mem_ctx, &info);
300 : }
301 :
302 0 : TALLOC_FREE(tmp_ctx);
303 0 : return status;
304 : }
305 :
306 : /* Query display info for a domain */
307 0 : static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
308 : TALLOC_CTX *mem_ctx,
309 : uint32_t **prids)
310 : {
311 0 : struct rpc_pipe_client *samr_pipe = NULL;
312 0 : struct policy_handle dom_pol = { 0 };
313 0 : uint32_t *rids = NULL;
314 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
315 : NTSTATUS status;
316 0 : bool retry = false;
317 :
318 0 : DEBUG(3,("samr_query_user_list\n"));
319 :
320 0 : again:
321 0 : status = open_cached_internal_pipe_conn(domain,
322 : &samr_pipe,
323 : &dom_pol,
324 : NULL,
325 : NULL);
326 0 : if (!NT_STATUS_IS_OK(status)) {
327 0 : goto done;
328 : }
329 :
330 0 : status = rpc_query_user_list(tmp_ctx,
331 : samr_pipe,
332 : &dom_pol,
333 0 : &domain->sid,
334 : &rids);
335 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
336 0 : retry = true;
337 0 : goto again;
338 : }
339 :
340 0 : if (!NT_STATUS_IS_OK(status)) {
341 0 : goto done;
342 : }
343 :
344 0 : if (prids != NULL) {
345 0 : *prids = talloc_move(mem_ctx, &rids);
346 : }
347 :
348 0 : done:
349 0 : TALLOC_FREE(rids);
350 0 : TALLOC_FREE(tmp_ctx);
351 0 : return status;
352 : }
353 :
354 : /* get a list of trusted domains - builtin domain */
355 0 : static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
356 : TALLOC_CTX *mem_ctx,
357 : struct netr_DomainTrustList *ptrust_list)
358 : {
359 : struct rpc_pipe_client *lsa_pipe;
360 0 : struct policy_handle lsa_policy = { 0 };
361 0 : struct netr_DomainTrust *trusts = NULL;
362 0 : uint32_t num_trusts = 0;
363 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
364 : NTSTATUS status;
365 0 : bool retry = false;
366 :
367 0 : DEBUG(3,("samr: trusted domains\n"));
368 :
369 0 : if (ptrust_list) {
370 0 : ZERO_STRUCTP(ptrust_list);
371 : }
372 :
373 0 : again:
374 0 : status = open_cached_internal_pipe_conn(domain,
375 : NULL,
376 : NULL,
377 : &lsa_pipe,
378 : &lsa_policy);
379 0 : if (!NT_STATUS_IS_OK(status)) {
380 0 : goto done;
381 : }
382 :
383 0 : status = rpc_trusted_domains(tmp_ctx,
384 : lsa_pipe,
385 : &lsa_policy,
386 : &num_trusts,
387 : &trusts);
388 :
389 0 : if (!retry && reset_connection_on_error(domain, lsa_pipe, status)) {
390 0 : retry = true;
391 0 : goto again;
392 : }
393 :
394 0 : if (!NT_STATUS_IS_OK(status)) {
395 0 : goto done;
396 : }
397 :
398 0 : if (ptrust_list) {
399 0 : ptrust_list->count = num_trusts;
400 0 : ptrust_list->array = talloc_move(mem_ctx, &trusts);
401 : }
402 :
403 0 : done:
404 0 : TALLOC_FREE(tmp_ctx);
405 0 : return status;
406 : }
407 :
408 : /* Lookup group membership given a rid. */
409 0 : static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
410 : TALLOC_CTX *mem_ctx,
411 : const struct dom_sid *group_sid,
412 : enum lsa_SidType type,
413 : uint32_t *pnum_names,
414 : struct dom_sid **psid_mem,
415 : char ***pnames,
416 : uint32_t **pname_types)
417 : {
418 : struct rpc_pipe_client *samr_pipe;
419 0 : struct policy_handle dom_pol = { 0 };
420 :
421 0 : uint32_t num_names = 0;
422 0 : struct dom_sid *sid_mem = NULL;
423 0 : char **names = NULL;
424 0 : uint32_t *name_types = NULL;
425 :
426 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
427 : NTSTATUS status;
428 0 : bool retry = false;
429 :
430 0 : DEBUG(3,("sam_lookup_groupmem\n"));
431 :
432 : /* Paranoia check */
433 0 : if (sid_check_is_in_builtin(group_sid) && (type != SID_NAME_ALIAS)) {
434 : /* There's no groups, only aliases in BUILTIN */
435 0 : status = NT_STATUS_NO_SUCH_GROUP;
436 0 : goto done;
437 : }
438 :
439 0 : if (pnum_names) {
440 0 : *pnum_names = 0;
441 : }
442 :
443 0 : again:
444 0 : status = open_cached_internal_pipe_conn(domain,
445 : &samr_pipe,
446 : &dom_pol,
447 : NULL,
448 : NULL);
449 0 : if (!NT_STATUS_IS_OK(status)) {
450 0 : goto done;
451 : }
452 :
453 0 : status = rpc_lookup_groupmem(tmp_ctx,
454 : samr_pipe,
455 : &dom_pol,
456 0 : domain->name,
457 0 : &domain->sid,
458 : group_sid,
459 : type,
460 : &num_names,
461 : &sid_mem,
462 : &names,
463 : &name_types);
464 :
465 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
466 0 : retry = true;
467 0 : goto again;
468 : }
469 :
470 0 : if (pnum_names) {
471 0 : *pnum_names = num_names;
472 : }
473 :
474 0 : if (pnames) {
475 0 : *pnames = talloc_move(mem_ctx, &names);
476 : }
477 :
478 0 : if (pname_types) {
479 0 : *pname_types = talloc_move(mem_ctx, &name_types);
480 : }
481 :
482 0 : if (psid_mem) {
483 0 : *psid_mem = talloc_move(mem_ctx, &sid_mem);
484 : }
485 :
486 0 : done:
487 0 : TALLOC_FREE(tmp_ctx);
488 0 : return status;
489 : }
490 :
491 : /*********************************************************************
492 : BUILTIN specific functions.
493 : *********************************************************************/
494 :
495 : /* List all domain groups */
496 0 : static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
497 : TALLOC_CTX *mem_ctx,
498 : uint32_t *num_entries,
499 : struct wb_acct_info **info)
500 : {
501 : /* BUILTIN doesn't have domain groups */
502 0 : *num_entries = 0;
503 0 : *info = NULL;
504 0 : return NT_STATUS_OK;
505 : }
506 :
507 : /* Query display info for a domain */
508 0 : static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
509 : TALLOC_CTX *mem_ctx,
510 : uint32_t **rids)
511 : {
512 : /* We don't have users */
513 0 : *rids = NULL;
514 0 : return NT_STATUS_OK;
515 : }
516 :
517 : /* get a list of trusted domains - builtin domain */
518 0 : static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
519 : TALLOC_CTX *mem_ctx,
520 : struct netr_DomainTrustList *trusts)
521 : {
522 0 : ZERO_STRUCTP(trusts);
523 0 : return NT_STATUS_OK;
524 : }
525 :
526 : /*********************************************************************
527 : COMMON functions.
528 : *********************************************************************/
529 :
530 : /* List all local groups (aliases) */
531 0 : static NTSTATUS sam_enum_local_groups(struct winbindd_domain *domain,
532 : TALLOC_CTX *mem_ctx,
533 : uint32_t *pnum_info,
534 : struct wb_acct_info **pinfo)
535 : {
536 : struct rpc_pipe_client *samr_pipe;
537 0 : struct policy_handle dom_pol = { 0 };
538 0 : struct wb_acct_info *info = NULL;
539 0 : uint32_t num_info = 0;
540 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
541 : NTSTATUS status;
542 0 : bool retry = false;
543 :
544 0 : DEBUG(3,("samr: enum local groups\n"));
545 :
546 0 : if (pnum_info) {
547 0 : *pnum_info = 0;
548 : }
549 :
550 0 : again:
551 0 : status = open_cached_internal_pipe_conn(domain,
552 : &samr_pipe,
553 : &dom_pol,
554 : NULL,
555 : NULL);
556 0 : if (!NT_STATUS_IS_OK(status)) {
557 0 : goto done;
558 : }
559 :
560 0 : status = rpc_enum_local_groups(mem_ctx,
561 : samr_pipe,
562 : &dom_pol,
563 : &num_info,
564 :
565 : &info);
566 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
567 0 : retry = true;
568 0 : goto again;
569 : }
570 :
571 0 : if (!NT_STATUS_IS_OK(status)) {
572 0 : goto done;
573 : }
574 :
575 0 : if (pnum_info) {
576 0 : *pnum_info = num_info;
577 : }
578 :
579 0 : if (pinfo) {
580 0 : *pinfo = talloc_move(mem_ctx, &info);
581 : }
582 :
583 0 : done:
584 0 : TALLOC_FREE(tmp_ctx);
585 0 : return status;
586 : }
587 :
588 : /* convert a single name to a sid in a domain */
589 0 : static NTSTATUS sam_name_to_sid(struct winbindd_domain *domain,
590 : TALLOC_CTX *mem_ctx,
591 : const char *domain_name,
592 : const char *name,
593 : uint32_t flags,
594 : const char **pdom_name,
595 : struct dom_sid *psid,
596 : enum lsa_SidType *ptype)
597 : {
598 0 : struct rpc_pipe_client *samr_pipe = NULL;
599 0 : struct dcerpc_binding_handle *h = NULL;
600 0 : struct policy_handle dom_pol = { .handle_type = 0, };
601 : struct dom_sid sid;
602 0 : const char *dom_name = domain_name;
603 0 : struct lsa_String lsa_name = { .string = name };
604 0 : struct samr_Ids rids = { .count = 0 };
605 0 : struct samr_Ids types = { .count = 0 };
606 : enum lsa_SidType type;
607 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
608 0 : NTSTATUS status = NT_STATUS_NONE_MAPPED;
609 : NTSTATUS result;
610 0 : bool retry = false;
611 : bool ok;
612 :
613 0 : DBG_NOTICE("%s\\%s\n", domain_name, name);
614 :
615 0 : if (strequal(domain_name, unix_users_domain_name())) {
616 0 : struct passwd *pwd = NULL;
617 :
618 0 : if (name[0] == '\0') {
619 0 : sid_copy(&sid, &global_sid_Unix_Users);
620 0 : type = SID_NAME_DOMAIN;
621 0 : goto done;
622 : }
623 :
624 0 : pwd = Get_Pwnam_alloc(tmp_ctx, name);
625 0 : if (pwd == NULL) {
626 0 : goto fail;
627 : }
628 0 : ok = sid_compose(&sid, &global_sid_Unix_Users, pwd->pw_uid);
629 0 : if (!ok) {
630 0 : status = NT_STATUS_INTERNAL_ERROR;
631 0 : goto fail;
632 : }
633 0 : type = SID_NAME_USER;
634 0 : goto done;
635 : }
636 :
637 0 : if (strequal(domain_name, unix_groups_domain_name())) {
638 0 : struct group *grp = NULL;
639 :
640 0 : if (name[0] == '\0') {
641 0 : sid_copy(&sid, &global_sid_Unix_Groups);
642 0 : type = SID_NAME_DOMAIN;
643 0 : goto done;
644 : }
645 :
646 0 : grp = getgrnam(name);
647 0 : if (grp == NULL) {
648 0 : goto fail;
649 : }
650 0 : ok = sid_compose(&sid, &global_sid_Unix_Groups, grp->gr_gid);
651 0 : if (!ok) {
652 0 : status = NT_STATUS_INTERNAL_ERROR;
653 0 : goto fail;
654 : }
655 0 : type = SID_NAME_DOM_GRP;
656 0 : goto done;
657 : }
658 :
659 0 : if (name[0] == '\0') {
660 0 : sid_copy(&sid, &domain->sid);
661 0 : type = SID_NAME_DOMAIN;
662 0 : goto done;
663 : }
664 :
665 0 : ok = lookup_wellknown_name(tmp_ctx, name, &sid, &dom_name);
666 0 : if (ok) {
667 0 : type = SID_NAME_WKN_GRP;
668 0 : goto done;
669 : }
670 :
671 : {
672 0 : char *normalized = NULL;
673 0 : NTSTATUS nstatus = normalize_name_unmap(
674 : tmp_ctx, name, &normalized);
675 0 : if (NT_STATUS_IS_OK(nstatus) ||
676 0 : NT_STATUS_EQUAL(nstatus, NT_STATUS_FILE_RENAMED)) {
677 0 : lsa_name.string = normalized;
678 : }
679 : }
680 :
681 0 : again:
682 0 : status = open_cached_internal_pipe_conn(
683 : domain, &samr_pipe, &dom_pol, NULL, NULL);
684 0 : if (!NT_STATUS_IS_OK(status)) {
685 0 : goto fail;
686 : }
687 0 : h = samr_pipe->binding_handle;
688 :
689 0 : status = dcerpc_samr_LookupNames(
690 : h, tmp_ctx, &dom_pol, 1, &lsa_name, &rids, &types, &result);
691 :
692 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
693 0 : retry = true;
694 0 : goto again;
695 : }
696 :
697 0 : if (!NT_STATUS_IS_OK(status)) {
698 0 : DBG_DEBUG("dcerpc_samr_LookupNames returned %s\n",
699 : nt_errstr(status));
700 0 : goto fail;
701 : }
702 0 : if (!NT_STATUS_IS_OK(result)) {
703 0 : DBG_DEBUG("dcerpc_samr_LookupNames resulted in %s\n",
704 : nt_errstr(status));
705 0 : status = result;
706 0 : goto fail;
707 : }
708 :
709 0 : sid_compose(&sid, &domain->sid, rids.ids[0]);
710 0 : type = types.ids[0];
711 :
712 0 : done:
713 0 : if (pdom_name != NULL) {
714 0 : *pdom_name = talloc_strdup(mem_ctx, dom_name);
715 0 : if (*pdom_name == NULL) {
716 0 : status = NT_STATUS_NO_MEMORY;
717 0 : goto fail;
718 : }
719 : }
720 :
721 0 : if (psid) {
722 0 : sid_copy(psid, &sid);
723 : }
724 0 : if (ptype) {
725 0 : *ptype = type;
726 : }
727 :
728 0 : status = NT_STATUS_OK;
729 0 : fail:
730 0 : TALLOC_FREE(tmp_ctx);
731 0 : return status;
732 : }
733 :
734 : /* convert a domain SID to a user or group name */
735 0 : static NTSTATUS sam_sid_to_name(struct winbindd_domain *domain,
736 : TALLOC_CTX *mem_ctx,
737 : const struct dom_sid *sid,
738 : char **pdomain_name,
739 : char **pname,
740 : enum lsa_SidType *ptype)
741 : {
742 0 : struct rpc_pipe_client *samr_pipe = NULL;
743 0 : struct dcerpc_binding_handle *h = NULL;
744 0 : struct policy_handle dom_pol = { .handle_type = 0, };
745 0 : const char *domain_name = "";
746 0 : const char *name = "";
747 0 : enum lsa_SidType type = SID_NAME_USE_NONE;
748 0 : struct lsa_Strings names = { .count = 0, };
749 0 : struct samr_Ids types = { .count = 0 };
750 : struct dom_sid domain_sid;
751 : uint32_t rid;
752 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
753 0 : NTSTATUS status = NT_STATUS_NONE_MAPPED;
754 : NTSTATUS result;
755 0 : bool retry = false;
756 : bool ok;
757 :
758 0 : DEBUG(3,("sam_sid_to_name\n"));
759 :
760 0 : if (sid_check_is_unix_users(sid)) {
761 0 : domain_name = unix_users_domain_name();
762 0 : type = SID_NAME_DOMAIN;
763 0 : goto done;
764 : }
765 0 : if (sid_check_is_in_unix_users(sid)) {
766 0 : struct passwd *pwd = NULL;
767 :
768 0 : ok = sid_peek_rid(sid, &rid);
769 0 : if (!ok) {
770 0 : goto fail;
771 : }
772 0 : pwd = getpwuid(rid);
773 0 : if (pwd == NULL) {
774 0 : goto fail;
775 : }
776 :
777 0 : domain_name = unix_users_domain_name();
778 0 : name = talloc_strdup(tmp_ctx, pwd->pw_name);
779 0 : if (name == NULL) {
780 0 : status = NT_STATUS_NO_MEMORY;
781 0 : goto fail;
782 : }
783 0 : type = SID_NAME_USER;
784 0 : goto done;
785 : }
786 :
787 0 : if (sid_check_is_unix_groups(sid)) {
788 0 : domain_name = unix_groups_domain_name();
789 0 : type = SID_NAME_DOMAIN;
790 0 : goto done;
791 : }
792 0 : if (sid_check_is_in_unix_groups(sid)) {
793 0 : struct group *grp = NULL;
794 :
795 0 : ok = sid_peek_rid(sid, &rid);
796 0 : if (!ok) {
797 0 : goto fail;
798 : }
799 0 : grp = getgrgid(rid);
800 0 : if (grp == NULL) {
801 0 : goto fail;
802 : }
803 :
804 0 : domain_name = unix_groups_domain_name();
805 0 : name = talloc_strdup(tmp_ctx, grp->gr_name);
806 0 : if (name == NULL) {
807 0 : status = NT_STATUS_NO_MEMORY;
808 0 : goto fail;
809 : }
810 0 : type = SID_NAME_DOM_GRP;
811 0 : goto done;
812 : }
813 :
814 0 : ok = lookup_wellknown_sid(tmp_ctx, sid, &domain_name, &name);
815 0 : if (ok) {
816 0 : type = SID_NAME_WKN_GRP;
817 0 : goto done;
818 : }
819 :
820 0 : if (dom_sid_equal(sid, &domain->sid)) {
821 0 : domain_name = domain->name;
822 0 : type = SID_NAME_DOMAIN;
823 0 : goto done;
824 : }
825 :
826 0 : sid_copy(&domain_sid, sid);
827 0 : ok = sid_split_rid(&domain_sid, &rid);
828 0 : if (!ok) {
829 0 : goto fail;
830 : }
831 :
832 0 : if (!dom_sid_equal(&domain_sid, &domain->sid)) {
833 0 : goto fail;
834 : }
835 :
836 0 : again:
837 0 : status = open_cached_internal_pipe_conn(
838 : domain, &samr_pipe, &dom_pol, NULL, NULL);
839 0 : if (!NT_STATUS_IS_OK(status)) {
840 0 : goto fail;
841 : }
842 0 : h = samr_pipe->binding_handle;
843 :
844 0 : status = dcerpc_samr_LookupRids(
845 : h, tmp_ctx, &dom_pol, 1, &rid, &names, &types, &result);
846 :
847 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
848 0 : retry = true;
849 0 : goto again;
850 : }
851 :
852 0 : if (!NT_STATUS_IS_OK(status)) {
853 0 : DBG_DEBUG("dcerpc_samr_LookupRids failed: %s\n",
854 : nt_errstr(status));
855 0 : goto fail;
856 : }
857 0 : if (!NT_STATUS_IS_OK(result)) {
858 0 : DBG_DEBUG("dcerpc_samr_LookupRids resulted in %s\n",
859 : nt_errstr(result));
860 0 : status = result;
861 0 : goto fail;
862 : }
863 :
864 0 : domain_name = domain->name;
865 0 : name = names.names[0].string;
866 0 : type = types.ids[0];
867 :
868 0 : if (name != NULL) {
869 0 : char *normalized = NULL;
870 0 : NTSTATUS nstatus = normalize_name_map(
871 : tmp_ctx, domain_name, name, &normalized);
872 0 : if (NT_STATUS_IS_OK(nstatus) ||
873 0 : NT_STATUS_EQUAL(nstatus, NT_STATUS_FILE_RENAMED)) {
874 0 : name = normalized;
875 : }
876 : }
877 :
878 0 : done:
879 0 : if (ptype) {
880 0 : *ptype = type;
881 : }
882 :
883 0 : if (pname) {
884 0 : *pname = talloc_strdup(mem_ctx, name);
885 0 : if (*pname == NULL) {
886 0 : status = NT_STATUS_NO_MEMORY;
887 0 : goto fail;
888 : }
889 : }
890 :
891 0 : if (pdomain_name) {
892 0 : *pdomain_name = talloc_strdup(mem_ctx, domain_name);
893 0 : if (*pdomain_name == NULL) {
894 0 : status = NT_STATUS_NO_MEMORY;
895 0 : goto fail;
896 : }
897 : }
898 :
899 0 : status = NT_STATUS_OK;
900 0 : fail:
901 0 : TALLOC_FREE(tmp_ctx);
902 0 : return status;
903 : }
904 :
905 0 : static NTSTATUS sam_rids_to_names(struct winbindd_domain *domain,
906 : TALLOC_CTX *mem_ctx,
907 : const struct dom_sid *domain_sid,
908 : uint32_t *rids,
909 : size_t num_rids,
910 : char **pdomain_name,
911 : char ***pnames,
912 : enum lsa_SidType **ptypes)
913 : {
914 0 : struct rpc_pipe_client *samr_pipe = NULL;
915 0 : struct dcerpc_binding_handle *h = NULL;
916 0 : struct policy_handle dom_pol = { .handle_type = 0, };
917 0 : enum lsa_SidType *types = NULL;
918 0 : char **names = NULL;
919 0 : const char *domain_name = NULL;
920 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
921 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
922 : NTSTATUS result;
923 0 : bool retry = false;
924 : uint32_t i;
925 :
926 0 : DEBUG(3,("sam_rids_to_names for %s\n", domain->name));
927 :
928 0 : types = talloc_array(tmp_ctx, enum lsa_SidType, num_rids);
929 0 : if (types == NULL) {
930 0 : goto fail;
931 : }
932 :
933 0 : names = talloc_array(tmp_ctx, char *, num_rids);
934 0 : if (names == NULL) {
935 0 : goto fail;
936 : }
937 :
938 0 : if (sid_check_is_unix_users(domain_sid)) {
939 0 : domain_name = unix_users_domain_name();
940 0 : domain_sid = &global_sid_Unix_Users;
941 : }
942 0 : if (sid_check_is_unix_groups(domain_sid)) {
943 0 : domain_name = unix_groups_domain_name();
944 0 : domain_sid = &global_sid_Unix_Groups;
945 : }
946 :
947 : /* Here we're only interested in the domain name being set */
948 0 : sid_check_is_wellknown_domain(domain_sid, &domain_name);
949 :
950 0 : if (domain_name != NULL) {
951 0 : uint32_t num_mapped = 0;
952 :
953 : /*
954 : * Do unix users/groups and wkn in a loop. There is no
955 : * getpwuids() call & friends anyway
956 : */
957 :
958 0 : for (i=0; i<num_rids; i++) {
959 : struct dom_sid sid;
960 0 : char *name = NULL;
961 :
962 0 : sid_compose(&sid, domain_sid, rids[i]);
963 :
964 0 : types[i] = SID_NAME_UNKNOWN;
965 0 : names[i] = NULL;
966 :
967 0 : status = sam_sid_to_name(
968 : domain,
969 : tmp_ctx,
970 : &sid,
971 : NULL,
972 : &name,
973 0 : &types[i]);
974 0 : if (NT_STATUS_IS_OK(status)) {
975 0 : names[i] = talloc_move(names, &name);
976 0 : num_mapped += 1;
977 : }
978 : }
979 :
980 0 : status = NT_STATUS_NONE_MAPPED;
981 0 : if (num_mapped > 0) {
982 0 : status = (num_mapped == num_rids) ?
983 0 : NT_STATUS_OK : STATUS_SOME_UNMAPPED;
984 : }
985 0 : goto done;
986 : }
987 :
988 0 : domain_name = domain->name;
989 :
990 0 : again:
991 0 : status = open_cached_internal_pipe_conn(
992 : domain, &samr_pipe, &dom_pol, NULL, NULL);
993 0 : if (!NT_STATUS_IS_OK(status)) {
994 0 : goto done;
995 : }
996 0 : h = samr_pipe->binding_handle;
997 :
998 : /*
999 : * Magic number 1000 comes from samr.idl
1000 : */
1001 :
1002 0 : for (i = 0; i < num_rids; i += 1000) {
1003 0 : uint32_t num_lookup_rids = MIN(num_rids - i, 1000);
1004 0 : struct lsa_Strings lsa_names = {
1005 : .count = 0,
1006 : };
1007 0 : struct samr_Ids samr_types = {
1008 : .count = 0,
1009 : };
1010 : uint32_t j;
1011 :
1012 0 : status = dcerpc_samr_LookupRids(h,
1013 : tmp_ctx,
1014 : &dom_pol,
1015 : num_lookup_rids,
1016 0 : &rids[i],
1017 : &lsa_names,
1018 : &samr_types,
1019 : &result);
1020 :
1021 0 : if (!retry &&
1022 0 : reset_connection_on_error(domain, samr_pipe, status)) {
1023 0 : retry = true;
1024 0 : goto again;
1025 : }
1026 :
1027 0 : if (!NT_STATUS_IS_OK(status)) {
1028 0 : DBG_DEBUG("dcerpc_samr_LookupRids failed: %s\n",
1029 : nt_errstr(status));
1030 0 : goto fail;
1031 : }
1032 0 : if (!NT_STATUS_IS_OK(result) &&
1033 0 : !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1034 0 : DBG_DEBUG("dcerpc_samr_LookupRids resulted in %s\n",
1035 : nt_errstr(result));
1036 0 : status = result;
1037 0 : goto fail;
1038 : }
1039 :
1040 0 : for (j = 0; j < num_lookup_rids; j++) {
1041 0 : uint32_t dst = i + j;
1042 :
1043 0 : types[dst] = samr_types.ids[j];
1044 0 : names[dst] = talloc_move(
1045 : names,
1046 : discard_const_p(char *,
1047 : &lsa_names.names[j].string));
1048 0 : if (names[dst] != NULL) {
1049 0 : char *normalized = NULL;
1050 0 : NTSTATUS nstatus =
1051 0 : normalize_name_map(names,
1052 : domain_name,
1053 0 : names[dst],
1054 : &normalized);
1055 0 : if (NT_STATUS_IS_OK(nstatus) ||
1056 0 : NT_STATUS_EQUAL(nstatus,
1057 : NT_STATUS_FILE_RENAMED)) {
1058 0 : names[dst] = normalized;
1059 : }
1060 : }
1061 : }
1062 :
1063 0 : TALLOC_FREE(samr_types.ids);
1064 0 : TALLOC_FREE(lsa_names.names);
1065 : }
1066 :
1067 0 : done:
1068 0 : if (pdomain_name) {
1069 0 : *pdomain_name = talloc_strdup(mem_ctx, domain_name);
1070 0 : if (*pdomain_name == NULL) {
1071 0 : status = NT_STATUS_NO_MEMORY;
1072 0 : goto fail;
1073 : }
1074 : }
1075 :
1076 0 : if (ptypes) {
1077 0 : *ptypes = talloc_move(mem_ctx, &types);
1078 : }
1079 :
1080 0 : if (pnames) {
1081 0 : *pnames = talloc_move(mem_ctx, &names);
1082 : }
1083 :
1084 0 : fail:
1085 0 : TALLOC_FREE(tmp_ctx);
1086 0 : return status;
1087 : }
1088 :
1089 0 : static NTSTATUS sam_lockout_policy(struct winbindd_domain *domain,
1090 : TALLOC_CTX *mem_ctx,
1091 : struct samr_DomInfo12 *lockout_policy)
1092 : {
1093 : struct rpc_pipe_client *samr_pipe;
1094 0 : struct policy_handle dom_pol = { 0 };
1095 0 : union samr_DomainInfo *info = NULL;
1096 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1097 : NTSTATUS status, result;
1098 0 : struct dcerpc_binding_handle *b = NULL;
1099 0 : bool retry = false;
1100 :
1101 0 : DEBUG(3,("sam_lockout_policy\n"));
1102 :
1103 0 : again:
1104 0 : status = open_cached_internal_pipe_conn(domain,
1105 : &samr_pipe,
1106 : &dom_pol,
1107 : NULL,
1108 : NULL);
1109 0 : if (!NT_STATUS_IS_OK(status)) {
1110 0 : goto error;
1111 : }
1112 :
1113 0 : b = samr_pipe->binding_handle;
1114 :
1115 0 : status = dcerpc_samr_QueryDomainInfo(b,
1116 : mem_ctx,
1117 : &dom_pol,
1118 : DomainLockoutInformation,
1119 : &info,
1120 : &result);
1121 :
1122 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
1123 0 : retry = true;
1124 0 : goto again;
1125 : }
1126 :
1127 0 : if (!NT_STATUS_IS_OK(status)) {
1128 0 : goto error;
1129 : }
1130 0 : if (!NT_STATUS_IS_OK(result)) {
1131 0 : status = result;
1132 0 : goto error;
1133 : }
1134 :
1135 0 : *lockout_policy = info->info12;
1136 :
1137 0 : error:
1138 0 : TALLOC_FREE(tmp_ctx);
1139 0 : return status;
1140 : }
1141 :
1142 0 : static NTSTATUS sam_password_policy(struct winbindd_domain *domain,
1143 : TALLOC_CTX *mem_ctx,
1144 : struct samr_DomInfo1 *passwd_policy)
1145 : {
1146 : struct rpc_pipe_client *samr_pipe;
1147 0 : struct policy_handle dom_pol = { 0 };
1148 0 : union samr_DomainInfo *info = NULL;
1149 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1150 : NTSTATUS status, result;
1151 0 : struct dcerpc_binding_handle *b = NULL;
1152 0 : bool retry = false;
1153 :
1154 0 : DEBUG(3,("sam_password_policy\n"));
1155 :
1156 0 : again:
1157 0 : status = open_cached_internal_pipe_conn(domain,
1158 : &samr_pipe,
1159 : &dom_pol,
1160 : NULL,
1161 : NULL);
1162 0 : if (!NT_STATUS_IS_OK(status)) {
1163 0 : goto error;
1164 : }
1165 :
1166 0 : b = samr_pipe->binding_handle;
1167 :
1168 0 : status = dcerpc_samr_QueryDomainInfo(b,
1169 : mem_ctx,
1170 : &dom_pol,
1171 : DomainPasswordInformation,
1172 : &info,
1173 : &result);
1174 :
1175 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
1176 0 : retry = true;
1177 0 : goto again;
1178 : }
1179 :
1180 0 : if (!NT_STATUS_IS_OK(status)) {
1181 0 : goto error;
1182 : }
1183 0 : if (!NT_STATUS_IS_OK(result)) {
1184 0 : status = result;
1185 0 : goto error;
1186 : }
1187 :
1188 0 : *passwd_policy = info->info1;
1189 :
1190 0 : error:
1191 0 : TALLOC_FREE(tmp_ctx);
1192 0 : return status;
1193 : }
1194 :
1195 : /* Lookup groups a user is a member of. */
1196 0 : static NTSTATUS sam_lookup_usergroups(struct winbindd_domain *domain,
1197 : TALLOC_CTX *mem_ctx,
1198 : const struct dom_sid *user_sid,
1199 : uint32_t *pnum_groups,
1200 : struct dom_sid **puser_grpsids)
1201 : {
1202 : struct rpc_pipe_client *samr_pipe;
1203 : struct policy_handle dom_pol;
1204 0 : struct dom_sid *user_grpsids = NULL;
1205 0 : uint32_t num_groups = 0;
1206 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1207 : NTSTATUS status;
1208 0 : bool retry = false;
1209 :
1210 0 : DEBUG(3,("sam_lookup_usergroups\n"));
1211 :
1212 0 : ZERO_STRUCT(dom_pol);
1213 :
1214 0 : if (pnum_groups) {
1215 0 : *pnum_groups = 0;
1216 : }
1217 :
1218 0 : again:
1219 0 : status = open_cached_internal_pipe_conn(domain,
1220 : &samr_pipe,
1221 : &dom_pol,
1222 : NULL,
1223 : NULL);
1224 0 : if (!NT_STATUS_IS_OK(status)) {
1225 0 : goto done;
1226 : }
1227 :
1228 0 : status = rpc_lookup_usergroups(tmp_ctx,
1229 : samr_pipe,
1230 : &dom_pol,
1231 0 : &domain->sid,
1232 : user_sid,
1233 : &num_groups,
1234 : &user_grpsids);
1235 :
1236 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
1237 0 : retry = true;
1238 0 : goto again;
1239 : }
1240 :
1241 0 : if (!NT_STATUS_IS_OK(status)) {
1242 0 : goto done;
1243 : }
1244 :
1245 0 : if (pnum_groups) {
1246 0 : *pnum_groups = num_groups;
1247 : }
1248 :
1249 0 : if (puser_grpsids) {
1250 0 : *puser_grpsids = talloc_move(mem_ctx, &user_grpsids);
1251 : }
1252 :
1253 0 : done:
1254 :
1255 0 : TALLOC_FREE(tmp_ctx);
1256 0 : return status;
1257 : }
1258 :
1259 0 : static NTSTATUS sam_lookup_useraliases(struct winbindd_domain *domain,
1260 : TALLOC_CTX *mem_ctx,
1261 : uint32_t num_sids,
1262 : const struct dom_sid *sids,
1263 : uint32_t *pnum_aliases,
1264 : uint32_t **palias_rids)
1265 : {
1266 : struct rpc_pipe_client *samr_pipe;
1267 0 : struct policy_handle dom_pol = { 0 };
1268 0 : uint32_t num_aliases = 0;
1269 0 : uint32_t *alias_rids = NULL;
1270 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1271 : NTSTATUS status;
1272 0 : bool retry = false;
1273 :
1274 0 : DEBUG(3,("sam_lookup_useraliases\n"));
1275 :
1276 0 : if (pnum_aliases) {
1277 0 : *pnum_aliases = 0;
1278 : }
1279 :
1280 0 : again:
1281 0 : status = open_cached_internal_pipe_conn(domain,
1282 : &samr_pipe,
1283 : &dom_pol,
1284 : NULL,
1285 : NULL);
1286 0 : if (!NT_STATUS_IS_OK(status)) {
1287 0 : goto done;
1288 : }
1289 :
1290 0 : status = rpc_lookup_useraliases(tmp_ctx,
1291 : samr_pipe,
1292 : &dom_pol,
1293 : num_sids,
1294 : sids,
1295 : &num_aliases,
1296 : &alias_rids);
1297 :
1298 0 : if (!retry && reset_connection_on_error(domain, samr_pipe, status)) {
1299 0 : retry = true;
1300 0 : goto again;
1301 : }
1302 :
1303 0 : if (!NT_STATUS_IS_OK(status)) {
1304 0 : goto done;
1305 : }
1306 :
1307 0 : if (pnum_aliases) {
1308 0 : *pnum_aliases = num_aliases;
1309 : }
1310 :
1311 0 : if (palias_rids) {
1312 0 : *palias_rids = talloc_move(mem_ctx, &alias_rids);
1313 : }
1314 :
1315 0 : done:
1316 :
1317 0 : TALLOC_FREE(tmp_ctx);
1318 0 : return status;
1319 : }
1320 :
1321 : /* the rpc backend methods are exposed via this structure */
1322 : struct winbindd_methods builtin_passdb_methods = {
1323 : .consistent = false,
1324 :
1325 : .query_user_list = builtin_query_user_list,
1326 : .enum_dom_groups = builtin_enum_dom_groups,
1327 : .enum_local_groups = sam_enum_local_groups,
1328 : .name_to_sid = sam_name_to_sid,
1329 : .sid_to_name = sam_sid_to_name,
1330 : .rids_to_names = sam_rids_to_names,
1331 : .lookup_usergroups = sam_lookup_usergroups,
1332 : .lookup_useraliases = sam_lookup_useraliases,
1333 : .lookup_groupmem = sam_lookup_groupmem,
1334 : .lockout_policy = sam_lockout_policy,
1335 : .password_policy = sam_password_policy,
1336 : .trusted_domains = builtin_trusted_domains
1337 : };
1338 :
1339 : /* the rpc backend methods are exposed via this structure */
1340 : struct winbindd_methods sam_passdb_methods = {
1341 : .consistent = false,
1342 :
1343 : .query_user_list = sam_query_user_list,
1344 : .enum_dom_groups = sam_enum_dom_groups,
1345 : .enum_local_groups = sam_enum_local_groups,
1346 : .name_to_sid = sam_name_to_sid,
1347 : .sid_to_name = sam_sid_to_name,
1348 : .rids_to_names = sam_rids_to_names,
1349 : .lookup_usergroups = sam_lookup_usergroups,
1350 : .lookup_useraliases = sam_lookup_useraliases,
1351 : .lookup_groupmem = sam_lookup_groupmem,
1352 : .lockout_policy = sam_lockout_policy,
1353 : .password_policy = sam_password_policy,
1354 : .trusted_domains = sam_trusted_domains
1355 : };
|