2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #define DBGC_CLASS DBGC_WINBIND
29 /***************************************************************
30 Empty static struct for negative caching.
31 ****************************************************************/
33 /* Fill a grent structure from various other information */
35 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
36 const char *gr_name, gid_t unix_gid)
38 fstring full_group_name;
40 fill_domain_username(full_group_name, dom_name, gr_name);
42 gr->gr_gid = unix_gid;
44 /* Group name and password */
46 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
47 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
52 /* Fill in the group membership field of a NT group given by group_sid */
54 static BOOL fill_grent_mem(struct winbindd_domain *domain,
56 enum SID_NAME_USE group_name_type,
57 int *num_gr_mem, char **gr_mem, int *gr_mem_len)
59 DOM_SID **sid_mem = NULL;
61 uint32 *name_types = NULL;
62 unsigned int buf_len, buf_ndx, i;
63 char **names = NULL, *buf;
69 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
72 /* Initialise group membership information */
74 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
78 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
79 ((group_name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
81 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
82 sid_to_string(sid_string, group_sid), domain->name,
87 /* Lookup group members */
88 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
89 &sid_mem, &names, &name_types);
90 if (!NT_STATUS_IS_OK(status)) {
91 DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n",
92 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
97 DEBUG(10, ("looked up %d names\n", num_names));
99 if (DEBUGLEVEL >= 10) {
100 for (i = 0; i < num_names; i++)
101 DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
105 /* Add members to list */
108 buf_len = buf_ndx = 0;
112 for (i = 0; i < num_names; i++) {
119 DEBUG(10, ("processing name %s\n", the_name));
121 /* FIXME: need to cope with groups within groups. These
122 occur in Universal groups on a Windows 2000 native mode
125 if (name_types[i] != SID_NAME_USER) {
126 DEBUG(3, ("name %s isn't a domain user\n", the_name));
130 /* Don't bother with machine accounts */
132 if (the_name[strlen(the_name) - 1] == '$') {
133 DEBUG(10, ("%s is machine account\n", the_name));
137 /* Append domain name */
139 fill_domain_username(name, domain->name, the_name);
143 /* Add to list or calculate buffer length */
146 buf_len += len + 1; /* List is comma separated */
148 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
150 DEBUG(10, ("appending %s at ndx %d\n", name, len));
151 safe_strcpy(&buf[buf_ndx], name, len);
158 /* Allocate buffer */
160 if (!buf && buf_len != 0) {
161 if (!(buf = malloc(buf_len))) {
162 DEBUG(1, ("out of memory\n"));
166 memset(buf, 0, buf_len);
170 if (buf && buf_ndx > 0) {
171 buf[buf_ndx - 1] = '\0';
175 *gr_mem_len = buf_len;
177 DEBUG(10, ("num_mem = %d, len = %d, mem = %s\n", *num_gr_mem,
178 buf_len, *num_gr_mem ? buf : "NULL"));
183 talloc_destroy(mem_ctx);
185 DEBUG(10, ("fill_grent_mem returning %d\n", result));
190 /* Return a group structure from a group name */
192 enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
195 struct winbindd_domain *domain;
196 enum SID_NAME_USE name_type;
197 fstring name_domain, name_group;
202 /* Ensure null termination */
203 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
205 DEBUG(3, ("[%5d]: getgrnam %s\n", state->pid,
206 state->request.data.groupname));
208 /* Parse domain and groupname */
210 memset(name_group, 0, sizeof(fstring));
212 tmp = state->request.data.groupname;
213 if (!parse_domain_user(tmp, name_domain, name_group))
214 return WINBINDD_ERROR;
216 /* don't handle our own domain if we are a DC. This code handles cases where
217 the account doesn't exist anywhere and gets passed on down the NSS layer */
219 if ( ((lp_server_role() == ROLE_DOMAIN_PDC) || (lp_server_role()==ROLE_DOMAIN_BDC)) &&
220 strequal(name_domain, lp_workgroup()) )
222 DEBUG(7,("winbindd_getgrnam: rejecting getpwnam() for %s\\%s since I am on the PDC for this domain\n",
223 name_domain, name_group));
224 return WINBINDD_ERROR;
227 /* Get info for the domain */
229 if ((domain = find_domain_from_name(name_domain)) == NULL) {
230 DEBUG(0, ("could not get domain sid for domain %s\n",
232 return WINBINDD_ERROR;
235 /* Get rid and name type from name */
237 if (!winbindd_lookup_sid_by_name(domain, name_group, &group_sid,
239 DEBUG(1, ("group %s in domain %s does not exist\n",
240 name_group, name_domain));
241 return WINBINDD_ERROR;
244 if ( !((name_type==SID_NAME_DOM_GRP) ||
245 ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
247 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
248 name_group, name_type));
249 return WINBINDD_ERROR;
252 if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid))) {
253 DEBUG(1, ("error converting unix gid to sid\n"));
254 return WINBINDD_ERROR;
257 if (!fill_grent(&state->response.data.gr, name_domain,
259 !fill_grent_mem(domain, &group_sid, name_type,
260 &state->response.data.gr.num_gr_mem,
261 &gr_mem, &gr_mem_len)) {
262 return WINBINDD_ERROR;
265 /* Group membership lives at start of extra data */
267 state->response.data.gr.gr_mem_ofs = 0;
269 state->response.length += gr_mem_len;
270 state->response.extra_data = gr_mem;
275 /* Return a group structure from a gid number */
277 enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
279 struct winbindd_domain *domain;
281 enum SID_NAME_USE name_type;
287 DEBUG(3, ("[%5d]: getgrgid %d\n", state->pid,
288 state->request.data.gid));
290 /* Bug out if the gid isn't in the winbind range */
292 if ((state->request.data.gid < server_state.gid_low) ||
293 (state->request.data.gid > server_state.gid_high))
294 return WINBINDD_ERROR;
296 /* Get rid from gid */
297 if (!NT_STATUS_IS_OK(gid_to_sid(&group_sid, state->request.data.gid))) {
298 DEBUG(1, ("could not convert gid %d to rid\n",
299 state->request.data.gid));
300 return WINBINDD_ERROR;
303 /* Get name from sid */
305 if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
306 DEBUG(1, ("could not lookup sid\n"));
307 return WINBINDD_ERROR;
310 /* Fill in group structure */
312 domain = find_domain_from_sid(&group_sid);
315 DEBUG(1,("Can't find domain from sid\n"));
316 return WINBINDD_ERROR;
319 if ( !((name_type==SID_NAME_DOM_GRP) ||
320 ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
322 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
323 group_name, name_type));
324 return WINBINDD_ERROR;
327 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
328 state->request.data.gid) ||
329 !fill_grent_mem(domain, &group_sid, name_type,
330 &state->response.data.gr.num_gr_mem,
331 &gr_mem, &gr_mem_len))
332 return WINBINDD_ERROR;
334 /* Group membership lives at start of extra data */
336 state->response.data.gr.gr_mem_ofs = 0;
338 state->response.length += gr_mem_len;
339 state->response.extra_data = gr_mem;
345 * set/get/endgrent functions
348 /* "Rewind" file pointer for group database enumeration */
350 enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
352 struct winbindd_domain *domain;
354 DEBUG(3, ("[%5d]: setgrent\n", state->pid));
356 /* Check user has enabled this */
358 if (!lp_winbind_enum_groups())
359 return WINBINDD_ERROR;
361 /* Free old static data if it exists */
363 if (state->getgrent_state != NULL) {
364 free_getent_state(state->getgrent_state);
365 state->getgrent_state = NULL;
368 /* Create sam pipes for each domain we know about */
370 for (domain = domain_list(); domain != NULL; domain = domain->next) {
371 struct getent_state *domain_state;
373 /* Create a state record for this domain */
375 if ((domain_state = (struct getent_state *)
376 malloc(sizeof(struct getent_state))) == NULL) {
377 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
378 return WINBINDD_ERROR;
381 ZERO_STRUCTP(domain_state);
383 fstrcpy(domain_state->domain_name, domain->name);
385 /* Add to list of open domains */
387 DLIST_ADD(state->getgrent_state, domain_state);
393 /* Close file pointer to ntdom group database */
395 enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
397 DEBUG(3, ("[%5d]: endgrent\n", state->pid));
399 free_getent_state(state->getgrent_state);
400 state->getgrent_state = NULL;
405 /* Get the list of domain groups and domain aliases for a domain. We fill in
406 the sam_entries and num_sam_entries fields with domain group information.
407 The dispinfo_ndx field is incremented to the index of the next group to
408 fetch. Return True if some groups were returned, False otherwise. */
410 #define MAX_FETCH_SAM_ENTRIES 100
412 static BOOL get_sam_group_entries(struct getent_state *ent)
416 struct acct_info *name_list = NULL, *tmp_name_list = NULL;
419 struct acct_info *sam_grp_entries = NULL;
420 struct winbindd_domain *domain;
422 if (ent->got_sam_entries)
425 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
426 ent->domain_name))) {
427 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
431 /* Free any existing group info */
433 SAFE_FREE(ent->sam_entries);
434 ent->num_sam_entries = 0;
435 ent->got_sam_entries = True;
437 /* Enumerate domain groups */
441 if (!(domain = find_domain_from_name(ent->domain_name))) {
442 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
446 /* always get the domain global groups */
448 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
456 /* Copy entries into return buffer */
459 if ( !(name_list = malloc(sizeof(struct acct_info) * num_entries)) ) {
460 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
465 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
468 ent->num_sam_entries = num_entries;
470 /* get the domain local groups if we are a member of a native win2k domain
471 and are not using LDAP to get the groups */
473 if ( lp_security() != SEC_ADS && domain->native_mode
474 && strequal(lp_workgroup(), domain->name) )
476 DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
478 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
480 if ( !NT_STATUS_IS_OK(status) ) {
481 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
485 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
487 /* Copy entries into return buffer */
490 if ( !(tmp_name_list = Realloc( name_list, sizeof(struct acct_info) * (ent->num_sam_entries+num_entries))) )
492 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
495 SAFE_FREE( name_list );
499 name_list = tmp_name_list;
501 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
502 num_entries * sizeof(struct acct_info) );
505 ent->num_sam_entries += num_entries;
509 /* Fill in remaining fields */
511 ent->sam_entries = name_list;
512 ent->sam_entry_index = 0;
514 result = (ent->num_sam_entries > 0);
517 talloc_destroy(mem_ctx);
522 /* Fetch next group entry from ntdom database */
524 #define MAX_GETGRENT_GROUPS 500
526 enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
528 struct getent_state *ent;
529 struct winbindd_gr *group_list = NULL;
530 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
531 char *new_extra_data, *gr_mem_list = NULL;
533 DEBUG(3, ("[%5d]: getgrent\n", state->pid));
535 /* Check user has enabled this */
537 if (!lp_winbind_enum_groups())
538 return WINBINDD_ERROR;
540 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
542 if ((state->response.extra_data =
543 malloc(num_groups * sizeof(struct winbindd_gr))) == NULL)
544 return WINBINDD_ERROR;
546 state->response.data.num_entries = 0;
548 group_list = (struct winbindd_gr *)state->response.extra_data;
550 if (!(ent = state->getgrent_state))
551 return WINBINDD_ERROR;
553 /* Start sending back groups */
555 for (i = 0; i < num_groups; i++) {
556 struct acct_info *name_list = NULL;
557 fstring domain_group_name;
561 char *gr_mem, *new_gr_mem_list;
563 struct winbindd_domain *domain;
565 /* Do we need to fetch another chunk of groups? */
569 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
570 ent->sam_entry_index, ent->num_sam_entries));
572 if (ent->num_sam_entries == ent->sam_entry_index) {
574 while(ent && !get_sam_group_entries(ent)) {
575 struct getent_state *next_ent;
577 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
579 /* Free state information for this domain */
581 SAFE_FREE(ent->sam_entries);
583 next_ent = ent->next;
584 DLIST_REMOVE(state->getgrent_state, ent);
590 /* No more domains */
596 name_list = ent->sam_entries;
599 find_domain_from_name(ent->domain_name))) {
600 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
605 /* Lookup group info */
607 sid_copy(&group_sid, &domain->sid);
608 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
610 if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &group_gid))) {
612 DEBUG(1, ("could not look up gid for group %s\n",
613 name_list[ent->sam_entry_index].acct_name));
615 ent->sam_entry_index++;
619 DEBUG(10, ("got gid %d for group %x\n", group_gid,
620 name_list[ent->sam_entry_index].rid));
622 /* Fill in group entry */
624 fill_domain_username(domain_group_name, ent->domain_name,
625 name_list[ent->sam_entry_index].acct_name);
627 result = fill_grent(&group_list[group_list_ndx],
629 name_list[ent->sam_entry_index].acct_name,
632 /* Fill in group membership entry */
636 group_list[group_list_ndx].num_gr_mem = 0;
640 /* Get group membership */
641 if (state->request.cmd == WINBINDD_GETGRLST) {
644 sid_copy(&member_sid, &domain->sid);
645 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
646 result = fill_grent_mem(
650 &group_list[group_list_ndx].num_gr_mem,
651 &gr_mem, &gr_mem_len);
656 /* Append to group membership list */
657 new_gr_mem_list = Realloc(
659 gr_mem_list_len + gr_mem_len);
661 if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
662 DEBUG(0, ("out of memory\n"));
663 SAFE_FREE(gr_mem_list);
668 DEBUG(10, ("list_len = %d, mem_len = %d\n",
669 gr_mem_list_len, gr_mem_len));
671 gr_mem_list = new_gr_mem_list;
673 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
678 group_list[group_list_ndx].gr_mem_ofs =
681 gr_mem_list_len += gr_mem_len;
684 ent->sam_entry_index++;
686 /* Add group to return list */
690 DEBUG(10, ("adding group num_entries = %d\n",
691 state->response.data.num_entries));
694 state->response.data.num_entries++;
696 state->response.length +=
697 sizeof(struct winbindd_gr);
700 DEBUG(0, ("could not lookup domain group %s\n",
705 /* Copy the list of group memberships to the end of the extra data */
707 if (group_list_ndx == 0)
710 new_extra_data = Realloc(
711 state->response.extra_data,
712 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
714 if (!new_extra_data) {
715 DEBUG(0, ("out of memory\n"));
717 SAFE_FREE(state->response.extra_data);
718 SAFE_FREE(gr_mem_list);
720 return WINBINDD_ERROR;
723 state->response.extra_data = new_extra_data;
725 memcpy(&((char *)state->response.extra_data)
726 [group_list_ndx * sizeof(struct winbindd_gr)],
727 gr_mem_list, gr_mem_list_len);
729 SAFE_FREE(gr_mem_list);
731 state->response.length += gr_mem_list_len;
733 DEBUG(10, ("returning %d groups, length = %d\n",
734 group_list_ndx, gr_mem_list_len));
740 return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
743 /* List domain groups without mapping to unix ids */
745 enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
747 uint32 total_entries = 0;
748 struct winbindd_domain *domain;
749 char *extra_data = NULL;
751 unsigned int extra_data_len = 0, i;
753 DEBUG(3, ("[%5d]: list groups\n", state->pid));
755 /* Enumerate over trusted domains */
757 for (domain = domain_list(); domain; domain = domain->next) {
758 struct getent_state groups;
762 /* Get list of sam groups */
764 fstrcpy(groups.domain_name, domain->name);
766 get_sam_group_entries(&groups);
768 if (groups.num_sam_entries == 0) {
769 /* this domain is empty or in an error state */
773 /* keep track the of the total number of groups seen so
774 far over all domains */
775 total_entries += groups.num_sam_entries;
777 /* Allocate some memory for extra data. Note that we limit
778 account names to sizeof(fstring) = 128 characters. */
779 ted = Realloc(extra_data, sizeof(fstring) * total_entries);
782 DEBUG(0,("failed to enlarge buffer!\n"));
783 SAFE_FREE(extra_data);
784 return WINBINDD_ERROR;
788 /* Pack group list into extra data fields */
789 for (i = 0; i < groups.num_sam_entries; i++) {
790 char *group_name = ((struct acct_info *)
791 groups.sam_entries)[i].acct_name;
794 fill_domain_username(name, domain->name, group_name);
795 /* Append to extra data */
796 memcpy(&extra_data[extra_data_len], name,
798 extra_data_len += strlen(name);
799 extra_data[extra_data_len++] = ',';
802 free(groups.sam_entries);
805 /* Assign extra_data fields in response structure */
807 extra_data[extra_data_len - 1] = '\0';
808 state->response.extra_data = extra_data;
809 state->response.length += extra_data_len;
812 /* No domains may have responded but that's still OK so don't
818 /* Get user supplementary groups. This is much quicker than trying to
819 invert the groups database. We merge the groups from the gids and
820 other_sids info3 fields as trusted domain, universal group
821 memberships, and nested groups (win2k native mode only) are not
822 returned by the getgroups RPC call but are present in the info3. */
824 enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
826 fstring name_domain, name_user;
827 DOM_SID user_sid, group_sid;
828 enum SID_NAME_USE name_type;
829 uint32 num_groups = 0;
832 DOM_SID **user_grpsids;
833 struct winbindd_domain *domain;
834 enum winbindd_result result = WINBINDD_ERROR;
838 NET_USER_INFO_3 *info3 = NULL;
840 /* Ensure null termination */
841 state->request.data.username[sizeof(state->request.data.username)-1]='\0';
843 DEBUG(3, ("[%5d]: getgroups %s\n", state->pid,
844 state->request.data.username));
846 if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
847 state->request.data.username)))
848 return WINBINDD_ERROR;
850 /* Parse domain and username */
852 if (!parse_domain_user(state->request.data.username, name_domain,
856 /* Get info for the domain */
858 if ((domain = find_domain_from_name(name_domain)) == NULL) {
859 DEBUG(0, ("could not find domain entry for domain %s\n",
864 /* Get rid and name type from name. The following costs 1 packet */
866 if (!winbindd_lookup_sid_by_name(domain, name_user, &user_sid,
868 DEBUG(1, ("user '%s' does not exist\n", name_user));
872 if (name_type != SID_NAME_USER) {
873 DEBUG(1, ("name '%s' is not a user name: %d\n",
874 name_user, name_type));
878 /* Treat the info3 cache as authoritative as the
879 lookup_usergroups() function may return cached data. */
881 if ((info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) {
883 DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n",
884 info3->num_groups2, info3->num_other_sids));
886 num_groups = info3->num_other_sids + info3->num_groups2;
887 gid_list = calloc(sizeof(gid_t), num_groups);
889 /* Go through each other sid and convert it to a gid */
891 for (i = 0; i < info3->num_other_sids; i++) {
894 enum SID_NAME_USE sid_type;
896 /* Is this sid known to us? It can either be
897 a trusted domain sid or a foreign sid. */
899 if (!winbindd_lookup_name_by_sid( &info3->other_sids[i].sid,
900 dom_name, name, &sid_type))
902 DEBUG(10, ("winbindd_getgroups: could not lookup name for %s\n",
903 sid_string_static(&info3->other_sids[i].sid)));
907 /* Check it is a domain group or an alias (domain local group)
908 in a win2k native mode domain. */
910 if ( !((sid_type==SID_NAME_DOM_GRP) ||
911 ((sid_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
913 DEBUG(10, ("winbindd_getgroups: sid type %d "
914 "for %s is not a domain group\n",
917 &info3->other_sids[i].sid)));
923 if (!NT_STATUS_IS_OK(sid_to_gid(&info3->other_sids[i].sid,
924 &gid_list[num_gids])) )
926 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
927 sid_string_static(&info3->other_sids[i].sid)));
931 /* We've jumped through a lot of hoops to get here */
933 DEBUG(10, ("winbindd_getgroups: mapped other sid %s to "
934 "gid %d\n", sid_string_static(
935 &info3->other_sids[i].sid),
936 gid_list[num_gids]));
941 for (i = 0; i < info3->num_groups2; i++) {
943 /* create the group SID */
945 sid_copy( &group_sid, &domain->sid );
946 sid_append_rid( &group_sid, info3->gids[i].g_rid );
948 if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid_list[num_gids])) ) {
949 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
950 sid_string_static(&group_sid)));
959 status = domain->methods->lookup_usergroups(domain, mem_ctx,
960 &user_sid, &num_groups,
962 if (!NT_STATUS_IS_OK(status))
965 gid_list = malloc(sizeof(gid_t) * num_groups);
967 if (state->response.extra_data)
970 for (i = 0; i < num_groups; i++) {
971 if (!NT_STATUS_IS_OK(sid_to_gid(user_grpsids[i], &gid_list[num_gids]))) {
972 DEBUG(1, ("unable to convert group sid %s to gid\n",
973 sid_string_static(user_grpsids[i])));
980 /* Send data back to client */
982 state->response.data.num_entries = num_gids;
983 state->response.extra_data = gid_list;
984 state->response.length += num_gids * sizeof(gid_t);
986 result = WINBINDD_OK;
990 talloc_destroy(mem_ctx);