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.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #define DBGC_CLASS DBGC_WINBIND
30 /***************************************************************
31 Empty static struct for negative caching.
32 ****************************************************************/
34 /* Fill a grent structure from various other information */
36 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
37 const char *gr_name, gid_t unix_gid)
39 fstring full_group_name;
41 fill_domain_username(full_group_name, dom_name, gr_name);
43 gr->gr_gid = unix_gid;
45 /* Group name and password */
47 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
48 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
53 /* Fill in the group membership field of a NT group given by group_sid */
55 static BOOL fill_grent_mem(struct winbindd_domain *domain,
57 enum SID_NAME_USE group_name_type,
58 int *num_gr_mem, char **gr_mem, int *gr_mem_len)
60 DOM_SID **sid_mem = NULL;
62 uint32 *name_types = NULL;
63 unsigned int buf_len, buf_ndx, i;
64 char **names = NULL, *buf;
70 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
73 /* Initialise group membership information */
75 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
79 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
80 ((group_name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
82 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
83 sid_to_string(sid_string, group_sid), domain->name,
88 /* Lookup group members */
89 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
90 &sid_mem, &names, &name_types);
91 if (!NT_STATUS_IS_OK(status)) {
92 DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n",
93 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
98 DEBUG(10, ("looked up %d names\n", num_names));
100 if (DEBUGLEVEL >= 10) {
101 for (i = 0; i < num_names; i++)
102 DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
106 /* Add members to list */
109 buf_len = buf_ndx = 0;
113 for (i = 0; i < num_names; i++) {
120 DEBUG(10, ("processing name %s\n", the_name));
122 /* FIXME: need to cope with groups within groups. These
123 occur in Universal groups on a Windows 2000 native mode
126 if (name_types[i] != SID_NAME_USER) {
127 DEBUG(3, ("name %s isn't a domain user\n", the_name));
131 /* Don't bother with machine accounts */
133 if (the_name[strlen(the_name) - 1] == '$') {
134 DEBUG(10, ("%s is machine account\n", the_name));
138 /* Append domain name */
140 fill_domain_username(name, domain->name, the_name);
144 /* Add to list or calculate buffer length */
147 buf_len += len + 1; /* List is comma separated */
149 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
151 DEBUG(10, ("appending %s at ndx %d\n", name, len));
152 safe_strcpy(&buf[buf_ndx], name, len);
159 /* Allocate buffer */
161 if (!buf && buf_len != 0) {
162 if (!(buf = malloc(buf_len))) {
163 DEBUG(1, ("out of memory\n"));
167 memset(buf, 0, buf_len);
171 if (buf && buf_ndx > 0) {
172 buf[buf_ndx - 1] = '\0';
176 *gr_mem_len = buf_len;
178 DEBUG(10, ("num_mem = %d, len = %d, mem = %s\n", *num_gr_mem,
179 buf_len, *num_gr_mem ? buf : "NULL"));
184 talloc_destroy(mem_ctx);
186 DEBUG(10, ("fill_grent_mem returning %d\n", result));
191 /* Return a group structure from a group name */
193 enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
196 struct winbindd_domain *domain;
197 enum SID_NAME_USE name_type;
198 fstring name_domain, name_group;
203 /* Ensure null termination */
204 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
206 DEBUG(3, ("[%5d]: getgrnam %s\n", state->pid,
207 state->request.data.groupname));
209 /* Parse domain and groupname */
211 memset(name_group, 0, sizeof(fstring));
213 tmp = state->request.data.groupname;
214 if (!parse_domain_user(tmp, name_domain, name_group))
215 return WINBINDD_ERROR;
217 /* don't handle our own domain if we are a DC. This code handles cases where
218 the account doesn't exist anywhere and gets passed on down the NSS layer */
220 if ( IS_DC_FOR_DOMAIN(domain->name) ) {
221 DEBUG(7,("winbindd_getgrnam: rejecting getpwnam() for %s\\%s since I am on the PDC for this domain\n",
222 name_domain, name_group));
223 return WINBINDD_ERROR;
226 /* Get info for the domain */
228 if ((domain = find_domain_from_name(name_domain)) == NULL) {
229 DEBUG(0, ("could not get domain sid for domain %s\n",
231 return WINBINDD_ERROR;
234 /* Get rid and name type from name */
236 if (!winbindd_lookup_sid_by_name(domain, name_group, &group_sid,
238 DEBUG(1, ("group %s in domain %s does not exist\n",
239 name_group, name_domain));
240 return WINBINDD_ERROR;
243 if ( !((name_type==SID_NAME_DOM_GRP) ||
244 ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
246 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
247 name_group, name_type));
248 return WINBINDD_ERROR;
251 if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid))) {
252 DEBUG(1, ("error converting unix gid to sid\n"));
253 return WINBINDD_ERROR;
256 if (!fill_grent(&state->response.data.gr, name_domain,
258 !fill_grent_mem(domain, &group_sid, name_type,
259 &state->response.data.gr.num_gr_mem,
260 &gr_mem, &gr_mem_len)) {
261 return WINBINDD_ERROR;
264 /* Group membership lives at start of extra data */
266 state->response.data.gr.gr_mem_ofs = 0;
268 state->response.length += gr_mem_len;
269 state->response.extra_data = gr_mem;
274 /* Return a group structure from a gid number */
276 enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
278 struct winbindd_domain *domain;
280 enum SID_NAME_USE name_type;
286 DEBUG(3, ("[%5d]: getgrgid %d\n", state->pid,
287 state->request.data.gid));
289 /* Bug out if the gid isn't in the winbind range */
291 if ((state->request.data.gid < server_state.gid_low) ||
292 (state->request.data.gid > server_state.gid_high))
293 return WINBINDD_ERROR;
295 /* Get rid from gid */
296 if (!NT_STATUS_IS_OK(gid_to_sid(&group_sid, state->request.data.gid))) {
297 DEBUG(1, ("could not convert gid %d to rid\n",
298 state->request.data.gid));
299 return WINBINDD_ERROR;
302 /* Get name from sid */
304 if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
305 DEBUG(1, ("could not lookup sid\n"));
306 return WINBINDD_ERROR;
309 /* Fill in group structure */
311 domain = find_domain_from_sid(&group_sid);
314 DEBUG(1,("Can't find domain from sid\n"));
315 return WINBINDD_ERROR;
318 if ( !((name_type==SID_NAME_DOM_GRP) ||
319 ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
321 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
322 group_name, name_type));
323 return WINBINDD_ERROR;
326 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
327 state->request.data.gid) ||
328 !fill_grent_mem(domain, &group_sid, name_type,
329 &state->response.data.gr.num_gr_mem,
330 &gr_mem, &gr_mem_len))
331 return WINBINDD_ERROR;
333 /* Group membership lives at start of extra data */
335 state->response.data.gr.gr_mem_ofs = 0;
337 state->response.length += gr_mem_len;
338 state->response.extra_data = gr_mem;
344 * set/get/endgrent functions
347 /* "Rewind" file pointer for group database enumeration */
349 enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
351 struct winbindd_domain *domain;
353 DEBUG(3, ("[%5d]: setgrent\n", state->pid));
355 /* Check user has enabled this */
357 if (!lp_winbind_enum_groups())
358 return WINBINDD_ERROR;
360 /* Free old static data if it exists */
362 if (state->getgrent_state != NULL) {
363 free_getent_state(state->getgrent_state);
364 state->getgrent_state = NULL;
367 /* Create sam pipes for each domain we know about */
369 for (domain = domain_list(); domain != NULL; domain = domain->next) {
370 struct getent_state *domain_state;
373 /* don't add our domaina if we are a PDC */
375 if ( IS_DC_FOR_DOMAIN(domain->name) )
378 /* Create a state record for this domain */
380 if ((domain_state = (struct getent_state *)
381 malloc(sizeof(struct getent_state))) == NULL) {
382 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
383 return WINBINDD_ERROR;
386 ZERO_STRUCTP(domain_state);
388 fstrcpy(domain_state->domain_name, domain->name);
390 /* Add to list of open domains */
392 DLIST_ADD(state->getgrent_state, domain_state);
398 /* Close file pointer to ntdom group database */
400 enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
402 DEBUG(3, ("[%5d]: endgrent\n", state->pid));
404 free_getent_state(state->getgrent_state);
405 state->getgrent_state = NULL;
410 /* Get the list of domain groups and domain aliases for a domain. We fill in
411 the sam_entries and num_sam_entries fields with domain group information.
412 The dispinfo_ndx field is incremented to the index of the next group to
413 fetch. Return True if some groups were returned, False otherwise. */
415 #define MAX_FETCH_SAM_ENTRIES 100
417 static BOOL get_sam_group_entries(struct getent_state *ent)
421 struct acct_info *name_list = NULL, *tmp_name_list = NULL;
424 struct acct_info *sam_grp_entries = NULL;
425 struct winbindd_domain *domain;
427 if (ent->got_sam_entries)
430 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
431 ent->domain_name))) {
432 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
436 /* Free any existing group info */
438 SAFE_FREE(ent->sam_entries);
439 ent->num_sam_entries = 0;
440 ent->got_sam_entries = True;
442 /* Enumerate domain groups */
446 if (!(domain = find_domain_from_name(ent->domain_name))) {
447 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
451 /* always get the domain global groups */
453 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
455 if (!NT_STATUS_IS_OK(status)) {
456 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
461 /* Copy entries into return buffer */
464 if ( !(name_list = malloc(sizeof(struct acct_info) * num_entries)) ) {
465 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
470 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
473 ent->num_sam_entries = num_entries;
475 /* get the domain local groups if we are a member of a native win2k domain
476 and are not using LDAP to get the groups */
478 if ( lp_security() != SEC_ADS && domain->native_mode
479 && strequal(lp_workgroup(), domain->name) )
481 DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
483 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
485 if ( !NT_STATUS_IS_OK(status) ) {
486 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
490 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
492 /* Copy entries into return buffer */
495 if ( !(tmp_name_list = Realloc( name_list, sizeof(struct acct_info) * (ent->num_sam_entries+num_entries))) )
497 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
500 SAFE_FREE( name_list );
504 name_list = tmp_name_list;
506 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
507 num_entries * sizeof(struct acct_info) );
510 ent->num_sam_entries += num_entries;
514 /* Fill in remaining fields */
516 ent->sam_entries = name_list;
517 ent->sam_entry_index = 0;
519 result = (ent->num_sam_entries > 0);
522 talloc_destroy(mem_ctx);
527 /* Fetch next group entry from ntdom database */
529 #define MAX_GETGRENT_GROUPS 500
531 enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
533 struct getent_state *ent;
534 struct winbindd_gr *group_list = NULL;
535 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
536 char *new_extra_data, *gr_mem_list = NULL;
538 DEBUG(3, ("[%5d]: getgrent\n", state->pid));
540 /* Check user has enabled this */
542 if (!lp_winbind_enum_groups())
543 return WINBINDD_ERROR;
545 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
547 if ((state->response.extra_data =
548 malloc(num_groups * sizeof(struct winbindd_gr))) == NULL)
549 return WINBINDD_ERROR;
551 state->response.data.num_entries = 0;
553 group_list = (struct winbindd_gr *)state->response.extra_data;
555 if (!(ent = state->getgrent_state))
556 return WINBINDD_ERROR;
558 /* Start sending back groups */
560 for (i = 0; i < num_groups; i++) {
561 struct acct_info *name_list = NULL;
562 fstring domain_group_name;
566 char *gr_mem, *new_gr_mem_list;
568 struct winbindd_domain *domain;
570 /* Do we need to fetch another chunk of groups? */
574 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
575 ent->sam_entry_index, ent->num_sam_entries));
577 if (ent->num_sam_entries == ent->sam_entry_index) {
579 while(ent && !get_sam_group_entries(ent)) {
580 struct getent_state *next_ent;
582 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
584 /* Free state information for this domain */
586 SAFE_FREE(ent->sam_entries);
588 next_ent = ent->next;
589 DLIST_REMOVE(state->getgrent_state, ent);
595 /* No more domains */
601 name_list = ent->sam_entries;
604 find_domain_from_name(ent->domain_name))) {
605 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
610 /* Lookup group info */
612 sid_copy(&group_sid, &domain->sid);
613 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
615 if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &group_gid))) {
617 DEBUG(1, ("could not look up gid for group %s\n",
618 name_list[ent->sam_entry_index].acct_name));
620 ent->sam_entry_index++;
624 DEBUG(10, ("got gid %d for group %x\n", group_gid,
625 name_list[ent->sam_entry_index].rid));
627 /* Fill in group entry */
629 fill_domain_username(domain_group_name, ent->domain_name,
630 name_list[ent->sam_entry_index].acct_name);
632 result = fill_grent(&group_list[group_list_ndx],
634 name_list[ent->sam_entry_index].acct_name,
637 /* Fill in group membership entry */
641 group_list[group_list_ndx].num_gr_mem = 0;
645 /* Get group membership */
646 if (state->request.cmd == WINBINDD_GETGRLST) {
649 sid_copy(&member_sid, &domain->sid);
650 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
651 result = fill_grent_mem(
655 &group_list[group_list_ndx].num_gr_mem,
656 &gr_mem, &gr_mem_len);
661 /* Append to group membership list */
662 new_gr_mem_list = Realloc(
664 gr_mem_list_len + gr_mem_len);
666 if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
667 DEBUG(0, ("out of memory\n"));
668 SAFE_FREE(gr_mem_list);
673 DEBUG(10, ("list_len = %d, mem_len = %d\n",
674 gr_mem_list_len, gr_mem_len));
676 gr_mem_list = new_gr_mem_list;
678 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
683 group_list[group_list_ndx].gr_mem_ofs =
686 gr_mem_list_len += gr_mem_len;
689 ent->sam_entry_index++;
691 /* Add group to return list */
695 DEBUG(10, ("adding group num_entries = %d\n",
696 state->response.data.num_entries));
699 state->response.data.num_entries++;
701 state->response.length +=
702 sizeof(struct winbindd_gr);
705 DEBUG(0, ("could not lookup domain group %s\n",
710 /* Copy the list of group memberships to the end of the extra data */
712 if (group_list_ndx == 0)
715 new_extra_data = Realloc(
716 state->response.extra_data,
717 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
719 if (!new_extra_data) {
720 DEBUG(0, ("out of memory\n"));
722 SAFE_FREE(state->response.extra_data);
723 SAFE_FREE(gr_mem_list);
725 return WINBINDD_ERROR;
728 state->response.extra_data = new_extra_data;
730 memcpy(&((char *)state->response.extra_data)
731 [group_list_ndx * sizeof(struct winbindd_gr)],
732 gr_mem_list, gr_mem_list_len);
734 SAFE_FREE(gr_mem_list);
736 state->response.length += gr_mem_list_len;
738 DEBUG(10, ("returning %d groups, length = %d\n",
739 group_list_ndx, gr_mem_list_len));
745 return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
748 /* List domain groups without mapping to unix ids */
750 enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
752 uint32 total_entries = 0;
753 struct winbindd_domain *domain;
754 char *extra_data = NULL;
756 unsigned int extra_data_len = 0, i;
758 DEBUG(3, ("[%5d]: list groups\n", state->pid));
760 /* Enumerate over trusted domains */
762 for (domain = domain_list(); domain; domain = domain->next) {
763 struct getent_state groups;
767 /* Get list of sam groups */
769 fstrcpy(groups.domain_name, domain->name);
771 get_sam_group_entries(&groups);
773 if (groups.num_sam_entries == 0) {
774 /* this domain is empty or in an error state */
778 /* keep track the of the total number of groups seen so
779 far over all domains */
780 total_entries += groups.num_sam_entries;
782 /* Allocate some memory for extra data. Note that we limit
783 account names to sizeof(fstring) = 128 characters. */
784 ted = Realloc(extra_data, sizeof(fstring) * total_entries);
787 DEBUG(0,("failed to enlarge buffer!\n"));
788 SAFE_FREE(extra_data);
789 return WINBINDD_ERROR;
793 /* Pack group list into extra data fields */
794 for (i = 0; i < groups.num_sam_entries; i++) {
795 char *group_name = ((struct acct_info *)
796 groups.sam_entries)[i].acct_name;
799 fill_domain_username(name, domain->name, group_name);
800 /* Append to extra data */
801 memcpy(&extra_data[extra_data_len], name,
803 extra_data_len += strlen(name);
804 extra_data[extra_data_len++] = ',';
807 free(groups.sam_entries);
810 /* Assign extra_data fields in response structure */
812 extra_data[extra_data_len - 1] = '\0';
813 state->response.extra_data = extra_data;
814 state->response.length += extra_data_len;
817 /* No domains may have responded but that's still OK so don't
823 /* Get user supplementary groups. This is much quicker than trying to
824 invert the groups database. We merge the groups from the gids and
825 other_sids info3 fields as trusted domain, universal group
826 memberships, and nested groups (win2k native mode only) are not
827 returned by the getgroups RPC call but are present in the info3. */
829 enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
831 fstring name_domain, name_user;
832 DOM_SID user_sid, group_sid;
833 enum SID_NAME_USE name_type;
834 uint32 num_groups = 0;
837 DOM_SID **user_grpsids;
838 struct winbindd_domain *domain;
839 enum winbindd_result result = WINBINDD_ERROR;
843 NET_USER_INFO_3 *info3 = NULL;
845 /* Ensure null termination */
846 state->request.data.username[sizeof(state->request.data.username)-1]='\0';
848 DEBUG(3, ("[%5d]: getgroups %s\n", state->pid,
849 state->request.data.username));
851 if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
852 state->request.data.username)))
853 return WINBINDD_ERROR;
855 /* Parse domain and username */
857 if (!parse_domain_user(state->request.data.username, name_domain,
861 /* Get info for the domain */
863 if ((domain = find_domain_from_name(name_domain)) == NULL) {
864 DEBUG(0, ("could not find domain entry for domain %s\n",
869 /* Get rid and name type from name. The following costs 1 packet */
871 if (!winbindd_lookup_sid_by_name(domain, name_user, &user_sid,
873 DEBUG(1, ("user '%s' does not exist\n", name_user));
877 if (name_type != SID_NAME_USER) {
878 DEBUG(1, ("name '%s' is not a user name: %d\n",
879 name_user, name_type));
883 /* Treat the info3 cache as authoritative as the
884 lookup_usergroups() function may return cached data. */
886 if ((info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) {
888 DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n",
889 info3->num_groups2, info3->num_other_sids));
891 num_groups = info3->num_other_sids + info3->num_groups2;
892 gid_list = calloc(sizeof(gid_t), num_groups);
894 /* Go through each other sid and convert it to a gid */
896 for (i = 0; i < info3->num_other_sids; i++) {
899 enum SID_NAME_USE sid_type;
901 /* Is this sid known to us? It can either be
902 a trusted domain sid or a foreign sid. */
904 if (!winbindd_lookup_name_by_sid( &info3->other_sids[i].sid,
905 dom_name, name, &sid_type))
907 DEBUG(10, ("winbindd_getgroups: could not lookup name for %s\n",
908 sid_string_static(&info3->other_sids[i].sid)));
912 /* Check it is a domain group or an alias (domain local group)
913 in a win2k native mode domain. */
915 if ( !((sid_type==SID_NAME_DOM_GRP) ||
916 ((sid_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
918 DEBUG(10, ("winbindd_getgroups: sid type %d "
919 "for %s is not a domain group\n",
922 &info3->other_sids[i].sid)));
928 if (!NT_STATUS_IS_OK(sid_to_gid(&info3->other_sids[i].sid,
929 &gid_list[num_gids])) )
931 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
932 sid_string_static(&info3->other_sids[i].sid)));
936 /* We've jumped through a lot of hoops to get here */
938 DEBUG(10, ("winbindd_getgroups: mapped other sid %s to "
939 "gid %d\n", sid_string_static(
940 &info3->other_sids[i].sid),
941 gid_list[num_gids]));
946 for (i = 0; i < info3->num_groups2; i++) {
948 /* create the group SID */
950 sid_copy( &group_sid, &domain->sid );
951 sid_append_rid( &group_sid, info3->gids[i].g_rid );
953 if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid_list[num_gids])) ) {
954 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
955 sid_string_static(&group_sid)));
964 status = domain->methods->lookup_usergroups(domain, mem_ctx,
965 &user_sid, &num_groups,
967 if (!NT_STATUS_IS_OK(status))
970 gid_list = malloc(sizeof(gid_t) * num_groups);
972 if (state->response.extra_data)
975 for (i = 0; i < num_groups; i++) {
976 if (!NT_STATUS_IS_OK(sid_to_gid(user_grpsids[i], &gid_list[num_gids]))) {
977 DEBUG(1, ("unable to convert group sid %s to gid\n",
978 sid_string_static(user_grpsids[i])));
985 /* Send data back to client */
987 state->response.data.num_entries = num_gids;
988 state->response.extra_data = gid_list;
989 state->response.length += num_gids * sizeof(gid_t);
991 result = WINBINDD_OK;
995 talloc_destroy(mem_ctx);