source: branches/samba-3.2.x/source/winbindd/winbindd_group.c

Last change on this file was 228, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.6

File size: 43.8 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind daemon for ntdom nss module
5
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
8 Copyright (C) Gerald (Jerry) Carter 2003.
9 Copyright (C) Volker Lendecke 2005
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "includes.h"
26#include "winbindd.h"
27
28extern bool opt_nocache;
29
30#undef DBGC_CLASS
31#define DBGC_CLASS DBGC_WINBIND
32
33static void add_member(const char *domain, const char *user,
34 char **pp_members, size_t *p_num_members)
35{
36 fstring name;
37
38 if (domain != NULL) {
39 fill_domain_username(name, domain, user, True);
40 } else {
41 fstrcpy(name, user);
42 }
43 safe_strcat(name, ",", sizeof(name)-1);
44 string_append(pp_members, name);
45 *p_num_members += 1;
46}
47
48/**********************************************************************
49 Add member users resulting from sid. Expand if it is a domain group.
50**********************************************************************/
51
52static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
53{
54 DOM_SID dom_sid;
55 uint32 rid;
56 struct winbindd_domain *domain;
57 size_t i;
58
59 char *domain_name = NULL;
60 char *name = NULL;
61 enum lsa_SidType type;
62
63 uint32 num_names;
64 DOM_SID *sid_mem;
65 char **names;
66 uint32 *types;
67
68 NTSTATUS result;
69
70 TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
71
72 if (mem_ctx == NULL) {
73 DEBUG(1, ("talloc_init failed\n"));
74 return;
75 }
76
77 sid_copy(&dom_sid, sid);
78 sid_split_rid(&dom_sid, &rid);
79
80 domain = find_lookup_domain_from_sid(sid);
81
82 if (domain == NULL) {
83 DEBUG(3, ("Could not find domain for sid %s\n",
84 sid_string_dbg(sid)));
85 goto done;
86 }
87
88 result = domain->methods->sid_to_name(domain, mem_ctx, sid,
89 &domain_name, &name, &type);
90
91 if (!NT_STATUS_IS_OK(result)) {
92 DEBUG(3, ("sid_to_name failed for sid %s\n",
93 sid_string_dbg(sid)));
94 goto done;
95 }
96
97 DEBUG(10, ("Found name %s, type %d\n", name, type));
98
99 if (type == SID_NAME_USER) {
100 add_member(domain_name, name, pp_members, p_num_members);
101 goto done;
102 }
103
104 if (type != SID_NAME_DOM_GRP) {
105 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
106 name));
107 goto done;
108 }
109
110 /* Expand the domain group, this must be done via the target domain */
111
112 domain = find_domain_from_sid(sid);
113
114 if (domain == NULL) {
115 DEBUG(3, ("Could not find domain from SID %s\n",
116 sid_string_dbg(sid)));
117 goto done;
118 }
119
120 result = domain->methods->lookup_groupmem(domain, mem_ctx,
121 sid, &num_names,
122 &sid_mem, &names,
123 &types);
124
125 if (!NT_STATUS_IS_OK(result)) {
126 DEBUG(10, ("Could not lookup group members for %s: %s\n",
127 name, nt_errstr(result)));
128 goto done;
129 }
130
131 for (i=0; i<num_names; i++) {
132 DEBUG(10, ("Adding group member SID %s\n",
133 sid_string_dbg(&sid_mem[i])));
134
135 if (types[i] != SID_NAME_USER) {
136 DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
137 "Ignoring.\n", names[i], name));
138 continue;
139 }
140
141 add_member(NULL, names[i], pp_members, p_num_members);
142 }
143
144 done:
145 talloc_destroy(mem_ctx);
146 return;
147}
148
149static bool fill_passdb_alias_grmem(struct winbindd_domain *domain,
150 DOM_SID *group_sid,
151 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
152{
153 DOM_SID *members;
154 size_t i, num_members;
155
156 *num_gr_mem = 0;
157 *gr_mem = NULL;
158 *gr_mem_len = 0;
159
160 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
161 &num_members)))
162 return True;
163
164 for (i=0; i<num_members; i++) {
165 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
166 }
167
168 TALLOC_FREE(members);
169
170 if (*gr_mem != NULL) {
171 size_t len;
172
173 /* We have at least one member, strip off the last "," */
174 len = strlen(*gr_mem);
175 (*gr_mem)[len-1] = '\0';
176 *gr_mem_len = len;
177 }
178
179 return True;
180}
181
182/* Fill a grent structure from various other information */
183
184static bool fill_grent(struct winbindd_gr *gr, const char *dom_name,
185 const char *gr_name, gid_t unix_gid)
186{
187 fstring full_group_name;
188
189 fill_domain_username( full_group_name, dom_name, gr_name, True );
190
191 gr->gr_gid = unix_gid;
192
193 /* Group name and password */
194
195 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
196 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
197
198 return True;
199}
200
201/***********************************************************************
202 If "enum users" is set to false, and the group being looked
203 up is the Domain Users SID: S-1-5-domain-513, then for the
204 list of members check if the querying user is in that group,
205 and if so only return that user as the gr_mem array.
206 We can change this to a different parameter than "enum users"
207 if neccessaey, or parameterize the group list we do this for.
208***********************************************************************/
209
210static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
211 struct winbindd_domain *domain,
212 struct winbindd_cli_state *state,
213 DOM_SID *group_sid,
214 enum lsa_SidType group_name_type,
215 size_t *num_gr_mem, char **gr_mem,
216 size_t *gr_mem_len)
217{
218 DOM_SID querying_user_sid;
219 DOM_SID *pquerying_user_sid = NULL;
220 uint32 num_groups = 0;
221 DOM_SID *user_sids = NULL;
222 bool u_in_group = False;
223 NTSTATUS status;
224 int i;
225 unsigned int buf_len = 0;
226 char *buf = NULL;
227
228 DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
229 domain->name ));
230
231 if (state) {
232 uid_t ret_uid = (uid_t)-1;
233 if (sys_getpeereid(state->sock, &ret_uid)==0) {
234 /* We know who's asking - look up their SID if
235 it's one we've mapped before. */
236 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
237 if (NT_STATUS_IS_OK(status)) {
238 pquerying_user_sid = &querying_user_sid;
239 DEBUG(10,("fill_grent_mem_domain_users: querying uid %u -> %s\n",
240 (unsigned int)ret_uid,
241 sid_string_dbg(pquerying_user_sid)));
242 }
243 }
244 }
245
246 /* Only look up if it was a winbindd user in this domain. */
247 if (pquerying_user_sid &&
248 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
249
250 DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
251 sid_string_dbg(pquerying_user_sid) ));
252
253 status = domain->methods->lookup_usergroups(domain,
254 mem_ctx,
255 pquerying_user_sid,
256 &num_groups,
257 &user_sids);
258 if (!NT_STATUS_IS_OK(status)) {
259 DEBUG(1, ("fill_grent_mem_domain_users: lookup_usergroups failed "
260 "for sid %s in domain %s (error: %s)\n",
261 sid_string_dbg(pquerying_user_sid),
262 domain->name,
263 nt_errstr(status)));
264 return False;
265 }
266
267 for (i = 0; i < num_groups; i++) {
268 if (sid_equal(group_sid, &user_sids[i])) {
269 /* User is in Domain Users, add their name
270 as the only group member. */
271 u_in_group = True;
272 break;
273 }
274 }
275 }
276
277 if (u_in_group) {
278 size_t len = 0;
279 char *domainname = NULL;
280 char *username = NULL;
281 fstring name;
282 enum lsa_SidType type;
283
284 DEBUG(10,("fill_grent_mem_domain_users: sid %s in 'Domain Users' in domain %s\n",
285 sid_string_dbg(pquerying_user_sid),
286 domain->name ));
287
288 status = domain->methods->sid_to_name(domain, mem_ctx,
289 pquerying_user_sid,
290 &domainname,
291 &username,
292 &type);
293 if (!NT_STATUS_IS_OK(status)) {
294 DEBUG(1, ("could not lookup username for user "
295 "sid %s in domain %s (error: %s)\n",
296 sid_string_dbg(pquerying_user_sid),
297 domain->name,
298 nt_errstr(status)));
299 return False;
300 }
301 fill_domain_username(name, domain->name, username, True);
302 len = strlen(name);
303 buf_len = len + 1;
304 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
305 DEBUG(1, ("out of memory\n"));
306 return False;
307 }
308 memcpy(buf, name, buf_len);
309
310 DEBUG(10,("fill_grent_mem_domain_users: user %s in "
311 "'Domain Users' in domain %s\n",
312 name, domain->name ));
313
314 /* user is the only member */
315 *num_gr_mem = 1;
316 }
317
318 *gr_mem = buf;
319 *gr_mem_len = buf_len;
320
321 DEBUG(10, ("fill_grent_mem_domain_users: num_mem = %u, len = %u, mem = %s\n",
322 (unsigned int)*num_gr_mem,
323 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
324
325 return True;
326}
327
328/***********************************************************************
329 Add names to a list. Assumes a canonical version of the string
330 in DOMAIN\user
331***********************************************************************/
332
333static int namecmp( const void *a, const void *b )
334{
335 return StrCaseCmp( * (char * const *) a, * (char * const *) b);
336}
337
338static void sort_unique_list(char ***list, uint32 *n_list)
339{
340 uint32_t i;
341
342 /* search for duplicates for sorting and looking for matching
343 neighbors */
344
345 qsort(*list, *n_list, sizeof(char*), QSORT_CAST namecmp);
346
347 for (i=1; i < *n_list; i++) {
348 if (strcmp((*list)[i-1], (*list)[i]) == 0) {
349 memmove(&((*list)[i-1]), &((*list)[i]),
350 sizeof(char*)*((*n_list)-i));
351 (*n_list)--;
352 }
353 }
354}
355
356static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
357 char ***list, uint32 *n_list,
358 char **names, uint32 n_names )
359{
360 char **new_list = NULL;
361 uint32 n_new_list = 0;
362 int i, j;
363
364 if ( !names || (n_names == 0) )
365 return NT_STATUS_OK;
366
367 /* Alloc the maximum size we'll need */
368
369 if ( *list == NULL ) {
370 if ( (new_list = TALLOC_ARRAY( ctx, char *, n_names )) == NULL )
371 return NT_STATUS_NO_MEMORY;
372 n_new_list = n_names;
373 } else {
374 new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
375 (*n_list) + n_names );
376 if ( !new_list )
377 return NT_STATUS_NO_MEMORY;
378 n_new_list = (*n_list) + n_names;
379 }
380
381 /* Add all names */
382
383 for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
384 new_list[i] = talloc_strdup( new_list, names[j] );
385 }
386
387 *list = new_list;
388 *n_list = n_new_list;
389
390 return NT_STATUS_OK;
391}
392
393/***********************************************************************
394***********************************************************************/
395
396static NTSTATUS expand_groups( TALLOC_CTX *ctx,
397 struct winbindd_domain *d,
398 DOM_SID *glist, uint32 n_glist,
399 DOM_SID **new_glist, uint32 *n_new_glist,
400 char ***members, uint32 *n_members )
401{
402 int i, j;
403 NTSTATUS status = NT_STATUS_OK;
404 uint32 num_names = 0;
405 uint32 *name_types = NULL;
406 char **names = NULL;
407 DOM_SID *sid_mem = NULL;
408 TALLOC_CTX *tmp_ctx = NULL;
409 DOM_SID *new_groups = NULL;
410 size_t new_groups_size = 0;
411
412 *members = NULL;
413 *n_members = 0;
414 *new_glist = NULL;
415 *n_new_glist = 0;
416
417 for ( i=0; i<n_glist; i++ ) {
418 tmp_ctx = talloc_new( ctx );
419
420 /* Lookup the group membership */
421
422 status = d->methods->lookup_groupmem(d, tmp_ctx,
423 &glist[i], &num_names,
424 &sid_mem, &names,
425 &name_types);
426 if ( !NT_STATUS_IS_OK(status) )
427 goto out;
428
429 /* Separate users and groups into two lists */
430
431 for ( j=0; j<num_names; j++ ) {
432
433 /* Users */
434 if ( name_types[j] == SID_NAME_USER ||
435 name_types[j] == SID_NAME_COMPUTER )
436 {
437 status = add_names_to_list( ctx, members,
438 n_members,
439 names+j, 1 );
440 if ( !NT_STATUS_IS_OK(status) )
441 goto out;
442
443 continue;
444 }
445
446 /* Groups */
447 if ( name_types[j] == SID_NAME_DOM_GRP ||
448 name_types[j] == SID_NAME_ALIAS )
449 {
450 status = add_sid_to_array_unique(ctx,
451 &sid_mem[j],
452 &new_groups,
453 &new_groups_size);
454 if (!NT_STATUS_IS_OK(status)) {
455 goto out;
456 }
457
458 continue;
459 }
460 }
461
462 TALLOC_FREE( tmp_ctx );
463 }
464
465 *new_glist = new_groups;
466 *n_new_glist = (uint32)new_groups_size;
467
468 out:
469 TALLOC_FREE( tmp_ctx );
470
471 return status;
472}
473
474/***********************************************************************
475 Fill in the group membership field of a NT group given by group_sid
476***********************************************************************/
477
478static bool fill_grent_mem(struct winbindd_domain *domain,
479 struct winbindd_cli_state *state,
480 DOM_SID *group_sid,
481 enum lsa_SidType group_name_type,
482 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
483{
484 uint32 num_names = 0;
485 unsigned int buf_len = 0, buf_ndx = 0, i;
486 char **names = NULL, *buf = NULL;
487 bool result = False;
488 TALLOC_CTX *mem_ctx;
489 uint32 group_rid;
490 DOM_SID *glist = NULL;
491 DOM_SID *new_glist = NULL;
492 uint32 n_glist, n_new_glist;
493 int max_depth = lp_winbind_expand_groups();
494
495 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
496 return False;
497
498 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
499
500 /* Initialize with no members */
501
502 *num_gr_mem = 0;
503
504 /* HACK ALERT!! This whole routine does not cope with group members
505 * from more than one domain, ie aliases. Thus we have to work it out
506 * ourselves in a special routine. */
507
508 if (domain->internal) {
509 result = fill_passdb_alias_grmem(domain, group_sid,
510 num_gr_mem,
511 gr_mem, gr_mem_len);
512 goto done;
513 }
514
515 /* Verify name type */
516
517 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
518 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
519 {
520 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
521 sid_string_dbg(group_sid),
522 domain->name, group_name_type));
523 goto done;
524 }
525
526 /* OPTIMIZATION / HACK. See comment in
527 fill_grent_mem_domusers() */
528
529 sid_peek_rid( group_sid, &group_rid );
530 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
531 result = fill_grent_mem_domusers( mem_ctx, domain, state,
532 group_sid, group_name_type,
533 num_gr_mem, gr_mem,
534 gr_mem_len );
535 goto done;
536 }
537
538 /* Real work goes here. Create a list of group names to
539 expand starting with the initial one. Pass that to
540 expand_groups() which returns a list of more group names
541 to expand. Do this up to the max search depth. */
542
543 if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
544 result = False;
545 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
546 goto done;
547 }
548 sid_copy( &glist[0], group_sid );
549 n_glist = 1;
550
551 for ( i=0; i<max_depth && glist; i++ ) {
552 uint32 n_members = 0;
553 char **members = NULL;
554 NTSTATUS nt_status;
555
556 nt_status = expand_groups( mem_ctx, domain,
557 glist, n_glist,
558 &new_glist, &n_new_glist,
559 &members, &n_members);
560 if ( !NT_STATUS_IS_OK(nt_status) ) {
561 result = False;
562 goto done;
563 }
564
565 /* Add new group members to list */
566
567 nt_status = add_names_to_list( mem_ctx, &names, &num_names,
568 members, n_members );
569 if ( !NT_STATUS_IS_OK(nt_status) ) {
570 result = False;
571 goto done;
572 }
573
574 TALLOC_FREE( members );
575
576 /* If we have no more groups to expand, break out
577 early */
578
579 if (new_glist == NULL)
580 break;
581
582 /* One more round */
583 TALLOC_FREE(glist);
584 glist = new_glist;
585 n_glist = n_new_glist;
586 }
587 TALLOC_FREE( glist );
588
589 sort_unique_list(&names, &num_names);
590
591 DEBUG(10, ("looked up %d names\n", num_names));
592
593 again:
594 /* Add members to list */
595
596 for (i = 0; i < num_names; i++) {
597 int len;
598
599 DEBUG(10, ("processing name %s\n", names[i]));
600
601 len = strlen(names[i]);
602
603 /* Add to list or calculate buffer length */
604
605 if (!buf) {
606 buf_len += len + 1; /* List is comma separated */
607 (*num_gr_mem)++;
608 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
609 } else {
610 DEBUG(10, ("appending %s at ndx %d\n",
611 names[i], buf_ndx));
612 parse_add_domuser(&buf[buf_ndx], names[i], &len);
613 buf_ndx += len;
614 buf[buf_ndx] = ',';
615 buf_ndx++;
616 }
617 }
618
619 /* Allocate buffer */
620
621 if (!buf && buf_len != 0) {
622 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
623 DEBUG(1, ("out of memory\n"));
624 result = False;
625 goto done;
626 }
627 memset(buf, 0, buf_len);
628 goto again;
629 }
630
631 /* Now we're done */
632
633 if (buf && buf_ndx > 0) {
634 buf[buf_ndx - 1] = '\0';
635 }
636
637 *gr_mem = buf;
638 *gr_mem_len = buf_len;
639
640 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
641 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
642 result = True;
643
644done:
645
646 talloc_destroy(mem_ctx);
647
648 DEBUG(10, ("fill_grent_mem returning %d\n", result));
649
650 return result;
651}
652
653static void winbindd_getgrsid( struct winbindd_cli_state *state, DOM_SID group_sid );
654
655static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
656 enum lsa_SidType type )
657{
658 struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
659
660 if (!success) {
661 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
662 request_error(state);
663 return;
664 }
665
666 if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
667 DEBUG(5,("getgrnam_recv: not a group!\n"));
668 request_error(state);
669 return;
670 }
671
672 winbindd_getgrsid( state, *sid );
673}
674
675
676/* Return a group structure from a group name */
677
678void winbindd_getgrnam(struct winbindd_cli_state *state)
679{
680 struct winbindd_domain *domain;
681 fstring name_domain, name_group;
682 char *tmp;
683
684 /* Ensure null termination */
685 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
686
687 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
688 state->request.data.groupname));
689
690 /* Parse domain and groupname */
691
692 memset(name_group, 0, sizeof(fstring));
693
694 tmp = state->request.data.groupname;
695
696 name_domain[0] = '\0';
697 name_group[0] = '\0';
698
699 parse_domain_user(tmp, name_domain, name_group);
700
701 /* if no domain or our local domain and no local tdb group, default to
702 * our local domain for aliases */
703
704 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
705 fstrcpy(name_domain, get_global_sam_name());
706 }
707
708 /* Get info for the domain */
709
710 if ((domain = find_domain_from_name_noinit(name_domain)) == NULL) {
711 DEBUG(3, ("could not get domain sid for domain %s\n",
712 name_domain));
713 request_error(state);
714 return;
715 }
716 /* should we deal with users for our domain? */
717
718 if ( lp_winbind_trusted_domains_only() && domain->primary) {
719 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
720 "getgrnam() for %s\\%s.\n", name_domain, name_group));
721 request_error(state);
722 return;
723 }
724
725 /* Get rid and name type from name */
726
727 ws_name_replace( name_group, WB_REPLACE_CHAR );
728
729 winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
730 getgrnam_recv, WINBINDD_GETGRNAM, state );
731}
732
733struct getgrsid_state {
734 struct winbindd_cli_state *state;
735 struct winbindd_domain *domain;
736 char *group_name;
737 enum lsa_SidType group_type;
738 uid_t gid;
739 DOM_SID group_sid;
740};
741
742static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
743{
744 struct getgrsid_state *s =
745 (struct getgrsid_state *)private_data;
746 struct winbindd_domain *domain;
747 size_t gr_mem_len;
748 size_t num_gr_mem;
749 char *gr_mem;
750 fstring dom_name, group_name;
751
752 if (!success) {
753 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
754 request_error(s->state);
755 return;
756 }
757
758 s->gid = gid;
759
760 if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
761 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
762 request_error(s->state);
763 return;
764 }
765
766
767 /* Fill in group structure */
768
769 if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
770 DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
771 request_error(s->state);
772 return;
773 }
774
775 if (!fill_grent(&s->state->response.data.gr, dom_name, group_name, gid) ||
776 !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
777 &num_gr_mem, &gr_mem, &gr_mem_len))
778 {
779 request_error(s->state);
780 return;
781 }
782
783 s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
784
785 /* Group membership lives at start of extra data */
786
787 s->state->response.data.gr.gr_mem_ofs = 0;
788
789 s->state->response.length += gr_mem_len;
790 s->state->response.extra_data.data = gr_mem;
791
792 request_ok(s->state);
793}
794
795static void getgrsid_lookupsid_recv( void *private_data, bool success,
796 const char *dom_name, const char *name,
797 enum lsa_SidType name_type )
798{
799 struct getgrsid_state *s = (struct getgrsid_state *)private_data;
800
801 if (!success) {
802 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
803 request_error(s->state);
804 return;
805 }
806
807 /* either it's a domain group, a domain local group, or a
808 local group in an internal domain */
809
810 if ( !( (name_type==SID_NAME_DOM_GRP) ||
811 ((name_type==SID_NAME_ALIAS) &&
812 (s->domain->primary || s->domain->internal)) ) )
813 {
814 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
815 dom_name, name, name_type));
816 request_error(s->state);
817 return;
818 }
819
820 if ( (s->group_name = talloc_asprintf( s->state->mem_ctx,
821 "%s%c%s",
822 dom_name,
823 *lp_winbind_separator(),
824 name)) == NULL )
825 {
826 DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n"));
827 request_error(s->state);
828 return;
829 }
830
831 s->group_type = name_type;
832
833 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
834 getgrsid_sid2gid_recv, s);
835}
836
837static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
838{
839 struct getgrsid_state *s;
840
841 if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
842 DEBUG(0, ("talloc failed\n"));
843 request_error(state);
844 return;
845 }
846
847 s->state = state;
848
849 if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
850 DEBUG(3, ("Could not find domain for sid %s\n",
851 sid_string_dbg(&group_sid)));
852 request_error(state);
853 return;
854 }
855
856 sid_copy(&s->group_sid, &group_sid);
857
858 winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
859 getgrsid_lookupsid_recv, s );
860}
861
862
863static void getgrgid_recv(void *private_data, bool success, const char *sid)
864{
865 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
866 enum lsa_SidType name_type;
867 DOM_SID group_sid;
868
869 if (success) {
870 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
871 (unsigned long)(state->request.data.gid), sid));
872
873 string_to_sid(&group_sid, sid);
874 winbindd_getgrsid(state, group_sid);
875 return;
876 }
877
878 /* Ok, this might be "ours", i.e. an alias */
879 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
880 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
881 (name_type == SID_NAME_ALIAS)) {
882 /* Hey, got an alias */
883 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
884 (unsigned long)(state->request.data.gid), sid));
885 winbindd_getgrsid(state, group_sid);
886 return;
887 }
888
889 DEBUG(1, ("could not convert gid %lu to sid\n",
890 (unsigned long)state->request.data.gid));
891 request_error(state);
892}
893
894/* Return a group structure from a gid number */
895void winbindd_getgrgid(struct winbindd_cli_state *state)
896{
897 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
898 (unsigned long)state->request.data.gid));
899
900 /* always use the async interface */
901 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
902}
903
904/*
905 * set/get/endgrent functions
906 */
907
908/* "Rewind" file pointer for group database enumeration */
909
910static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
911{
912 struct winbindd_domain *domain;
913
914 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
915
916 /* Check user has enabled this */
917
918 if (!lp_winbind_enum_groups()) {
919 return False;
920 }
921
922 /* Free old static data if it exists */
923
924 if (state->getgrent_state != NULL) {
925 free_getent_state(state->getgrent_state);
926 state->getgrent_state = NULL;
927 }
928
929 /* Create sam pipes for each domain we know about */
930
931 for (domain = domain_list(); domain != NULL; domain = domain->next) {
932 struct getent_state *domain_state;
933
934 /* Create a state record for this domain */
935
936 /* don't add our domaina if we are a PDC or if we
937 are a member of a Samba domain */
938
939 if ( lp_winbind_trusted_domains_only() && domain->primary )
940 {
941 continue;
942 }
943
944
945 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
946 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
947 return False;
948 }
949
950 ZERO_STRUCTP(domain_state);
951
952 fstrcpy(domain_state->domain_name, domain->name);
953
954 /* Add to list of open domains */
955
956 DLIST_ADD(state->getgrent_state, domain_state);
957 }
958
959 state->getgrent_initialized = True;
960 return True;
961}
962
963void winbindd_setgrent(struct winbindd_cli_state *state)
964{
965 if (winbindd_setgrent_internal(state)) {
966 request_ok(state);
967 } else {
968 request_error(state);
969 }
970}
971
972/* Close file pointer to ntdom group database */
973
974void winbindd_endgrent(struct winbindd_cli_state *state)
975{
976 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
977
978 free_getent_state(state->getgrent_state);
979 state->getgrent_initialized = False;
980 state->getgrent_state = NULL;
981 request_ok(state);
982}
983
984/* Get the list of domain groups and domain aliases for a domain. We fill in
985 the sam_entries and num_sam_entries fields with domain group information.
986 Return True if some groups were returned, False otherwise. */
987
988bool get_sam_group_entries(struct getent_state *ent)
989{
990 NTSTATUS status;
991 uint32 num_entries;
992 struct acct_info *name_list = NULL;
993 TALLOC_CTX *mem_ctx;
994 bool result = False;
995 struct acct_info *sam_grp_entries = NULL;
996 struct winbindd_domain *domain;
997
998 if (ent->got_sam_entries)
999 return False;
1000
1001 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
1002 ent->domain_name))) {
1003 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
1004 return False;
1005 }
1006
1007 /* Free any existing group info */
1008
1009 SAFE_FREE(ent->sam_entries);
1010 ent->num_sam_entries = 0;
1011 ent->got_sam_entries = True;
1012
1013 /* Enumerate domain groups */
1014
1015 num_entries = 0;
1016
1017 if (!(domain = find_domain_from_name(ent->domain_name))) {
1018 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
1019 goto done;
1020 }
1021
1022 /* always get the domain global groups */
1023
1024 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
1025
1026 if (!NT_STATUS_IS_OK(status)) {
1027 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
1028 result = False;
1029 goto done;
1030 }
1031
1032 /* Copy entries into return buffer */
1033
1034 if (num_entries) {
1035 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
1036 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
1037 num_entries));
1038 result = False;
1039 goto done;
1040 }
1041 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
1042 }
1043
1044 ent->num_sam_entries = num_entries;
1045
1046 /* get the domain local groups if we are a member of a native win2k domain
1047 and are not using LDAP to get the groups */
1048
1049 if ( ( lp_security() != SEC_ADS && domain->native_mode
1050 && domain->primary) || domain->internal )
1051 {
1052 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
1053 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
1054
1055 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
1056
1057 if ( !NT_STATUS_IS_OK(status) ) {
1058 DEBUG(3,("get_sam_group_entries: "
1059 "Failed to enumerate "
1060 "domain local groups with error %s!\n",
1061 nt_errstr(status)));
1062 num_entries = 0;
1063 }
1064 else
1065 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
1066
1067 /* Copy entries into return buffer */
1068
1069 if ( num_entries ) {
1070 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
1071 {
1072 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
1073 num_entries));
1074 result = False;
1075 goto done;
1076 }
1077
1078 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
1079 num_entries * sizeof(struct acct_info) );
1080 }
1081
1082 ent->num_sam_entries += num_entries;
1083 }
1084
1085
1086 /* Fill in remaining fields */
1087
1088 ent->sam_entries = name_list;
1089 ent->sam_entry_index = 0;
1090
1091 result = (ent->num_sam_entries > 0);
1092
1093 done:
1094 talloc_destroy(mem_ctx);
1095
1096 return result;
1097}
1098
1099/* Fetch next group entry from ntdom database */
1100
1101#define MAX_GETGRENT_GROUPS 500
1102
1103void winbindd_getgrent(struct winbindd_cli_state *state)
1104{
1105 struct getent_state *ent;
1106 struct winbindd_gr *group_list = NULL;
1107 int num_groups, group_list_ndx, gr_mem_list_len = 0;
1108 char *gr_mem_list = NULL;
1109
1110 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1111
1112 /* Check user has enabled this */
1113
1114 if (!lp_winbind_enum_groups()) {
1115 request_error(state);
1116 return;
1117 }
1118
1119 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
1120
1121 if (num_groups == 0) {
1122 request_error(state);
1123 return;
1124 }
1125
1126 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
1127 request_error(state);
1128 return;
1129 }
1130
1131 memset(state->response.extra_data.data, '\0',
1132 num_groups * sizeof(struct winbindd_gr) );
1133
1134 state->response.data.num_entries = 0;
1135
1136 group_list = (struct winbindd_gr *)state->response.extra_data.data;
1137
1138 if (!state->getgrent_initialized)
1139 winbindd_setgrent_internal(state);
1140
1141 if (!(ent = state->getgrent_state)) {
1142 request_error(state);
1143 return;
1144 }
1145
1146 /* Start sending back groups */
1147
1148 for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
1149 struct acct_info *name_list = NULL;
1150 fstring domain_group_name;
1151 uint32 result;
1152 gid_t group_gid;
1153 size_t gr_mem_len;
1154 char *gr_mem;
1155 DOM_SID group_sid;
1156 struct winbindd_domain *domain;
1157
1158 /* Do we need to fetch another chunk of groups? */
1159
1160 tryagain:
1161
1162 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1163 ent->sam_entry_index, ent->num_sam_entries));
1164
1165 if (ent->num_sam_entries == ent->sam_entry_index) {
1166
1167 while(ent && !get_sam_group_entries(ent)) {
1168 struct getent_state *next_ent;
1169
1170 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
1171
1172 /* Free state information for this domain */
1173
1174 SAFE_FREE(ent->sam_entries);
1175
1176 next_ent = ent->next;
1177 DLIST_REMOVE(state->getgrent_state, ent);
1178
1179 SAFE_FREE(ent);
1180 ent = next_ent;
1181 }
1182
1183 /* No more domains */
1184
1185 if (!ent)
1186 break;
1187 }
1188
1189 name_list = (struct acct_info *)ent->sam_entries;
1190
1191 if (!(domain =
1192 find_domain_from_name(ent->domain_name))) {
1193 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
1194 result = False;
1195 goto done;
1196 }
1197
1198 /* Lookup group info */
1199
1200 sid_copy(&group_sid, &domain->sid);
1201 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1202
1203 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
1204 union unid_t id;
1205 enum lsa_SidType type;
1206
1207 DEBUG(10, ("SID %s not in idmap\n",
1208 sid_string_dbg(&group_sid)));
1209
1210 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1211 DEBUG(1, ("could not look up gid for group "
1212 "%s\n",
1213 name_list[ent->sam_entry_index].acct_name));
1214 ent->sam_entry_index++;
1215 goto tryagain;
1216 }
1217
1218 if ((type != SID_NAME_DOM_GRP) &&
1219 (type != SID_NAME_ALIAS) &&
1220 (type != SID_NAME_WKN_GRP)) {
1221 DEBUG(1, ("Group %s is a %s, not a group\n",
1222 sid_type_lookup(type),
1223 name_list[ent->sam_entry_index].acct_name));
1224 ent->sam_entry_index++;
1225 goto tryagain;
1226 }
1227 group_gid = id.gid;
1228 }
1229
1230 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1231 (unsigned long)name_list[ent->sam_entry_index].rid));
1232
1233 /* Fill in group entry */
1234
1235 fill_domain_username(domain_group_name, ent->domain_name,
1236 name_list[ent->sam_entry_index].acct_name, True);
1237
1238 result = fill_grent(&group_list[group_list_ndx],
1239 ent->domain_name,
1240 name_list[ent->sam_entry_index].acct_name,
1241 group_gid);
1242
1243 /* Fill in group membership entry */
1244
1245 if (result) {
1246 size_t num_gr_mem = 0;
1247 DOM_SID member_sid;
1248 group_list[group_list_ndx].num_gr_mem = 0;
1249 gr_mem = NULL;
1250 gr_mem_len = 0;
1251
1252 /* Get group membership */
1253 if (state->request.cmd == WINBINDD_GETGRLST) {
1254 result = True;
1255 } else {
1256 sid_copy(&member_sid, &domain->sid);
1257 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1258 result = fill_grent_mem(
1259 domain,
1260 NULL,
1261 &member_sid,
1262 SID_NAME_DOM_GRP,
1263 &num_gr_mem,
1264 &gr_mem, &gr_mem_len);
1265
1266 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1267 }
1268 }
1269
1270 if (result) {
1271 /* Append to group membership list */
1272 gr_mem_list = (char *)SMB_REALLOC(
1273 gr_mem_list, gr_mem_list_len + gr_mem_len);
1274
1275 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
1276 DEBUG(0, ("out of memory\n"));
1277 gr_mem_list_len = 0;
1278 break;
1279 }
1280
1281 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1282 gr_mem_list_len, (unsigned int)gr_mem_len));
1283
1284 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1285 gr_mem_len);
1286
1287 SAFE_FREE(gr_mem);
1288
1289 group_list[group_list_ndx].gr_mem_ofs =
1290 gr_mem_list_len;
1291
1292 gr_mem_list_len += gr_mem_len;
1293 }
1294
1295 ent->sam_entry_index++;
1296
1297 /* Add group to return list */
1298
1299 if (result) {
1300
1301 DEBUG(10, ("adding group num_entries = %d\n",
1302 state->response.data.num_entries));
1303
1304 group_list_ndx++;
1305 state->response.data.num_entries++;
1306
1307 state->response.length +=
1308 sizeof(struct winbindd_gr);
1309
1310 } else {
1311 DEBUG(0, ("could not lookup domain group %s\n",
1312 domain_group_name));
1313 }
1314 }
1315
1316 /* Copy the list of group memberships to the end of the extra data */
1317
1318 if (group_list_ndx == 0)
1319 goto done;
1320
1321 state->response.extra_data.data = SMB_REALLOC(
1322 state->response.extra_data.data,
1323 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1324
1325 if (!state->response.extra_data.data) {
1326 DEBUG(0, ("out of memory\n"));
1327 group_list_ndx = 0;
1328 SAFE_FREE(gr_mem_list);
1329 request_error(state);
1330 return;
1331 }
1332
1333 memcpy(&((char *)state->response.extra_data.data)
1334 [group_list_ndx * sizeof(struct winbindd_gr)],
1335 gr_mem_list, gr_mem_list_len);
1336
1337 state->response.length += gr_mem_list_len;
1338
1339 DEBUG(10, ("returning %d groups, length = %d\n",
1340 group_list_ndx, gr_mem_list_len));
1341
1342 /* Out of domains */
1343
1344 done:
1345
1346 SAFE_FREE(gr_mem_list);
1347
1348 if (group_list_ndx > 0)
1349 request_ok(state);
1350 else
1351 request_error(state);
1352}
1353
1354/* List domain groups without mapping to unix ids */
1355void winbindd_list_groups(struct winbindd_cli_state *state)
1356{
1357 winbindd_list_ent(state, LIST_GROUPS);
1358}
1359
1360/* Get user supplementary groups. This is much quicker than trying to
1361 invert the groups database. We merge the groups from the gids and
1362 other_sids info3 fields as trusted domain, universal group
1363 memberships, and nested groups (win2k native mode only) are not
1364 returned by the getgroups RPC call but are present in the info3. */
1365
1366struct getgroups_state {
1367 struct winbindd_cli_state *state;
1368 struct winbindd_domain *domain;
1369 char *domname;
1370 char *username;
1371 DOM_SID user_sid;
1372
1373 const DOM_SID *token_sids;
1374 size_t i, num_token_sids;
1375
1376 gid_t *token_gids;
1377 size_t num_token_gids;
1378};
1379
1380static void getgroups_usersid_recv(void *private_data, bool success,
1381 const DOM_SID *sid, enum lsa_SidType type);
1382static void getgroups_tokensids_recv(void *private_data, bool success,
1383 DOM_SID *token_sids, size_t num_token_sids);
1384static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1385
1386void winbindd_getgroups(struct winbindd_cli_state *state)
1387{
1388 struct getgroups_state *s;
1389
1390 /* Ensure null termination */
1391 state->request.data.username
1392 [sizeof(state->request.data.username)-1]='\0';
1393
1394 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1395 state->request.data.username));
1396
1397 /* Parse domain and username */
1398
1399 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1400 if (s == NULL) {
1401 DEBUG(0, ("talloc failed\n"));
1402 request_error(state);
1403 return;
1404 }
1405
1406 s->state = state;
1407
1408 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
1409
1410 if (!parse_domain_user_talloc(state->mem_ctx,
1411 state->request.data.username,
1412 &s->domname, &s->username)) {
1413 DEBUG(5, ("Could not parse domain user: %s\n",
1414 state->request.data.username));
1415
1416 /* error out if we do not have nested group support */
1417
1418 if ( !lp_winbind_nested_groups() ) {
1419 request_error(state);
1420 return;
1421 }
1422
1423 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1424 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1425 }
1426
1427 /* Get info for the domain (either by short domain name or
1428 DNS name in the case of a UPN) */
1429
1430 s->domain = find_domain_from_name_noinit(s->domname);
1431 if (!s->domain) {
1432 char *p = strchr(s->username, '@');
1433
1434 if (p) {
1435 s->domain = find_domain_from_name_noinit(p+1);
1436 }
1437
1438 }
1439
1440 if (s->domain == NULL) {
1441 DEBUG(7, ("could not find domain entry for domain %s\n",
1442 s->domname));
1443 request_error(state);
1444 return;
1445 }
1446
1447 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1448 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1449 "getgroups() for %s\\%s.\n", s->domname,
1450 s->username));
1451 request_error(state);
1452 return;
1453 }
1454
1455 /* Get rid and name type from name. The following costs 1 packet */
1456
1457 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1458 getgroups_usersid_recv, WINBINDD_GETGROUPS, s);
1459}
1460
1461static void getgroups_usersid_recv(void *private_data, bool success,
1462 const DOM_SID *sid, enum lsa_SidType type)
1463{
1464 struct getgroups_state *s =
1465 (struct getgroups_state *)private_data;
1466
1467 if ((!success) ||
1468 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1469 request_error(s->state);
1470 return;
1471 }
1472
1473 sid_copy(&s->user_sid, sid);
1474
1475 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1476 getgroups_tokensids_recv, s);
1477}
1478
1479static void getgroups_tokensids_recv(void *private_data, bool success,
1480 DOM_SID *token_sids, size_t num_token_sids)
1481{
1482 struct getgroups_state *s =
1483 (struct getgroups_state *)private_data;
1484
1485 /* We need at least the user sid and the primary group in the token,
1486 * otherwise it's an error */
1487
1488 if ((!success) || (num_token_sids < 2)) {
1489 request_error(s->state);
1490 return;
1491 }
1492
1493 s->token_sids = token_sids;
1494 s->num_token_sids = num_token_sids;
1495 s->i = 0;
1496
1497 s->token_gids = NULL;
1498 s->num_token_gids = 0;
1499
1500 getgroups_sid2gid_recv(s, False, 0);
1501}
1502
1503static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
1504{
1505 struct getgroups_state *s =
1506 (struct getgroups_state *)private_data;
1507
1508 if (success) {
1509 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1510 &s->token_gids,
1511 &s->num_token_gids)) {
1512 return;
1513 }
1514 }
1515
1516 if (s->i < s->num_token_sids) {
1517 const DOM_SID *sid = &s->token_sids[s->i];
1518 s->i += 1;
1519
1520 if (sid_equal(sid, &s->user_sid)) {
1521 getgroups_sid2gid_recv(s, False, 0);
1522 return;
1523 }
1524
1525 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1526 getgroups_sid2gid_recv, s);
1527 return;
1528 }
1529
1530 s->state->response.data.num_entries = s->num_token_gids;
1531 if (s->num_token_gids) {
1532 /* s->token_gids are talloced */
1533 s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
1534 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1535 }
1536 request_ok(s->state);
1537}
1538
1539/* Get user supplementary sids. This is equivalent to the
1540 winbindd_getgroups() function but it involves a SID->SIDs mapping
1541 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1542 idmap. This call is designed to be used with applications that need
1543 to do ACL evaluation themselves. Note that the cached info3 data is
1544 not used
1545
1546 this function assumes that the SID that comes in is a user SID. If
1547 you pass in another type of SID then you may get unpredictable
1548 results.
1549*/
1550
1551static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1552 size_t num_sids);
1553
1554void winbindd_getusersids(struct winbindd_cli_state *state)
1555{
1556 DOM_SID *user_sid;
1557
1558 /* Ensure null termination */
1559 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1560
1561 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1562 if (user_sid == NULL) {
1563 DEBUG(1, ("talloc failed\n"));
1564 request_error(state);
1565 return;
1566 }
1567
1568 if (!string_to_sid(user_sid, state->request.data.sid)) {
1569 DEBUG(1, ("Could not get convert sid %s from string\n",
1570 state->request.data.sid));
1571 request_error(state);
1572 return;
1573 }
1574
1575 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1576 state);
1577}
1578
1579static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1580 size_t num_sids)
1581{
1582 struct winbindd_cli_state *state =
1583 (struct winbindd_cli_state *)private_data;
1584 char *ret = NULL;
1585 unsigned ofs, ret_size = 0;
1586 size_t i;
1587
1588 if (!success) {
1589 request_error(state);
1590 return;
1591 }
1592
1593 /* work out the response size */
1594 for (i = 0; i < num_sids; i++) {
1595 fstring s;
1596 sid_to_fstring(s, &sids[i]);
1597 ret_size += strlen(s) + 1;
1598 }
1599
1600 /* build the reply */
1601 ret = (char *)SMB_MALLOC(ret_size);
1602 if (!ret) {
1603 DEBUG(0, ("malloc failed\n"));
1604 request_error(state);
1605 return;
1606 }
1607 ofs = 0;
1608 for (i = 0; i < num_sids; i++) {
1609 fstring s;
1610 sid_to_fstring(s, &sids[i]);
1611 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1612 ofs += strlen(ret+ofs) + 1;
1613 }
1614
1615 /* Send data back to client */
1616 state->response.data.num_entries = num_sids;
1617 state->response.extra_data.data = ret;
1618 state->response.length += ret_size;
1619 request_ok(state);
1620}
1621
1622void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1623{
1624 DOM_SID user_sid;
1625 struct winbindd_domain *domain;
1626
1627 /* Ensure null termination */
1628 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1629
1630 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1631 DEBUG(1, ("Could not get convert sid %s from string\n",
1632 state->request.data.sid));
1633 request_error(state);
1634 return;
1635 }
1636
1637 /* Get info for the domain */
1638 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1639 DEBUG(0,("could not find domain entry for sid %s\n",
1640 sid_string_dbg(&user_sid)));
1641 request_error(state);
1642 return;
1643 }
1644
1645 sendto_domain(state, domain);
1646}
1647
1648enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1649 struct winbindd_cli_state *state)
1650{
1651 DOM_SID user_sid;
1652 NTSTATUS status;
1653
1654 char *sidstring;
1655 ssize_t len;
1656 DOM_SID *groups;
1657 uint32 num_groups;
1658
1659 /* Ensure null termination */
1660 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1661
1662 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1663 DEBUG(1, ("Could not get convert sid %s from string\n",
1664 state->request.data.sid));
1665 return WINBINDD_ERROR;
1666 }
1667
1668 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1669 &user_sid, &num_groups,
1670 &groups);
1671 if (!NT_STATUS_IS_OK(status))
1672 return WINBINDD_ERROR;
1673
1674 if (num_groups == 0) {
1675 state->response.data.num_entries = 0;
1676 state->response.extra_data.data = NULL;
1677 return WINBINDD_OK;
1678 }
1679
1680 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1681 DEBUG(0, ("talloc failed\n"));
1682 return WINBINDD_ERROR;
1683 }
1684
1685 state->response.extra_data.data = SMB_STRDUP(sidstring);
1686 if (!state->response.extra_data.data) {
1687 return WINBINDD_ERROR;
1688 }
1689 state->response.length += len+1;
1690 state->response.data.num_entries = num_groups;
1691
1692 return WINBINDD_OK;
1693}
Note: See TracBrowser for help on using the repository browser.