sync'ing up for 3.0alpha20 release
[Samba.git] / source / nsswitch / winbindd_rpc.c
blob047280e21e48bc2c31a1c7a77dc4ea19e6192401
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind rpc backend functions
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) Andrew Tridgell 2001
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "winbindd.h"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
29 /* Query display info for a domain. This returns enough information plus a
30 bit extra to give an overview of domain users for the User Manager
31 application. */
32 static NTSTATUS query_user_list(struct winbindd_domain *domain,
33 TALLOC_CTX *mem_ctx,
34 uint32 *num_entries,
35 WINBIND_USERINFO **info)
37 CLI_POLICY_HND *hnd;
38 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
39 POLICY_HND dom_pol;
40 BOOL got_dom_pol = False;
41 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
42 int i;
44 DEBUG(3,("rpc: query_user_list\n"));
46 *num_entries = 0;
47 *info = NULL;
49 /* Get sam handle */
51 if (!(hnd = cm_get_sam_handle(domain->name)))
52 goto done;
54 /* Get domain handle */
56 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
57 des_access, &domain->sid, &dom_pol);
59 if (!NT_STATUS_IS_OK(result))
60 goto done;
62 got_dom_pol = True;
64 i = 0;
65 do {
66 SAM_DISPINFO_CTR ctr;
67 SAM_DISPINFO_1 info1;
68 uint32 count = 0, start=i;
69 int j;
70 TALLOC_CTX *ctx2;
72 ctr.sam.info1 = &info1;
74 ctx2 = talloc_init_named("winbindd dispinfo");
75 if (!ctx2) {
76 result = NT_STATUS_NO_MEMORY;
77 goto done;
80 /* Query display info level 1 */
81 result = cli_samr_query_dispinfo(hnd->cli, ctx2,
82 &dom_pol, &start, 1,
83 &count, 0xFFFF, &ctr);
85 if (!NT_STATUS_IS_OK(result) &&
86 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
88 (*num_entries) += count;
90 /* now map the result into the WINBIND_USERINFO structure */
91 (*info) = talloc_realloc(mem_ctx, *info,
92 (*num_entries)*sizeof(WINBIND_USERINFO));
93 if (!(*info)) {
94 result = NT_STATUS_NO_MEMORY;
95 talloc_destroy(ctx2);
96 goto done;
99 for (j=0;j<count;i++, j++) {
100 (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
101 (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
102 (*info)[i].user_rid = info1.sam[j].rid_user;
103 /* For the moment we set the primary group for
104 every user to be the Domain Users group.
105 There are serious problems with determining
106 the actual primary group for large domains.
107 This should really be made into a 'winbind
108 force group' smb.conf parameter or
109 something like that. */
110 (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
113 talloc_destroy(ctx2);
114 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
116 done:
118 if (got_dom_pol)
119 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
121 return result;
124 /* list all domain groups */
125 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
126 TALLOC_CTX *mem_ctx,
127 uint32 *num_entries,
128 struct acct_info **info)
130 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
131 CLI_POLICY_HND *hnd;
132 POLICY_HND dom_pol;
133 NTSTATUS status;
135 *num_entries = 0;
136 *info = NULL;
138 DEBUG(3,("rpc: enum_dom_groups\n"));
140 if (!(hnd = cm_get_sam_handle(domain->name))) {
141 return NT_STATUS_UNSUCCESSFUL;
144 status = cli_samr_open_domain(hnd->cli, mem_ctx,
145 &hnd->pol, des_access, &domain->sid, &dom_pol);
146 if (!NT_STATUS_IS_OK(status)) {
147 return status;
150 do {
151 struct acct_info *info2 = NULL;
152 uint32 count = 0, start = *num_entries;
153 TALLOC_CTX *mem_ctx2;
155 mem_ctx2 = talloc_init_named("enum_dom_groups[rpc]");
157 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
158 &start,
159 0xFFFF, /* buffer size? */
160 &info2, &count);
162 if (!NT_STATUS_IS_OK(status) &&
163 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
164 talloc_destroy(mem_ctx2);
165 break;
168 (*info) = talloc_realloc(mem_ctx, *info,
169 sizeof(**info) * ((*num_entries) + count));
170 if (! *info) {
171 talloc_destroy(mem_ctx2);
172 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
173 return NT_STATUS_NO_MEMORY;
176 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
177 (*num_entries) += count;
178 talloc_destroy(mem_ctx2);
179 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
181 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
183 return status;
186 /* convert a single name to a sid in a domain */
187 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
188 const char *name,
189 DOM_SID *sid,
190 enum SID_NAME_USE *type)
192 TALLOC_CTX *mem_ctx;
193 CLI_POLICY_HND *hnd;
194 NTSTATUS status;
195 DOM_SID *sids = NULL;
196 uint32 *types = NULL;
197 const char *full_name;
199 DEBUG(3,("rpc: name_to_sid name=%s\n", name));
201 if (!(mem_ctx = talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
202 DEBUG(0, ("talloc_init failed!\n"));
203 return NT_STATUS_NO_MEMORY;
206 if (!(hnd = cm_get_lsa_handle(domain->name))) {
207 talloc_destroy(mem_ctx);
208 return NT_STATUS_UNSUCCESSFUL;
211 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
213 if (!full_name) {
214 DEBUG(0, ("talloc_asprintf failed!\n"));
215 talloc_destroy(mem_ctx);
216 return NT_STATUS_NO_MEMORY;
219 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
220 &full_name, &sids, &types);
222 /* Return rid and type if lookup successful */
224 if (NT_STATUS_IS_OK(status)) {
225 sid_copy(sid, &sids[0]);
226 *type = types[0];
229 talloc_destroy(mem_ctx);
230 return status;
234 convert a domain SID to a user or group name
236 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
237 TALLOC_CTX *mem_ctx,
238 DOM_SID *sid,
239 char **name,
240 enum SID_NAME_USE *type)
242 CLI_POLICY_HND *hnd;
243 char **domains;
244 char **names;
245 uint32 *types;
246 NTSTATUS status;
248 DEBUG(3,("rpc: sid_to_name\n"));
250 if (!(hnd = cm_get_lsa_handle(domain->name)))
251 return NT_STATUS_UNSUCCESSFUL;
253 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
254 1, sid, &domains, &names, &types);
256 if (NT_STATUS_IS_OK(status)) {
257 *type = types[0];
258 *name = names[0];
259 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
261 /* Paranoia */
262 if (strcasecmp(domain->name, domains[0]) != 0) {
263 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
264 return NT_STATUS_UNSUCCESSFUL;
267 return status;
270 /* Lookup user information from a rid or username. */
271 static NTSTATUS query_user(struct winbindd_domain *domain,
272 TALLOC_CTX *mem_ctx,
273 uint32 user_rid,
274 WINBIND_USERINFO *user_info)
276 CLI_POLICY_HND *hnd;
277 NTSTATUS result;
278 POLICY_HND dom_pol, user_pol;
279 BOOL got_dom_pol = False, got_user_pol = False;
280 SAM_USERINFO_CTR *ctr;
282 DEBUG(3,("rpc: query_user rid=%u\n", user_rid));
284 /* Get sam handle */
285 if (!(hnd = cm_get_sam_handle(domain->name)))
286 goto done;
288 /* Get domain handle */
290 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
291 SEC_RIGHTS_MAXIMUM_ALLOWED,
292 &domain->sid, &dom_pol);
294 if (!NT_STATUS_IS_OK(result))
295 goto done;
297 got_dom_pol = True;
299 /* Get user handle */
300 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
301 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
303 if (!NT_STATUS_IS_OK(result))
304 goto done;
306 got_user_pol = True;
308 /* Get user info */
309 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
310 0x15, &ctr);
312 if (!NT_STATUS_IS_OK(result))
313 goto done;
315 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
316 got_user_pol = False;
318 user_info->user_rid = user_rid;
319 user_info->group_rid = ctr->info.id21->group_rid;
320 user_info->acct_name = unistr2_tdup(mem_ctx,
321 &ctr->info.id21->uni_user_name);
322 user_info->full_name = unistr2_tdup(mem_ctx,
323 &ctr->info.id21->uni_full_name);
325 done:
326 /* Clean up policy handles */
327 if (got_user_pol)
328 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
330 if (got_dom_pol)
331 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
333 return result;
336 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
337 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
338 TALLOC_CTX *mem_ctx,
339 uint32 user_rid,
340 uint32 *num_groups, uint32 **user_gids)
342 CLI_POLICY_HND *hnd;
343 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
344 POLICY_HND dom_pol, user_pol;
345 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
346 BOOL got_dom_pol = False, got_user_pol = False;
347 DOM_GID *user_groups;
348 int i;
350 DEBUG(3,("rpc: lookup_usergroups rid=%u\n", user_rid));
352 *num_groups = 0;
354 /* First try cached universal groups from logon */
355 *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
356 if((*num_groups > 0) && *user_gids) {
357 return NT_STATUS_OK;
358 } else {
359 *user_gids = NULL;
360 *num_groups = 0;
363 /* Get sam handle */
364 if (!(hnd = cm_get_sam_handle(domain->name)))
365 goto done;
367 /* Get domain handle */
368 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
369 des_access, &domain->sid, &dom_pol);
371 if (!NT_STATUS_IS_OK(result))
372 goto done;
374 got_dom_pol = True;
376 /* Get user handle */
377 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
378 des_access, user_rid, &user_pol);
380 if (!NT_STATUS_IS_OK(result))
381 goto done;
383 got_user_pol = True;
385 /* Query user rids */
386 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
387 num_groups, &user_groups);
389 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
390 goto done;
392 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
393 for (i=0;i<(*num_groups);i++) {
394 (*user_gids)[i] = user_groups[i].g_rid;
397 done:
398 /* Clean up policy handles */
399 if (got_user_pol)
400 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
402 if (got_dom_pol)
403 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
405 return result;
409 /* Lookup group membership given a rid. */
410 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
411 TALLOC_CTX *mem_ctx,
412 uint32 group_rid, uint32 *num_names,
413 uint32 **rid_mem, char ***names,
414 uint32 **name_types)
416 CLI_POLICY_HND *hnd;
417 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
418 uint32 i, total_names = 0;
419 POLICY_HND dom_pol, group_pol;
420 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
421 BOOL got_dom_pol = False, got_group_pol = False;
423 DEBUG(10,("rpc: lookup_groupmem %s rid=%u\n", domain->name, group_rid));
425 *num_names = 0;
427 /* Get sam handle */
429 if (!(hnd = cm_get_sam_handle(domain->name)))
430 goto done;
432 /* Get domain handle */
434 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
435 des_access, &domain->sid, &dom_pol);
437 if (!NT_STATUS_IS_OK(result))
438 goto done;
440 got_dom_pol = True;
442 /* Get group handle */
444 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
445 des_access, group_rid, &group_pol);
447 if (!NT_STATUS_IS_OK(result))
448 goto done;
450 got_group_pol = True;
452 /* Step #1: Get a list of user rids that are the members of the
453 group. */
455 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
456 &group_pol, num_names, rid_mem,
457 name_types);
459 if (!NT_STATUS_IS_OK(result))
460 goto done;
462 /* Step #2: Convert list of rids into list of usernames. Do this
463 in bunches of ~1000 to avoid crashing NT4. It looks like there
464 is a buffer overflow or something like that lurking around
465 somewhere. */
467 #define MAX_LOOKUP_RIDS 900
469 *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
470 *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
472 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
473 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
474 uint32 tmp_num_names = 0;
475 char **tmp_names = NULL;
476 uint32 *tmp_types = NULL;
478 /* Lookup a chunk of rids */
480 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
481 &dom_pol, 1000, /* flags */
482 num_lookup_rids,
483 &(*rid_mem)[i],
484 &tmp_num_names,
485 &tmp_names, &tmp_types);
487 if (!NT_STATUS_IS_OK(result))
488 goto done;
490 /* Copy result into array. The talloc system will take
491 care of freeing the temporary arrays later on. */
493 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
494 tmp_num_names);
496 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
497 tmp_num_names);
499 total_names += tmp_num_names;
502 *num_names = total_names;
504 done:
505 if (got_group_pol)
506 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
508 if (got_dom_pol)
509 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
511 return result;
514 /* find the sequence number for a domain */
515 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
517 TALLOC_CTX *mem_ctx;
518 CLI_POLICY_HND *hnd;
519 SAM_UNK_CTR ctr;
520 uint16 switch_value = 2;
521 NTSTATUS result;
522 uint32 seqnum = DOM_SEQUENCE_NONE;
523 POLICY_HND dom_pol;
524 BOOL got_dom_pol = False;
525 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
527 DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
529 *seq = DOM_SEQUENCE_NONE;
531 if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
532 return NT_STATUS_NO_MEMORY;
534 /* Get sam handle */
536 if (!(hnd = cm_get_sam_handle(domain->name)))
537 goto done;
539 /* Get domain handle */
541 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
542 des_access, &domain->sid, &dom_pol);
544 if (!NT_STATUS_IS_OK(result))
545 goto done;
547 got_dom_pol = True;
549 /* Query domain info */
551 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
552 switch_value, &ctr);
554 if (NT_STATUS_IS_OK(result)) {
555 seqnum = ctr.info.inf2.seq_num;
556 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
557 } else {
558 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
559 (unsigned)seqnum, domain->name ));
562 done:
564 if (got_dom_pol)
565 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
567 talloc_destroy(mem_ctx);
569 *seq = seqnum;
571 return result;
574 /* get a list of trusted domains */
575 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
576 TALLOC_CTX *mem_ctx,
577 uint32 *num_domains,
578 char ***names,
579 char ***alt_names,
580 DOM_SID **dom_sids)
582 CLI_POLICY_HND *hnd;
583 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
584 uint32 enum_ctx = 0;
586 DEBUG(3,("rpc: trusted_domains\n"));
588 *num_domains = 0;
589 *alt_names = NULL;
591 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
592 goto done;
594 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
595 &hnd->pol, &enum_ctx,
596 num_domains, names, dom_sids);
597 done:
598 return result;
601 /* find the domain sid for a domain */
602 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
604 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
605 TALLOC_CTX *mem_ctx;
606 CLI_POLICY_HND *hnd;
607 fstring level5_dom;
609 DEBUG(3,("rpc: domain_sid\n"));
611 if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
612 return NT_STATUS_NO_MEMORY;
614 /* Get sam handle */
615 if (!(hnd = cm_get_lsa_handle(domain->name)))
616 goto done;
618 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
619 &hnd->pol, 0x05, level5_dom, sid);
621 done:
622 talloc_destroy(mem_ctx);
623 return status;
626 /* find alternate names list for the domain - none for rpc */
627 static NTSTATUS alternate_name(struct winbindd_domain *domain)
629 return NT_STATUS_OK;
633 /* the rpc backend methods are exposed via this structure */
634 struct winbindd_methods msrpc_methods = {
635 False,
636 query_user_list,
637 enum_dom_groups,
638 name_to_sid,
639 sid_to_name,
640 query_user,
641 lookup_usergroups,
642 lookup_groupmem,
643 sequence_number,
644 trusted_domains,
645 domain_sid,
646 alternate_name