2 Unix SMB/Netbios implementation.
5 Winbind daemon for ntdom nss module
7 Copyright (C) Tim Potter 2000
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.
26 /* Fill a grent structure from various other information */
28 static BOOL
fill_grent(struct winbindd_gr
*gr
, char *gr_name
,
33 gr
->gr_gid
= unix_gid
;
35 /* Group name and password */
37 safe_strcpy(gr
->gr_name
, gr_name
, sizeof(gr
->gr_name
) - 1);
38 safe_strcpy(gr
->gr_passwd
, "x", sizeof(gr
->gr_passwd
) - 1);
43 /* Fill in the group membership field of a NT group given by group_rid */
45 static BOOL
fill_grent_mem(struct winbindd_domain
*domain
,
47 enum SID_NAME_USE group_name_type
,
48 int *num_gr_mem
, char **gr_mem
, int *gr_mem_len
)
50 uint32
*rid_mem
= NULL
, num_names
= 0;
51 enum SID_NAME_USE
*name_types
= NULL
;
52 int buf_len
, buf_ndx
, i
;
53 char **names
= NULL
, *buf
;
56 if (!num_gr_mem
|| !gr_mem
|| !gr_mem_len
) return False
;
58 /* Initialise group membership information */
60 DEBUG(10, ("fill_grent_mem(): group %s rid 0x%x\n",
61 domain
? domain
->name
: "NULL", group_rid
));
65 if (group_name_type
!= SID_NAME_DOM_GRP
) {
66 DEBUG(1, ("fill_grent_mem(): rid %d in domain %s isn't a "
67 "domain group\n", group_rid
, domain
->name
));
71 /* Lookup group members */
73 if (!winbindd_lookup_groupmem(domain
, group_rid
, &num_names
,
74 &rid_mem
, &names
, &name_types
)) {
76 DEBUG(1, ("fill_grent_mem(): could not lookup membership "
77 "for group rid %d in domain %s\n",
78 group_rid
, domain
->name
));
83 DEBUG(10, ("fill_grent_mem(): looked up %d names\n", num_names
));
85 if (DEBUGLEVEL
>= 10) {
86 for (i
= 0; i
< num_names
; i
++) {
87 DEBUG(10, ("\t%20s %x %d\n", names
[i
], rid_mem
[i
],
92 /* Add members to list */
95 buf_len
= buf_ndx
= 0;
99 for (i
= 0; i
< num_names
; i
++) {
106 DEBUG(10, ("fill_grent_mem(): processing name %s\n", the_name
));
108 /* Only add domain users */
110 if (name_types
[i
] != SID_NAME_USER
) {
111 DEBUG(3, ("fill_grent_mem(): name %s isn't a domain "
112 "user\n", the_name
));
116 /* Don't bother with machine accounts */
118 if (the_name
[strlen(the_name
) - 1] == '$') {
119 DEBUG(10, ("fill_grent_mem(): %s is machine account\n",
124 /* Append domain name */
126 snprintf(name
, sizeof(name
), "%s%s%s", domain
->name
,
127 lp_winbind_separator(), the_name
);
131 /* Add to list or calculate buffer length */
134 buf_len
+= len
+ 1; /* List is comma separated */
136 DEBUG(10, ("fill_grent_mem(): buf_len + %d = %d\n", len
+ 1,
139 DEBUG(10, ("fill_grent_mem(): appending %s at index %d\n",
141 safe_strcpy(&buf
[buf_ndx
], name
, len
);
148 /* Allocate buffer */
151 if (!(buf
= malloc(buf_len
))) {
152 DEBUG(1, ("fill_grent_mem(): out of memory\n"));
156 memset(buf
, 0, buf_len
);
160 if (buf
&& buf_ndx
> 0) {
161 buf
[buf_ndx
- 1] = '\0';
165 *gr_mem_len
= buf_len
;
167 DEBUG(10, ("fill_grent_mem(): num_mem = %d, len = %d, mem = %s\n", *num_gr_mem
,
174 /* Free memory allocated in winbindd_lookup_groupmem() */
176 safe_free(name_types
);
179 free_char_array(num_names
, names
);
181 DEBUG(10, ("fill_grent_mem(): returning %d\n", result
));
186 /* Return a group structure from a group name */
188 enum winbindd_result
winbindd_getgrnam_from_group(struct winbindd_cli_state
192 struct winbindd_domain
*domain
;
193 enum SID_NAME_USE name_type
;
195 fstring name_domain
, name_group
, name
;
198 int extra_data_len
, gr_mem_len
;
200 DEBUG(3, ("[%5d]: getgrnam %s\n", state
->pid
,
201 state
->request
.data
.groupname
));
203 /* Parse domain and groupname */
205 memset(name_group
, 0, sizeof(fstring
));
207 tmp
= state
->request
.data
.groupname
;
208 parse_domain_user(tmp
, name_domain
, name_group
);
210 /* Reject names that don't have a domain - i.e name_domain contains
213 if (strequal(name_group
, "")) {
214 return WINBINDD_ERROR
;
217 /* Get info for the domain */
219 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
220 DEBUG(0, ("getgrname_from_group(): could not get domain "
221 "sid for domain %s\n", name_domain
));
222 return WINBINDD_ERROR
;
225 if (!domain_handles_open(domain
)) {
226 return WINBINDD_ERROR
;
229 /* Check for cached group entry */
231 if (winbindd_fetch_group_cache_entry(name_domain
, name_group
,
232 &state
->response
.data
.gr
,
233 &state
->response
.extra_data
,
235 state
->response
.length
+= extra_data_len
;
239 snprintf(name
, sizeof(name
), "%s\\%s", name_domain
, name_group
);
241 /* Get rid and name type from name */
243 if (!winbindd_lookup_sid_by_name(name
, &group_sid
, &name_type
)) {
244 DEBUG(1, ("group %s in domain %s does not exist\n",
245 name_group
, name_domain
));
246 return WINBINDD_ERROR
;
249 if ((name_type
!= SID_NAME_ALIAS
) && (name_type
!= SID_NAME_DOM_GRP
)) {
250 DEBUG(1, ("from_group: name '%s' is not a local or domain "
251 "group: %d\n", name_group
, name_type
));
252 return WINBINDD_ERROR
;
255 /* Fill in group structure */
257 sid_split_rid(&group_sid
, &group_rid
);
259 if (!winbindd_idmap_get_gid_from_rid(domain
->name
, group_rid
, &gid
)) {
260 DEBUG(1, ("error sursing unix gid for sid\n"));
261 return WINBINDD_ERROR
;
264 if (!fill_grent(&state
->response
.data
.gr
,
265 state
->request
.data
.groupname
, gid
) ||
266 !fill_grent_mem(domain
, group_rid
, name_type
,
267 &state
->response
.data
.gr
.num_gr_mem
,
268 &gr_mem
, &gr_mem_len
)) {
269 return WINBINDD_ERROR
;
272 /* Group membership lives at start of extra data */
274 state
->response
.data
.gr
.gr_mem_ofs
= 0;
276 state
->response
.length
+= gr_mem_len
;
277 state
->response
.extra_data
= gr_mem
;
279 /* Update cached group info */
281 winbindd_store_group_cache_entry(name_domain
, name_group
,
282 &state
->response
.data
.gr
,
283 state
->response
.extra_data
,
289 /* Return a group structure from a gid number */
291 enum winbindd_result
winbindd_getgrnam_from_gid(struct winbindd_cli_state
294 struct winbindd_domain
*domain
;
296 enum SID_NAME_USE name_type
;
299 int extra_data_len
, gr_mem_len
;
302 /* Bug out if the gid isn't in the winbind range */
304 if ((state
->request
.data
.gid
< server_state
.gid_low
) ||
305 (state
->request
.data
.gid
> server_state
.gid_high
)) {
306 return WINBINDD_ERROR
;
309 DEBUG(3, ("[%5d]: getgrgid %d\n", state
->pid
,
310 state
->request
.data
.gid
));
312 /* Get rid from gid */
314 if (!winbindd_idmap_get_rid_from_gid(state
->request
.data
.gid
,
315 &group_rid
, &domain
)) {
316 DEBUG(1, ("Could not convert gid %d to rid\n",
317 state
->request
.data
.gid
));
318 return WINBINDD_ERROR
;
321 if (!domain_handles_open(domain
)) {
322 return WINBINDD_ERROR
;
325 /* Try a cached entry */
327 if (winbindd_fetch_gid_cache_entry(domain
->name
,
328 state
->request
.data
.gid
,
329 &state
->response
.data
.gr
,
330 &state
->response
.extra_data
,
332 state
->response
.length
+= extra_data_len
;
336 /* Get sid from gid */
338 sid_copy(&group_sid
, &domain
->sid
);
339 sid_append_rid(&group_sid
, group_rid
);
341 if (!winbindd_lookup_name_by_sid(&group_sid
, group_name
, &name_type
)) {
342 DEBUG(1, ("Could not lookup sid\n"));
343 return WINBINDD_ERROR
;
346 if (strcmp(lp_winbind_separator(),"\\")) {
347 string_sub(group_name
, "\\", lp_winbind_separator(),
351 if (!((name_type
== SID_NAME_ALIAS
) ||
352 (name_type
== SID_NAME_DOM_GRP
))) {
353 DEBUG(1, ("from_gid: name '%s' is not a local or domain "
354 "group: %d\n", group_name
, name_type
));
355 return WINBINDD_ERROR
;
358 /* Fill in group structure */
360 if (!fill_grent(&state
->response
.data
.gr
, group_name
,
361 state
->request
.data
.gid
) ||
362 !fill_grent_mem(domain
, group_rid
, name_type
,
363 &state
->response
.data
.gr
.num_gr_mem
,
364 &gr_mem
, &gr_mem_len
)) {
365 return WINBINDD_ERROR
;
369 /* Group membership lives at start of extra data */
371 state
->response
.data
.gr
.gr_mem_ofs
= 0;
373 state
->response
.length
+= gr_mem_len
;
374 state
->response
.extra_data
= gr_mem
;
376 /* Update cached group info */
378 winbindd_store_gid_cache_entry(domain
->name
, state
->request
.data
.gid
,
379 &state
->response
.data
.gr
,
380 state
->response
.extra_data
,
387 * set/get/endgrent functions
390 /* "Rewind" file pointer for group database enumeration */
392 enum winbindd_result
winbindd_setgrent(struct winbindd_cli_state
*state
)
394 struct winbindd_domain
*tmp
;
396 DEBUG(3, ("[%5d]: setgrent\n", state
->pid
));
398 if (state
== NULL
) return WINBINDD_ERROR
;
400 /* Check user has enabled this */
402 if (!lp_winbind_enum_groups()) {
403 return WINBINDD_ERROR
;
406 /* Free old static data if it exists */
408 if (state
->getgrent_state
!= NULL
) {
409 free_getent_state(state
->getgrent_state
);
410 state
->getgrent_state
= NULL
;
413 /* Create sam pipes for each domain we know about */
415 for (tmp
= domain_list
; tmp
!= NULL
; tmp
= tmp
->next
) {
416 struct getent_state
*domain_state
;
418 /* Skip domains other than WINBINDD_DOMAIN environment
421 if ((strcmp(state
->request
.domain
, "") != 0) &&
422 !check_domain_env(state
->request
.domain
, tmp
->name
)) {
426 /* Create a state record for this domain */
428 if ((domain_state
= (struct getent_state
*)
429 malloc(sizeof(struct getent_state
))) == NULL
) {
431 return WINBINDD_ERROR
;
434 ZERO_STRUCTP(domain_state
);
436 /* Add to list of open domains */
438 domain_state
->domain
= tmp
;
439 DLIST_ADD(state
->getgrent_state
, domain_state
);
445 /* Close file pointer to ntdom group database */
447 enum winbindd_result
winbindd_endgrent(struct winbindd_cli_state
*state
)
449 DEBUG(3, ("[%5d]: endgrent\n", state
->pid
));
451 if (state
== NULL
) return WINBINDD_ERROR
;
453 free_getent_state(state
->getgrent_state
);
454 state
->getgrent_state
= NULL
;
459 /* Get the list of domain groups and domain aliases for a domain. We fill in
460 the sam_entries and num_sam_entries fields with domain group information.
461 The dispinfo_ndx field is incremented to the index of the next group to
462 fetch. Return True if some groups were returned, False otherwise. */
464 #define MAX_FETCH_SAM_ENTRIES 100
466 static BOOL
get_sam_group_entries(struct getent_state
*ent
)
468 uint32 status
, num_entries
;
469 struct acct_info
*name_list
= NULL
;
471 if (ent
->got_all_sam_entries
) {
476 if (winbindd_fetch_group_cache(ent
->domain
->name
,
478 &ent
->num_sam_entries
)) {
483 /* Fetch group entries */
485 if (!domain_handles_open(ent
->domain
)) {
489 /* Free any existing group info */
491 if (ent
->sam_entries
) {
492 free(ent
->sam_entries
);
493 ent
->sam_entries
= NULL
;
494 ent
->num_sam_entries
= 0;
497 /* Enumerate domain groups */
500 struct acct_info
*sam_grp_entries
= NULL
;
504 status
= samr_enum_dom_groups(&ent
->domain
->sam_dom_handle
,
505 &ent
->grp_query_start_ndx
,
506 0x8000, /* buffer size? */
507 (struct acct_info
**)
511 /* Copy entries into return buffer */
515 name_list
= Realloc(name_list
,
516 sizeof(struct acct_info
) *
517 (ent
->num_sam_entries
+
520 memcpy(&name_list
[ent
->num_sam_entries
],
522 num_entries
* sizeof(struct acct_info
));
524 safe_free(sam_grp_entries
);
527 ent
->num_sam_entries
+= num_entries
;
529 if (status
!= STATUS_MORE_ENTRIES
)
532 } while (ent
->num_sam_entries
< MAX_FETCH_SAM_ENTRIES
);
535 /* Fill cache with received entries */
537 winbindd_store_group_cache(ent
->domain
->name
, ent
->sam_entries
,
538 ent
->num_sam_entries
);
541 /* Fill in remaining fields */
543 ent
->sam_entries
= name_list
;
544 ent
->sam_entry_index
= 0;
545 ent
->got_all_sam_entries
= (status
!= STATUS_MORE_ENTRIES
);
547 return ent
->num_sam_entries
> 0;
550 /* Fetch next group entry from ntdom database */
552 #define MAX_GETGRENT_GROUPS 500
554 enum winbindd_result
winbindd_getgrent(struct winbindd_cli_state
*state
)
556 struct getent_state
*ent
;
557 struct winbindd_gr
*group_list
= NULL
;
558 int num_groups
, group_list_ndx
= 0, i
, gr_mem_list_len
= 0;
559 char *sep
, *new_extra_data
, *gr_mem_list
= NULL
;
561 DEBUG(3, ("[%5d]: getgrent\n", state
->pid
));
563 if (state
== NULL
) return WINBINDD_ERROR
;
565 /* Check user has enabled this */
567 if (!lp_winbind_enum_groups()) {
568 return WINBINDD_ERROR
;
571 num_groups
= MIN(MAX_GETGRENT_GROUPS
, state
->request
.data
.num_entries
);
573 if ((state
->response
.extra_data
=
574 malloc(num_groups
* sizeof(struct winbindd_gr
))) == NULL
) {
575 return WINBINDD_ERROR
;
578 state
->response
.data
.num_entries
= 0;
580 group_list
= (struct winbindd_gr
*)state
->response
.extra_data
;
581 sep
= lp_winbind_separator();
583 if (!(ent
= state
->getgrent_state
)) {
584 return WINBINDD_ERROR
;
587 /* Start sending back groups */
589 for (i
= 0; i
< num_groups
; i
++) {
590 struct acct_info
*name_list
= NULL
;
591 fstring domain_group_name
;
595 /* Do we need to fetch another chunk of groups? */
599 DEBUG(10, ("getgrent(): entry_index = %d, num_entries = %d\n",
600 ent
->sam_entry_index
, ent
->num_sam_entries
));
602 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
604 while(ent
&& !get_sam_group_entries(ent
)) {
605 struct getent_state
*next_ent
;
607 DEBUG(10, ("getgrent(): freeing state info for "
608 "domain %s\n", ent
->domain
->name
));
610 /* Free state information for this domain */
612 safe_free(ent
->sam_entries
);
613 ent
->sam_entries
= NULL
;
615 next_ent
= ent
->next
;
616 DLIST_REMOVE(state
->getgrent_state
, ent
);
622 /* No more domains */
627 name_list
= ent
->sam_entries
;
629 /* Lookup group info */
631 if (!winbindd_idmap_get_gid_from_rid(
633 name_list
[ent
->sam_entry_index
].rid
,
636 DEBUG(1, ("getgrent(): could not look up gid for group %s\n",
637 name_list
[ent
->sam_entry_index
].acct_name
));
639 ent
->sam_entry_index
++;
643 DEBUG(10, ("getgrent(): got gid %d for group %x\n", group_gid
,
644 name_list
[ent
->sam_entry_index
].rid
));
646 /* Fill in group entry */
648 slprintf(domain_group_name
, sizeof(domain_group_name
) - 1,
649 "%s%s%s", ent
->domain
->name
, lp_winbind_separator(),
650 name_list
[ent
->sam_entry_index
].acct_name
);
652 result
= fill_grent(&group_list
[group_list_ndx
],
653 domain_group_name
, group_gid
);
655 /* Fill in group membership entry */
659 char *gr_mem
, *new_gr_mem_list
;
661 /* Get group membership */
663 result
= fill_grent_mem(
665 name_list
[ent
->sam_entry_index
].rid
,
667 &group_list
[group_list_ndx
].num_gr_mem
,
668 &gr_mem
, &gr_mem_len
);
670 /* Append to group membership list */
672 new_gr_mem_list
= Realloc(
674 gr_mem_list_len
+ gr_mem_len
);
676 if (!new_gr_mem_list
&& (group_list
[group_list_ndx
].num_gr_mem
!= 0)) {
677 DEBUG(0, ("getgrent(): out of memory\n"));
683 DEBUG(10, ("getgrent(): list_len = %d, mem_len = %d\n",
684 gr_mem_list_len
, gr_mem_len
));
686 gr_mem_list
= new_gr_mem_list
;
688 memcpy(&gr_mem_list
[gr_mem_list_len
], gr_mem
,
693 group_list
[group_list_ndx
].gr_mem_ofs
=
696 gr_mem_list_len
+= gr_mem_len
;
699 ent
->sam_entry_index
++;
701 /* Add group to return list */
705 DEBUG(10, ("getgrent(): adding group num_entries = %d\n",
706 state
->response
.data
.num_entries
));
709 state
->response
.data
.num_entries
++;
711 state
->response
.length
+=
712 sizeof(struct winbindd_gr
);
715 DEBUG(0, ("could not lookup domain group %s\n",
720 /* Copy the list of group memberships to the end of the extra data */
722 if (group_list_ndx
== 0) {
726 new_extra_data
= Realloc(
727 state
->response
.extra_data
,
728 group_list_ndx
* sizeof(struct winbindd_gr
) + gr_mem_list_len
);
730 if (!new_extra_data
) {
731 DEBUG(0, ("out of memory\n"));
733 safe_free(state
->response
.extra_data
);
734 state
->response
.extra_data
= NULL
;
735 safe_free(gr_mem_list
);
737 return WINBINDD_ERROR
;
740 state
->response
.extra_data
= new_extra_data
;
742 memcpy(&((char *)state
->response
.extra_data
)
743 [group_list_ndx
* sizeof(struct winbindd_gr
)],
744 gr_mem_list
, gr_mem_list_len
);
746 safe_free(gr_mem_list
);
748 state
->response
.length
+= gr_mem_list_len
;
750 DEBUG(10, ("getgrent(): returning %d groups, length = %d\n",
751 group_list_ndx
, gr_mem_list_len
));
756 return (group_list_ndx
> 0) ? WINBINDD_OK
: WINBINDD_ERROR
;
759 /* List domain groups without mapping to unix ids */
761 enum winbindd_result
winbindd_list_groups(struct winbindd_cli_state
*state
)
763 uint32 total_entries
= 0;
764 uint32 num_domain_entries
;
765 struct winbindd_domain
*domain
;
766 struct getent_state groups
;
767 char *extra_data
= NULL
;
769 int extra_data_len
= 0, i
;
770 void *sam_entries
= NULL
;
772 DEBUG(3, ("[%5d]: list groups\n", state
->pid
));
774 /* Enumerate over trusted domains */
776 for (domain
= domain_list
; domain
; domain
= domain
->next
) {
778 /* Skip domains other than WINBINDD_DOMAIN environment
781 if ((strcmp(state
->request
.domain
, "") != 0) &&
782 !check_domain_env(state
->request
.domain
, domain
->name
)) {
786 /* Get list of sam groups */
789 groups
.domain
= domain
;
792 * iterate through all groups
793 * total_entries : maintains a total count over **all domains**
794 * num_domain_entries : is the running count for this domain
797 num_domain_entries
= 0;
798 while (get_sam_group_entries(&groups
))
803 offset
= sizeof(struct acct_info
) * num_domain_entries
;
804 new_size
= sizeof(struct acct_info
)
805 * (groups
.num_sam_entries
+ num_domain_entries
);
806 sam_entries
= Realloc(sam_entries
, new_size
);
809 return WINBINDD_ERROR
;
811 num_domain_entries
+= groups
.num_sam_entries
;
812 memcpy (sam_entries
+offset
, groups
.sam_entries
,
813 sizeof(struct acct_info
) * groups
.num_sam_entries
);
815 groups
.sam_entries
= NULL
;
816 groups
.num_sam_entries
= 0;
819 /* skip remainder of loop if we idn;t retrieve any groups */
821 if (num_domain_entries
== 0)
824 /* setup the groups struct to contain all the groups
825 retrieved for this domain */
827 groups
.num_sam_entries
= num_domain_entries
;
828 groups
.sam_entries
= sam_entries
;
830 /* keep track the of the total number of groups seen so
831 far over all domains */
833 total_entries
+= groups
.num_sam_entries
;
835 /* Allocate some memory for extra data. Note that we limit
836 account names to sizeof(fstring) = 128 characters. */
838 ted
= Realloc(extra_data
, sizeof(fstring
) * total_entries
);
841 DEBUG(0,("winbindd_list_groups: failed to enlarge buffer!\n"));
844 return WINBINDD_ERROR
;
848 /* Pack group list into extra data fields */
850 for (i
= 0; i
< groups
.num_sam_entries
; i
++) {
851 char *group_name
= ((struct acct_info
*)
852 groups
.sam_entries
)[i
].acct_name
;
855 /* Convert unistring to ascii */
857 snprintf(name
, sizeof(name
), "%s%s%s", domain
->name
,
858 lp_winbind_separator(), group_name
);
860 /* Append to extra data */
862 memcpy(&extra_data
[extra_data_len
], name
, strlen(name
));
863 extra_data_len
+= strlen(name
);
865 extra_data
[extra_data_len
++] = ',';
869 /* Assign extra_data fields in response structure */
872 extra_data
[extra_data_len
- 1] = '\0';
873 state
->response
.extra_data
= extra_data
;
874 state
->response
.length
+= extra_data_len
;
877 /* No domains may have responded but that's still OK so don't
883 /* Get user supplementary groups. This is much quicker than trying to
884 invert the groups database. */
886 enum winbindd_result
winbindd_getgroups(struct winbindd_cli_state
*state
)
888 fstring name_domain
, name_user
, name
;
890 enum SID_NAME_USE name_type
;
891 uint32 user_rid
, num_groups
, num_gids
;
892 DOM_GID
*user_groups
= NULL
;
893 struct winbindd_domain
*domain
;
894 enum winbindd_result result
;
898 DEBUG(3, ("[%5d]: getgroups %s\n", state
->pid
,
899 state
->request
.data
.username
));
901 if (state
== NULL
) return WINBINDD_ERROR
;
903 /* Parse domain and username */
905 parse_domain_user(state
->request
.data
.username
, name_domain
,
908 /* Reject names that don't have a domain - i.e name_domain contains
911 if (strequal(name_domain
, "")) {
912 return WINBINDD_ERROR
;
915 /* Get info for the domain */
917 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
918 DEBUG(0, ("could not find domain entry for domain %s\n",
920 return WINBINDD_ERROR
;
923 if (!domain_handles_open(domain
)) {
924 return WINBINDD_ERROR
;
927 slprintf(name
, sizeof(name
) - 1, "%s\\%s", name_domain
, name_user
);
929 /* Get rid and name type from name. The following costs 1 packet */
931 if (!winbindd_lookup_sid_by_name(name
, &user_sid
, &name_type
)) {
932 DEBUG(1, ("user '%s' does not exist\n", name_user
));
933 return WINBINDD_ERROR
;
936 if (name_type
!= SID_NAME_USER
) {
937 DEBUG(1, ("name '%s' is not a user name: %d\n", name_user
,
939 return WINBINDD_ERROR
;
942 sid_split_rid(&user_sid
, &user_rid
);
944 if (!winbindd_lookup_usergroups(domain
, user_rid
, &num_groups
,
946 return WINBINDD_ERROR
;
949 /* Copy data back to client */
952 gid_list
= malloc(sizeof(gid_t
) * num_groups
);
954 if (state
->response
.extra_data
) {
955 result
= WINBINDD_ERROR
;
959 for (i
= 0; i
< num_groups
; i
++) {
960 if (!winbindd_idmap_get_gid_from_rid(
961 domain
->name
, user_groups
[i
].g_rid
,
962 &gid_list
[num_gids
])) {
964 DEBUG(1, ("unable to convert group rid %d to gid\n",
965 user_groups
[i
].g_rid
));
972 state
->response
.data
.num_entries
= num_gids
;
973 state
->response
.extra_data
= gid_list
;
974 state
->response
.length
+= num_gids
* sizeof(gid_t
);
976 result
= WINBINDD_OK
;
979 safe_free(user_groups
);