if we are adding a new sambaAccount, make sure that we add a
[Samba.git] / source / nsswitch / winbindd_rpc.c
blobedf445a0ec9191a7fdcfef923318d3e02d7b07f3
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 /*******************************************************************
27 Duplicate a UNISTR2 string into a UNIX codepage null terminated char*
28 using a talloc context
29 ********************************************************************/
31 static char *unistr2_tdup(TALLOC_CTX *ctx, const UNISTR2 *str)
33 char *s;
34 int maxlen = (str->uni_str_len+1)*4;
35 if (!str->buffer)
36 return NULL;
37 s = (char *)talloc(ctx, maxlen); /* convervative */
38 if (!s)
39 return NULL;
40 unistr2_to_unix(s, str, maxlen);
41 return s;
44 /* Query display info for a domain. This returns enough information plus a
45 bit extra to give an overview of domain users for the User Manager
46 application. */
47 static NTSTATUS query_user_list(struct winbindd_domain *domain,
48 TALLOC_CTX *mem_ctx,
49 uint32 *num_entries,
50 WINBIND_USERINFO **info)
52 CLI_POLICY_HND *hnd;
53 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
54 POLICY_HND dom_pol;
55 BOOL got_dom_pol = False;
56 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
57 int i;
59 *num_entries = 0;
60 *info = NULL;
62 /* Get sam handle */
64 if (!(hnd = cm_get_sam_handle(domain->name)))
65 goto done;
67 /* Get domain handle */
69 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
70 des_access, &domain->sid, &dom_pol);
72 if (!NT_STATUS_IS_OK(result))
73 goto done;
75 got_dom_pol = True;
77 i = 0;
78 do {
79 SAM_DISPINFO_CTR ctr;
80 SAM_DISPINFO_1 info1;
81 uint32 count = 0, start=i;
82 int j;
83 TALLOC_CTX *ctx2;
85 ctr.sam.info1 = &info1;
87 ctx2 = talloc_init_named("winbindd dispinfo");
88 if (!ctx2) {
89 result = NT_STATUS_NO_MEMORY;
90 goto done;
93 /* Query display info level 1 */
94 result = cli_samr_query_dispinfo(hnd->cli, ctx2,
95 &dom_pol, &start, 1,
96 &count, 0xFFFF, &ctr);
98 if (!NT_STATUS_IS_OK(result) &&
99 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
101 (*num_entries) += count;
103 /* now map the result into the WINBIND_USERINFO structure */
104 (*info) = talloc_realloc(mem_ctx, *info,
105 (*num_entries)*sizeof(WINBIND_USERINFO));
106 if (!(*info)) {
107 result = NT_STATUS_NO_MEMORY;
108 talloc_destroy(ctx2);
109 goto done;
112 for (j=0;j<count;i++, j++) {
113 /* unistr2_tdup converts to UNIX charset. */
114 (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
115 (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
116 (*info)[i].user_rid = info1.sam[j].rid_user;
117 /* For the moment we set the primary group for
118 every user to be the Domain Users group.
119 There are serious problems with determining
120 the actual primary group for large domains.
121 This should really be made into a 'winbind
122 force group' smb.conf parameter or
123 something like that. */
124 (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
127 talloc_destroy(ctx2);
128 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
130 done:
132 if (got_dom_pol)
133 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
135 return result;
138 /* list all domain groups */
139 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
140 TALLOC_CTX *mem_ctx,
141 uint32 *num_entries,
142 struct acct_info **info)
144 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
145 CLI_POLICY_HND *hnd;
146 POLICY_HND dom_pol;
147 NTSTATUS status;
149 *num_entries = 0;
150 *info = NULL;
152 if (!(hnd = cm_get_sam_handle(domain->name))) {
153 return NT_STATUS_UNSUCCESSFUL;
156 status = cli_samr_open_domain(hnd->cli, mem_ctx,
157 &hnd->pol, des_access, &domain->sid, &dom_pol);
158 if (!NT_STATUS_IS_OK(status)) {
159 return status;
162 do {
163 struct acct_info *info2 = NULL;
164 uint32 count = 0, start = *num_entries;
165 TALLOC_CTX *mem_ctx2;
167 mem_ctx2 = talloc_init_named("enum_dom_groups[rpc]");
169 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
170 &start,
171 0xFFFF, /* buffer size? */
172 &info2, &count);
174 if (!NT_STATUS_IS_OK(status) &&
175 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
176 talloc_destroy(mem_ctx2);
177 break;
180 (*info) = talloc_realloc(mem_ctx, *info,
181 sizeof(**info) * ((*num_entries) + count));
182 if (! *info) {
183 talloc_destroy(mem_ctx2);
184 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
185 return NT_STATUS_NO_MEMORY;
188 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
189 (*num_entries) += count;
190 talloc_destroy(mem_ctx2);
191 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
193 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
195 return status;
198 /* convert a single name to a sid in a domain */
199 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
200 const char *name,
201 DOM_SID *sid,
202 enum SID_NAME_USE *type)
204 TALLOC_CTX *mem_ctx;
205 CLI_POLICY_HND *hnd;
206 NTSTATUS status;
207 DOM_SID *sids = NULL;
208 uint32 *types = NULL;
209 const char *full_name;
211 if (!(mem_ctx = talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
212 DEBUG(0, ("talloc_init failed!\n"));
213 return NT_STATUS_NO_MEMORY;
216 if (!(hnd = cm_get_lsa_handle(domain->name))) {
217 talloc_destroy(mem_ctx);
218 return NT_STATUS_UNSUCCESSFUL;
221 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
223 if (!full_name) {
224 DEBUG(0, ("talloc_asprintf failed!\n"));
225 talloc_destroy(mem_ctx);
226 return NT_STATUS_NO_MEMORY;
229 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
230 &full_name, &sids, &types);
232 /* Return rid and type if lookup successful */
234 if (NT_STATUS_IS_OK(status)) {
235 sid_copy(sid, &sids[0]);
236 *type = types[0];
239 talloc_destroy(mem_ctx);
240 return status;
244 convert a domain SID to a user or group name
246 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
247 TALLOC_CTX *mem_ctx,
248 DOM_SID *sid,
249 char **name,
250 enum SID_NAME_USE *type)
252 CLI_POLICY_HND *hnd;
253 char **domains;
254 char **names;
255 uint32 *types;
256 NTSTATUS status;
258 if (!(hnd = cm_get_lsa_handle(domain->name)))
259 return NT_STATUS_UNSUCCESSFUL;
261 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
262 1, sid, &domains, &names, &types);
264 if (NT_STATUS_IS_OK(status)) {
265 *type = types[0];
266 *name = names[0];
267 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
269 /* Paranoia */
270 if (strcasecmp(domain->name, domains[0]) != 0) {
271 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
272 return NT_STATUS_UNSUCCESSFUL;
275 return status;
278 /* Lookup user information from a rid or username. */
279 static NTSTATUS query_user(struct winbindd_domain *domain,
280 TALLOC_CTX *mem_ctx,
281 uint32 user_rid,
282 WINBIND_USERINFO *user_info)
284 CLI_POLICY_HND *hnd;
285 NTSTATUS result;
286 POLICY_HND dom_pol, user_pol;
287 BOOL got_dom_pol = False, got_user_pol = False;
288 SAM_USERINFO_CTR *ctr;
290 /* Get sam handle */
291 if (!(hnd = cm_get_sam_handle(domain->name)))
292 goto done;
294 /* Get domain handle */
296 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
297 SEC_RIGHTS_MAXIMUM_ALLOWED,
298 &domain->sid, &dom_pol);
300 if (!NT_STATUS_IS_OK(result))
301 goto done;
303 got_dom_pol = True;
305 /* Get user handle */
306 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
307 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
309 if (!NT_STATUS_IS_OK(result))
310 goto done;
312 got_user_pol = True;
314 /* Get user info */
315 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
316 0x15, &ctr);
318 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
319 got_user_pol = False;
321 user_info->group_rid = ctr->info.id21->group_rid;
322 user_info->acct_name = unistr2_tdup(mem_ctx,
323 &ctr->info.id21->uni_user_name);
324 user_info->full_name = unistr2_tdup(mem_ctx,
325 &ctr->info.id21->uni_full_name);
327 done:
328 /* Clean up policy handles */
329 if (got_user_pol)
330 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
332 if (got_dom_pol)
333 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
335 return result;
338 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
339 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
340 TALLOC_CTX *mem_ctx,
341 uint32 user_rid,
342 uint32 *num_groups, uint32 **user_gids)
344 CLI_POLICY_HND *hnd;
345 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
346 POLICY_HND dom_pol, user_pol;
347 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
348 BOOL got_dom_pol = False, got_user_pol = False;
349 DOM_GID *user_groups;
350 int i;
352 *num_groups = 0;
353 *user_gids = NULL;
355 /* Get sam handle */
356 if (!(hnd = cm_get_sam_handle(domain->name)))
357 goto done;
359 /* Get domain handle */
360 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
361 des_access, &domain->sid, &dom_pol);
363 if (!NT_STATUS_IS_OK(result))
364 goto done;
366 got_dom_pol = True;
368 /* Get user handle */
369 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
370 des_access, user_rid, &user_pol);
372 if (!NT_STATUS_IS_OK(result))
373 goto done;
375 got_user_pol = True;
377 /* Query user rids */
378 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
379 num_groups, &user_groups);
381 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
382 goto done;
384 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
385 for (i=0;i<(*num_groups);i++) {
386 (*user_gids)[i] = user_groups[i].g_rid;
389 done:
390 /* Clean up policy handles */
391 if (got_user_pol)
392 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
394 if (got_dom_pol)
395 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
397 return result;
401 /* Lookup group membership given a rid. */
402 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
403 TALLOC_CTX *mem_ctx,
404 uint32 group_rid, uint32 *num_names,
405 uint32 **rid_mem, char ***names,
406 uint32 **name_types)
408 CLI_POLICY_HND *hnd;
409 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
410 uint32 i, total_names = 0;
411 POLICY_HND dom_pol, group_pol;
412 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
413 BOOL got_dom_pol = False, got_group_pol = False;
415 *num_names = 0;
417 /* Get sam handle */
419 if (!(hnd = cm_get_sam_handle(domain->name)))
420 goto done;
422 /* Get domain handle */
424 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
425 des_access, &domain->sid, &dom_pol);
427 if (!NT_STATUS_IS_OK(result))
428 goto done;
430 got_dom_pol = True;
432 /* Get group handle */
434 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
435 des_access, group_rid, &group_pol);
437 if (!NT_STATUS_IS_OK(result))
438 goto done;
440 got_group_pol = True;
442 /* Step #1: Get a list of user rids that are the members of the
443 group. */
445 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
446 &group_pol, num_names, rid_mem,
447 name_types);
449 if (!NT_STATUS_IS_OK(result))
450 goto done;
452 /* Step #2: Convert list of rids into list of usernames. Do this
453 in bunches of ~1000 to avoid crashing NT4. It looks like there
454 is a buffer overflow or something like that lurking around
455 somewhere. */
457 #define MAX_LOOKUP_RIDS 900
459 *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
460 *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
462 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
463 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
464 uint32 tmp_num_names = 0;
465 char **tmp_names = NULL;
466 uint32 *tmp_types = NULL;
468 /* Lookup a chunk of rids */
470 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
471 &dom_pol, 1000, /* flags */
472 num_lookup_rids,
473 &(*rid_mem)[i],
474 &tmp_num_names,
475 &tmp_names, &tmp_types);
477 if (!NT_STATUS_IS_OK(result))
478 goto done;
480 /* Copy result into array. The talloc system will take
481 care of freeing the temporary arrays later on. */
483 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
484 tmp_num_names);
486 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
487 tmp_num_names);
489 total_names += tmp_num_names;
492 *num_names = total_names;
494 done:
495 if (got_group_pol)
496 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
498 if (got_dom_pol)
499 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
501 return result;
504 /* find the sequence number for a domain */
505 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
507 TALLOC_CTX *mem_ctx;
508 CLI_POLICY_HND *hnd;
509 SAM_UNK_CTR ctr;
510 uint16 switch_value = 2;
511 NTSTATUS result;
512 uint32 seqnum = DOM_SEQUENCE_NONE;
513 POLICY_HND dom_pol;
514 BOOL got_dom_pol = False;
515 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
517 *seq = DOM_SEQUENCE_NONE;
519 if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
520 return NT_STATUS_NO_MEMORY;
522 /* Get sam handle */
524 if (!(hnd = cm_get_sam_handle(domain->name)))
525 goto done;
527 /* Get domain handle */
529 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
530 des_access, &domain->sid, &dom_pol);
532 if (!NT_STATUS_IS_OK(result))
533 goto done;
535 got_dom_pol = True;
537 /* Query domain info */
539 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
540 switch_value, &ctr);
542 if (NT_STATUS_IS_OK(result)) {
543 seqnum = ctr.info.inf2.seq_num;
544 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
545 } else {
546 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
547 (unsigned)seqnum, domain->name ));
550 done:
552 if (got_dom_pol)
553 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
555 talloc_destroy(mem_ctx);
557 *seq = seqnum;
559 return result;
562 /* get a list of trusted domains */
563 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
564 TALLOC_CTX *mem_ctx,
565 uint32 *num_domains,
566 char ***names,
567 DOM_SID **dom_sids)
569 CLI_POLICY_HND *hnd;
570 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
571 uint32 enum_ctx = 0;
573 *num_domains = 0;
575 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
576 goto done;
578 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
579 &hnd->pol, &enum_ctx, num_domains,
580 names, dom_sids);
581 done:
582 return result;
585 /* find the domain sid for a domain */
586 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
588 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
589 TALLOC_CTX *mem_ctx;
590 CLI_POLICY_HND *hnd;
591 fstring level5_dom;
593 if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
594 return NT_STATUS_NO_MEMORY;
596 /* Get sam handle */
597 if (!(hnd = cm_get_lsa_handle(domain->name)))
598 goto done;
600 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
601 &hnd->pol, 0x05, level5_dom, sid);
603 done:
604 talloc_destroy(mem_ctx);
605 return status;
608 /* the rpc backend methods are exposed via this structure */
609 struct winbindd_methods msrpc_methods = {
610 False,
611 query_user_list,
612 enum_dom_groups,
613 name_to_sid,
614 sid_to_name,
615 query_user,
616 lookup_usergroups,
617 lookup_groupmem,
618 sequence_number,
619 trusted_domains,
620 domain_sid