winbindd: fix horrible mis-indentation of toplvl braces in getgrsid_sid2gid_recv
[Samba.git] / source / winbindd / winbindd_group.c
blob6f2b15a4819a5b78bf17137688f8fe944462233b
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
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
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.
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.
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/>.
25 #include "includes.h"
26 #include "winbindd.h"
28 extern bool opt_nocache;
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_WINBIND
33 static void add_member(const char *domain, const char *user,
34 char **pp_members, size_t *p_num_members)
36 fstring name;
38 if (domain != NULL) {
39 fill_domain_username(name, domain, user, True);
40 } else {
41 fstrcpy(name, user);
43 safe_strcat(name, ",", sizeof(name)-1);
44 string_append(pp_members, name);
45 *p_num_members += 1;
48 /**********************************************************************
49 Add member users resulting from sid. Expand if it is a domain group.
50 **********************************************************************/
52 static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
54 DOM_SID dom_sid;
55 uint32 rid;
56 struct winbindd_domain *domain;
57 size_t i;
59 char *domain_name = NULL;
60 char *name = NULL;
61 enum lsa_SidType type;
63 uint32 num_names;
64 DOM_SID *sid_mem;
65 char **names;
66 uint32 *types;
68 NTSTATUS result;
70 TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
72 if (mem_ctx == NULL) {
73 DEBUG(1, ("talloc_init failed\n"));
74 return;
77 sid_copy(&dom_sid, sid);
78 sid_split_rid(&dom_sid, &rid);
80 domain = find_lookup_domain_from_sid(sid);
82 if (domain == NULL) {
83 DEBUG(3, ("Could not find domain for sid %s\n",
84 sid_string_dbg(sid)));
85 goto done;
88 result = domain->methods->sid_to_name(domain, mem_ctx, sid,
89 &domain_name, &name, &type);
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;
97 DEBUG(10, ("Found name %s, type %d\n", name, type));
99 if (type == SID_NAME_USER) {
100 add_member(domain_name, name, pp_members, p_num_members);
101 goto done;
104 if (type != SID_NAME_DOM_GRP) {
105 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
106 name));
107 goto done;
110 /* Expand the domain group, this must be done via the target domain */
112 domain = find_domain_from_sid(sid);
114 if (domain == NULL) {
115 DEBUG(3, ("Could not find domain from SID %s\n",
116 sid_string_dbg(sid)));
117 goto done;
120 result = domain->methods->lookup_groupmem(domain, mem_ctx,
121 sid, &num_names,
122 &sid_mem, &names,
123 &types);
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;
131 for (i=0; i<num_names; i++) {
132 DEBUG(10, ("Adding group member SID %s\n",
133 sid_string_dbg(&sid_mem[i])));
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;
141 add_member(NULL, names[i], pp_members, p_num_members);
144 done:
145 talloc_destroy(mem_ctx);
146 return;
149 static 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)
153 DOM_SID *members;
154 size_t i, num_members;
156 *num_gr_mem = 0;
157 *gr_mem = NULL;
158 *gr_mem_len = 0;
160 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
161 &num_members)))
162 return True;
164 for (i=0; i<num_members; i++) {
165 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
168 TALLOC_FREE(members);
170 if (*gr_mem != NULL) {
171 size_t len;
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;
179 return True;
182 /* Fill a grent structure from various other information */
184 static bool fill_grent(struct winbindd_gr *gr, const char *dom_name,
185 const char *gr_name, gid_t unix_gid)
187 fstring full_group_name;
189 fill_domain_username( full_group_name, dom_name, gr_name, True );
191 gr->gr_gid = unix_gid;
193 /* Group name and password */
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);
198 return True;
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 ***********************************************************************/
210 static 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)
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;
228 DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
229 domain->name ));
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)));
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)) {
250 DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
251 sid_string_dbg(pquerying_user_sid) ));
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;
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;
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;
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 ));
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;
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;
308 memcpy(buf, name, buf_len);
310 DEBUG(10,("fill_grent_mem_domain_users: user %s in "
311 "'Domain Users' in domain %s\n",
312 name, domain->name ));
314 /* user is the only member */
315 *num_gr_mem = 1;
318 *gr_mem = buf;
319 *gr_mem_len = buf_len;
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"));
325 return True;
328 /***********************************************************************
329 Add names to a list. Assumes a canonical version of the string
330 in DOMAIN\user
331 ***********************************************************************/
333 static int namecmp( const void *a, const void *b )
335 return StrCaseCmp( * (char * const *) a, * (char * const *) b);
338 static void sort_unique_list(char ***list, uint32 *n_list)
340 uint32_t i;
342 /* search for duplicates for sorting and looking for matching
343 neighbors */
345 qsort(*list, *n_list, sizeof(char*), QSORT_CAST namecmp);
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)--;
356 static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
357 char ***list, uint32 *n_list,
358 char **names, uint32 n_names )
360 char **new_list = NULL;
361 uint32 n_new_list = 0;
362 int i, j;
364 if ( !names || (n_names == 0) )
365 return NT_STATUS_OK;
367 /* Alloc the maximum size we'll need */
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;
381 /* Add all names */
383 for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
384 new_list[i] = talloc_strdup( new_list, names[j] );
387 *list = new_list;
388 *n_list = n_new_list;
390 return NT_STATUS_OK;
393 /***********************************************************************
394 ***********************************************************************/
396 static 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 )
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;
412 *members = NULL;
413 *n_members = 0;
414 *new_glist = NULL;
415 *n_new_glist = 0;
417 for ( i=0; i<n_glist; i++ ) {
418 tmp_ctx = talloc_new( ctx );
420 /* Lookup the group membership */
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;
429 /* Separate users and groups into two lists */
431 for ( j=0; j<num_names; j++ ) {
433 /* Users */
434 if ( name_types[j] == SID_NAME_USER ||
435 name_types[j] == SID_NAME_COMPUTER )
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;
443 continue;
446 /* Groups */
447 if ( name_types[j] == SID_NAME_DOM_GRP ||
448 name_types[j] == SID_NAME_ALIAS )
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;
458 continue;
462 TALLOC_FREE( tmp_ctx );
465 *new_glist = new_groups;
466 *n_new_glist = (uint32)new_groups_size;
468 out:
469 TALLOC_FREE( tmp_ctx );
471 return status;
474 /***********************************************************************
475 Fill in the group membership field of a NT group given by group_sid
476 ***********************************************************************/
478 static 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)
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();
495 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
496 return False;
498 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
500 /* Initialize with no members */
502 *num_gr_mem = 0;
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. */
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;
515 /* Verify name type */
517 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
518 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
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;
526 /* OPTIMIZATION / HACK. See comment in
527 fill_grent_mem_domusers() */
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;
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. */
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;
548 sid_copy( &glist[0], group_sid );
549 n_glist = 1;
551 for ( i=0; i<max_depth && glist; i++ ) {
552 uint32 n_members = 0;
553 char **members = NULL;
554 NTSTATUS nt_status;
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;
565 /* Add new group members to list */
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;
574 TALLOC_FREE( members );
576 /* If we have no more groups to expand, break out
577 early */
579 if (new_glist == NULL)
580 break;
582 /* One more round */
583 TALLOC_FREE(glist);
584 glist = new_glist;
585 n_glist = n_new_glist;
587 TALLOC_FREE( glist );
589 sort_unique_list(&names, &num_names);
591 DEBUG(10, ("looked up %d names\n", num_names));
593 again:
594 /* Add members to list */
596 for (i = 0; i < num_names; i++) {
597 int len;
599 DEBUG(10, ("processing name %s\n", names[i]));
601 len = strlen(names[i]);
603 /* Add to list or calculate buffer length */
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++;
619 /* Allocate buffer */
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;
627 memset(buf, 0, buf_len);
628 goto again;
631 /* Now we're done */
633 if (buf && buf_ndx > 0) {
634 buf[buf_ndx - 1] = '\0';
637 *gr_mem = buf;
638 *gr_mem_len = buf_len;
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;
644 done:
646 talloc_destroy(mem_ctx);
648 DEBUG(10, ("fill_grent_mem returning %d\n", result));
650 return result;
653 static void winbindd_getgrsid( struct winbindd_cli_state *state, DOM_SID group_sid );
655 static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
656 enum lsa_SidType type )
658 struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
660 if (!success) {
661 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
662 request_error(state);
663 return;
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;
672 winbindd_getgrsid( state, *sid );
676 /* Return a group structure from a group name */
678 void winbindd_getgrnam(struct winbindd_cli_state *state)
680 struct winbindd_domain *domain;
681 fstring name_domain, name_group;
682 char *tmp;
684 /* Ensure null termination */
685 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
687 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
688 state->request.data.groupname));
690 /* Parse domain and groupname */
692 memset(name_group, 0, sizeof(fstring));
694 tmp = state->request.data.groupname;
696 name_domain[0] = '\0';
697 name_group[0] = '\0';
699 parse_domain_user(tmp, name_domain, name_group);
701 /* if no domain or our local domain and no local tdb group, default to
702 * our local domain for aliases */
704 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
705 fstrcpy(name_domain, get_global_sam_name());
708 /* Get info for the domain */
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;
716 /* should we deal with users for our domain? */
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;
725 /* Get rid and name type from name */
727 ws_name_replace( name_group, WB_REPLACE_CHAR );
729 winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
730 getgrnam_recv, WINBINDD_GETGRNAM, state );
733 struct 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;
742 static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
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;
752 if (!success) {
753 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
754 request_error(s->state);
755 return;
758 s->gid = gid;
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;
767 /* Fill in group structure */
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;
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))
779 request_error(s->state);
780 return;
783 s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
785 /* Group membership lives at start of extra data */
787 s->state->response.data.gr.gr_mem_ofs = 0;
789 s->state->response.length += gr_mem_len;
790 s->state->response.extra_data.data = gr_mem;
792 request_ok(s->state);
795 static void getgrsid_lookupsid_recv( void *private_data, bool success,
796 const char *dom_name, const char *name,
797 enum lsa_SidType name_type )
799 struct getgrsid_state *s = (struct getgrsid_state *)private_data;
801 if (!success) {
802 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
803 request_error(s->state);
804 return;
807 /* either it's a domain group, a domain local group, or a
808 local group in an internal domain */
810 if ( !( (name_type==SID_NAME_DOM_GRP) ||
811 ((name_type==SID_NAME_ALIAS) &&
812 (s->domain->primary || s->domain->internal)) ) )
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;
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 )
826 DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n"));
827 request_error(s->state);
828 return;
831 s->group_type = name_type;
833 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
834 getgrsid_sid2gid_recv, s);
837 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
839 struct getgrsid_state *s;
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;
847 s->state = state;
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;
856 sid_copy(&s->group_sid, &group_sid);
858 winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
859 getgrsid_lookupsid_recv, s );
863 static void getgrgid_recv(void *private_data, bool success, const char *sid)
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;
869 if (success) {
870 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
871 (unsigned long)(state->request.data.gid), sid));
873 string_to_sid(&group_sid, sid);
874 winbindd_getgrsid(state, group_sid);
875 return;
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;
889 DEBUG(1, ("could not convert gid %lu to sid\n",
890 (unsigned long)state->request.data.gid));
891 request_error(state);
894 /* Return a group structure from a gid number */
895 void winbindd_getgrgid(struct winbindd_cli_state *state)
897 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
898 (unsigned long)state->request.data.gid));
900 /* always use the async interface */
901 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
905 * set/get/endgrent functions
908 /* "Rewind" file pointer for group database enumeration */
910 static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
912 struct winbindd_domain *domain;
914 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
916 /* Check user has enabled this */
918 if (!lp_winbind_enum_groups()) {
919 return False;
922 /* Free old static data if it exists */
924 if (state->getgrent_state != NULL) {
925 free_getent_state(state->getgrent_state);
926 state->getgrent_state = NULL;
929 /* Create sam pipes for each domain we know about */
931 for (domain = domain_list(); domain != NULL; domain = domain->next) {
932 struct getent_state *domain_state;
934 /* Create a state record for this domain */
936 /* don't add our domaina if we are a PDC or if we
937 are a member of a Samba domain */
939 if ( lp_winbind_trusted_domains_only() && domain->primary )
941 continue;
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;
950 ZERO_STRUCTP(domain_state);
952 fstrcpy(domain_state->domain_name, domain->name);
954 /* Add to list of open domains */
956 DLIST_ADD(state->getgrent_state, domain_state);
959 state->getgrent_initialized = True;
960 return True;
963 void winbindd_setgrent(struct winbindd_cli_state *state)
965 if (winbindd_setgrent_internal(state)) {
966 request_ok(state);
967 } else {
968 request_error(state);
972 /* Close file pointer to ntdom group database */
974 void winbindd_endgrent(struct winbindd_cli_state *state)
976 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
978 free_getent_state(state->getgrent_state);
979 state->getgrent_initialized = False;
980 state->getgrent_state = NULL;
981 request_ok(state);
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. */
988 bool get_sam_group_entries(struct getent_state *ent)
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;
998 if (ent->got_sam_entries)
999 return False;
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;
1007 /* Free any existing group info */
1009 SAFE_FREE(ent->sam_entries);
1010 ent->num_sam_entries = 0;
1011 ent->got_sam_entries = True;
1013 /* Enumerate domain groups */
1015 num_entries = 0;
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;
1022 /* always get the domain global groups */
1024 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
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;
1032 /* Copy entries into return buffer */
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;
1041 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
1044 ent->num_sam_entries = num_entries;
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 */
1049 if ( ( lp_security() != SEC_ADS && domain->native_mode
1050 && domain->primary) || domain->internal )
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"));
1055 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
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;
1064 else
1065 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
1067 /* Copy entries into return buffer */
1069 if ( num_entries ) {
1070 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
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;
1078 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
1079 num_entries * sizeof(struct acct_info) );
1082 ent->num_sam_entries += num_entries;
1086 /* Fill in remaining fields */
1088 ent->sam_entries = name_list;
1089 ent->sam_entry_index = 0;
1091 result = (ent->num_sam_entries > 0);
1093 done:
1094 talloc_destroy(mem_ctx);
1096 return result;
1099 /* Fetch next group entry from ntdom database */
1101 #define MAX_GETGRENT_GROUPS 500
1103 void winbindd_getgrent(struct winbindd_cli_state *state)
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;
1110 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1112 /* Check user has enabled this */
1114 if (!lp_winbind_enum_groups()) {
1115 request_error(state);
1116 return;
1119 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
1121 if (num_groups == 0) {
1122 request_error(state);
1123 return;
1126 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
1127 request_error(state);
1128 return;
1131 memset(state->response.extra_data.data, '\0',
1132 num_groups * sizeof(struct winbindd_gr) );
1134 state->response.data.num_entries = 0;
1136 group_list = (struct winbindd_gr *)state->response.extra_data.data;
1138 if (!state->getgrent_initialized)
1139 winbindd_setgrent_internal(state);
1141 if (!(ent = state->getgrent_state)) {
1142 request_error(state);
1143 return;
1146 /* Start sending back groups */
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;
1158 /* Do we need to fetch another chunk of groups? */
1160 tryagain:
1162 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1163 ent->sam_entry_index, ent->num_sam_entries));
1165 if (ent->num_sam_entries == ent->sam_entry_index) {
1167 while(ent && !get_sam_group_entries(ent)) {
1168 struct getent_state *next_ent;
1170 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
1172 /* Free state information for this domain */
1174 SAFE_FREE(ent->sam_entries);
1176 next_ent = ent->next;
1177 DLIST_REMOVE(state->getgrent_state, ent);
1179 SAFE_FREE(ent);
1180 ent = next_ent;
1183 /* No more domains */
1185 if (!ent)
1186 break;
1189 name_list = (struct acct_info *)ent->sam_entries;
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;
1198 /* Lookup group info */
1200 sid_copy(&group_sid, &domain->sid);
1201 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1203 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
1204 union unid_t id;
1205 enum lsa_SidType type;
1207 DEBUG(10, ("SID %s not in idmap\n",
1208 sid_string_dbg(&group_sid)));
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;
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;
1227 group_gid = id.gid;
1230 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1231 (unsigned long)name_list[ent->sam_entry_index].rid));
1233 /* Fill in group entry */
1235 fill_domain_username(domain_group_name, ent->domain_name,
1236 name_list[ent->sam_entry_index].acct_name, True);
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);
1243 /* Fill in group membership entry */
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;
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);
1266 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
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);
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;
1281 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1282 gr_mem_list_len, (unsigned int)gr_mem_len));
1284 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1285 gr_mem_len);
1287 SAFE_FREE(gr_mem);
1289 group_list[group_list_ndx].gr_mem_ofs =
1290 gr_mem_list_len;
1292 gr_mem_list_len += gr_mem_len;
1295 ent->sam_entry_index++;
1297 /* Add group to return list */
1299 if (result) {
1301 DEBUG(10, ("adding group num_entries = %d\n",
1302 state->response.data.num_entries));
1304 group_list_ndx++;
1305 state->response.data.num_entries++;
1307 state->response.length +=
1308 sizeof(struct winbindd_gr);
1310 } else {
1311 DEBUG(0, ("could not lookup domain group %s\n",
1312 domain_group_name));
1316 /* Copy the list of group memberships to the end of the extra data */
1318 if (group_list_ndx == 0)
1319 goto done;
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);
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;
1333 memcpy(&((char *)state->response.extra_data.data)
1334 [group_list_ndx * sizeof(struct winbindd_gr)],
1335 gr_mem_list, gr_mem_list_len);
1337 state->response.length += gr_mem_list_len;
1339 DEBUG(10, ("returning %d groups, length = %d\n",
1340 group_list_ndx, gr_mem_list_len));
1342 /* Out of domains */
1344 done:
1346 SAFE_FREE(gr_mem_list);
1348 if (group_list_ndx > 0)
1349 request_ok(state);
1350 else
1351 request_error(state);
1354 /* List domain groups without mapping to unix ids */
1355 void winbindd_list_groups(struct winbindd_cli_state *state)
1357 winbindd_list_ent(state, LIST_GROUPS);
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. */
1366 struct getgroups_state {
1367 struct winbindd_cli_state *state;
1368 struct winbindd_domain *domain;
1369 char *domname;
1370 char *username;
1371 DOM_SID user_sid;
1373 const DOM_SID *token_sids;
1374 size_t i, num_token_sids;
1376 gid_t *token_gids;
1377 size_t num_token_gids;
1380 static void getgroups_usersid_recv(void *private_data, bool success,
1381 const DOM_SID *sid, enum lsa_SidType type);
1382 static void getgroups_tokensids_recv(void *private_data, bool success,
1383 DOM_SID *token_sids, size_t num_token_sids);
1384 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1386 void winbindd_getgroups(struct winbindd_cli_state *state)
1388 struct getgroups_state *s;
1390 /* Ensure null termination */
1391 state->request.data.username
1392 [sizeof(state->request.data.username)-1]='\0';
1394 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1395 state->request.data.username));
1397 /* Parse domain and username */
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;
1406 s->state = state;
1408 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
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));
1416 /* error out if we do not have nested group support */
1418 if ( !lp_winbind_nested_groups() ) {
1419 request_error(state);
1420 return;
1423 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1424 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1427 /* Get info for the domain (either by short domain name or
1428 DNS name in the case of a UPN) */
1430 s->domain = find_domain_from_name_noinit(s->domname);
1431 if (!s->domain) {
1432 char *p = strchr(s->username, '@');
1434 if (p) {
1435 s->domain = find_domain_from_name_noinit(p+1);
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;
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;
1455 /* Get rid and name type from name. The following costs 1 packet */
1457 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1458 getgroups_usersid_recv, WINBINDD_GETGROUPS, s);
1461 static void getgroups_usersid_recv(void *private_data, bool success,
1462 const DOM_SID *sid, enum lsa_SidType type)
1464 struct getgroups_state *s =
1465 (struct getgroups_state *)private_data;
1467 if ((!success) ||
1468 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1469 request_error(s->state);
1470 return;
1473 sid_copy(&s->user_sid, sid);
1475 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1476 getgroups_tokensids_recv, s);
1479 static void getgroups_tokensids_recv(void *private_data, bool success,
1480 DOM_SID *token_sids, size_t num_token_sids)
1482 struct getgroups_state *s =
1483 (struct getgroups_state *)private_data;
1485 /* We need at least the user sid and the primary group in the token,
1486 * otherwise it's an error */
1488 if ((!success) || (num_token_sids < 2)) {
1489 request_error(s->state);
1490 return;
1493 s->token_sids = token_sids;
1494 s->num_token_sids = num_token_sids;
1495 s->i = 0;
1497 s->token_gids = NULL;
1498 s->num_token_gids = 0;
1500 getgroups_sid2gid_recv(s, False, 0);
1503 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
1505 struct getgroups_state *s =
1506 (struct getgroups_state *)private_data;
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;
1516 if (s->i < s->num_token_sids) {
1517 const DOM_SID *sid = &s->token_sids[s->i];
1518 s->i += 1;
1520 if (sid_equal(sid, &s->user_sid)) {
1521 getgroups_sid2gid_recv(s, False, 0);
1522 return;
1525 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1526 getgroups_sid2gid_recv, s);
1527 return;
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);
1536 request_ok(s->state);
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
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.
1551 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1552 size_t num_sids);
1554 void winbindd_getusersids(struct winbindd_cli_state *state)
1556 DOM_SID *user_sid;
1558 /* Ensure null termination */
1559 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
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;
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;
1575 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1576 state);
1579 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1580 size_t num_sids)
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;
1588 if (!success) {
1589 request_error(state);
1590 return;
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;
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;
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;
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);
1622 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1624 DOM_SID user_sid;
1625 struct winbindd_domain *domain;
1627 /* Ensure null termination */
1628 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
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;
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;
1645 sendto_domain(state, domain);
1648 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1649 struct winbindd_cli_state *state)
1651 DOM_SID user_sid;
1652 NTSTATUS status;
1654 char *sidstring;
1655 ssize_t len;
1656 DOM_SID *groups;
1657 uint32 num_groups;
1659 /* Ensure null termination */
1660 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
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;
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;
1674 if (num_groups == 0) {
1675 state->response.data.num_entries = 0;
1676 state->response.extra_data.data = NULL;
1677 return WINBINDD_OK;
1680 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1681 DEBUG(0, ("talloc failed\n"));
1682 return WINBINDD_ERROR;
1685 state->response.extra_data.data = SMB_STRDUP(sidstring);
1686 if (!state->response.extra_data.data) {
1687 return WINBINDD_ERROR;
1689 state->response.length += len+1;
1690 state->response.data.num_entries = num_groups;
1692 return WINBINDD_OK;