2 Unix SMB/Netbios implementation.
5 Winbind daemon for ntdom nss module
7 Copyright (C) Tim Potter 2000
8 Copyright (C) Jeremy Allison 2001.
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.
27 /***************************************************************
28 Empty static struct for negative caching.
29 ****************************************************************/
31 static struct winbindd_gr negative_gr_cache_entry
;
33 /* Fill a grent structure from various other information */
35 static BOOL
fill_grent(struct winbindd_gr
*gr
, char *gr_name
,
40 gr
->gr_gid
= unix_gid
;
42 /* Group name and password */
44 safe_strcpy(gr
->gr_name
, gr_name
, sizeof(gr
->gr_name
) - 1);
45 safe_strcpy(gr
->gr_passwd
, "x", sizeof(gr
->gr_passwd
) - 1);
50 /* Fill in the group membership field of a NT group given by group_rid */
52 static BOOL
fill_grent_mem(struct winbindd_domain
*domain
,
54 enum SID_NAME_USE group_name_type
,
55 int *num_gr_mem
, char **gr_mem
, int *gr_mem_len
)
57 uint32
*rid_mem
= NULL
, num_names
= 0;
58 uint32
*name_types
= NULL
;
59 int buf_len
, buf_ndx
, i
;
60 char **names
= NULL
, *buf
;
64 if (!(mem_ctx
= talloc_init()))
67 /* Initialise group membership information */
69 DEBUG(10, ("fill_grent_mem(): group %s rid 0x%x\n",
70 domain
? domain
->name
: "NULL", group_rid
));
74 if (group_name_type
!= SID_NAME_DOM_GRP
) {
75 DEBUG(1, ("fill_grent_mem(): rid %d in domain %s isn't a "
76 "domain group\n", group_rid
, domain
->name
));
80 /* Lookup group members */
82 if (!winbindd_lookup_groupmem(domain
, mem_ctx
, group_rid
, &num_names
,
83 &rid_mem
, &names
, &name_types
)) {
85 DEBUG(1, ("fill_grent_mem(): could not lookup membership "
86 "for group rid %d in domain %s\n",
87 group_rid
, domain
->name
));
92 DEBUG(10, ("fill_grent_mem(): looked up %d names\n", num_names
));
94 if (DEBUGLEVEL
>= 10) {
95 for (i
= 0; i
< num_names
; i
++)
96 DEBUG(10, ("\t%20s %x %d\n", names
[i
], rid_mem
[i
],
100 /* Add members to list */
103 buf_len
= buf_ndx
= 0;
107 for (i
= 0; i
< num_names
; i
++) {
114 DEBUG(10, ("fill_grent_mem(): processing name %s\n",
117 /* FIXME: need to cope with groups within groups. These
118 occur in Universal groups on a Windows 2000 native mode
121 if (name_types
[i
] != SID_NAME_USER
) {
122 DEBUG(3, ("fill_grent_mem(): name %s isn't a domain "
123 "user\n", the_name
));
127 /* Don't bother with machine accounts */
129 if (the_name
[strlen(the_name
) - 1] == '$') {
130 DEBUG(10, ("fill_grent_mem(): %s is machine account\n",
135 /* Append domain name */
137 snprintf(name
, sizeof(name
), "%s%s%s", domain
->name
,
138 lp_winbind_separator(), the_name
);
142 /* Add to list or calculate buffer length */
145 buf_len
+= len
+ 1; /* List is comma separated */
147 DEBUG(10, ("fill_grent_mem(): buf_len + %d = %d\n", len
+ 1,
150 DEBUG(10, ("fill_grent_mem(): appending %s at index %d\n",
152 safe_strcpy(&buf
[buf_ndx
], name
, len
);
159 /* Allocate buffer */
162 if (!(buf
= malloc(buf_len
))) {
163 DEBUG(1, ("fill_grent_mem(): 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, ("fill_grent_mem(): num_mem = %d, len = %d, mem = %s\n",
179 *num_gr_mem
, buf_len
, num_gr_mem
? buf
: "NULL"));
185 talloc_destroy(mem_ctx
);
187 DEBUG(10, ("fill_grent_mem(): returning %d\n", result
));
192 /* Return a group structure from a group name */
194 enum winbindd_result
winbindd_getgrnam_from_group(struct winbindd_cli_state
*state
)
197 struct winbindd_domain
*domain
;
198 enum SID_NAME_USE name_type
;
200 fstring name_domain
, name_group
, name
;
203 int extra_data_len
, gr_mem_len
;
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 /* Get info for the domain */
218 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
219 DEBUG(0, ("getgrname_from_group(): could not get domain "
220 "sid for domain %s\n", name_domain
));
221 return WINBINDD_ERROR
;
224 /* Check for cached group entry */
226 if (winbindd_fetch_group_cache_entry(domain
, name_group
,
227 &state
->response
.data
.gr
,
228 &state
->response
.extra_data
,
231 /* Check if this is a negative cache entry. */
233 if (memcmp(&negative_gr_cache_entry
, &state
->response
.data
.gr
,
234 sizeof(state
->response
.data
.gr
)) == 0)
235 return WINBINDD_ERROR
;
237 state
->response
.length
+= extra_data_len
;
241 snprintf(name
, sizeof(name
), "%s\\%s", name_domain
, name_group
);
243 /* Get rid and name type from name */
245 if (!winbindd_lookup_sid_by_name(name
, &group_sid
, &name_type
)) {
246 DEBUG(1, ("group %s in domain %s does not exist\n",
247 name_group
, name_domain
));
249 winbindd_store_group_cache_entry(domain
, name_group
,
250 &negative_gr_cache_entry
, NULL
, 0);
252 return WINBINDD_ERROR
;
255 if ((name_type
!= SID_NAME_ALIAS
) && (name_type
!= SID_NAME_DOM_GRP
)) {
256 DEBUG(1, ("from_group: name '%s' is not a local or domain "
257 "group: %d\n", name_group
, name_type
));
259 winbindd_store_group_cache_entry(domain
, name_group
,
260 &negative_gr_cache_entry
, NULL
, 0);
262 return WINBINDD_ERROR
;
265 /* Fill in group structure */
267 sid_split_rid(&group_sid
, &group_rid
);
269 if (!winbindd_idmap_get_gid_from_rid(domain
->name
, group_rid
, &gid
)) {
270 DEBUG(1, ("error sursing unix gid for sid\n"));
272 winbindd_store_group_cache_entry(domain
, name_group
,
273 &negative_gr_cache_entry
, NULL
, 0);
275 return WINBINDD_ERROR
;
278 if (!fill_grent(&state
->response
.data
.gr
,
279 state
->request
.data
.groupname
, gid
) ||
280 !fill_grent_mem(domain
, group_rid
, name_type
,
281 &state
->response
.data
.gr
.num_gr_mem
,
282 &gr_mem
, &gr_mem_len
)) {
284 winbindd_store_group_cache_entry(domain
, name_group
,
285 &negative_gr_cache_entry
, NULL
, 0);
287 return WINBINDD_ERROR
;
290 /* Group membership lives at start of extra data */
292 state
->response
.data
.gr
.gr_mem_ofs
= 0;
294 state
->response
.length
+= gr_mem_len
;
295 state
->response
.extra_data
= gr_mem
;
297 /* Update cached group info */
299 winbindd_store_group_cache_entry(domain
, name_group
,
300 &state
->response
.data
.gr
,
301 state
->response
.extra_data
,
307 /* Return a group structure from a gid number */
309 enum winbindd_result
winbindd_getgrnam_from_gid(struct winbindd_cli_state
312 struct winbindd_domain
*domain
;
314 enum SID_NAME_USE name_type
;
317 int extra_data_len
, gr_mem_len
;
320 DEBUG(3, ("[%5d]: getgrgid %d\n", state
->pid
,
321 state
->request
.data
.gid
));
323 /* Bug out if the gid isn't in the winbind range */
325 if ((state
->request
.data
.gid
< server_state
.gid_low
) ||
326 (state
->request
.data
.gid
> server_state
.gid_high
))
327 return WINBINDD_ERROR
;
329 /* Get rid from gid */
331 if (!winbindd_idmap_get_rid_from_gid(state
->request
.data
.gid
,
332 &group_rid
, &domain
)) {
333 DEBUG(1, ("Could not convert gid %d to rid\n",
334 state
->request
.data
.gid
));
335 return WINBINDD_ERROR
;
338 /* Try a cached entry */
340 if (winbindd_fetch_gid_cache_entry(domain
,
341 state
->request
.data
.gid
,
342 &state
->response
.data
.gr
,
343 &state
->response
.extra_data
,
346 /* Check if this is a negative cache entry. */
348 if (memcmp(&negative_gr_cache_entry
, &state
->response
.data
.gr
,
349 sizeof(state
->response
.data
.gr
)) == 0)
350 return WINBINDD_ERROR
;
352 state
->response
.length
+= extra_data_len
;
356 /* Get sid from gid */
358 sid_copy(&group_sid
, &domain
->sid
);
359 sid_append_rid(&group_sid
, group_rid
);
361 if (!winbindd_lookup_name_by_sid(&group_sid
, group_name
, &name_type
)) {
362 DEBUG(1, ("Could not lookup sid\n"));
363 return WINBINDD_ERROR
;
366 if (strcmp(lp_winbind_separator(),"\\"))
367 string_sub(group_name
, "\\", lp_winbind_separator(),
370 if (!((name_type
== SID_NAME_ALIAS
) ||
371 (name_type
== SID_NAME_DOM_GRP
))) {
372 DEBUG(1, ("from_gid: name '%s' is not a local or domain "
373 "group: %d\n", group_name
, name_type
));
374 return WINBINDD_ERROR
;
377 /* Fill in group structure */
379 if (!fill_grent(&state
->response
.data
.gr
, group_name
,
380 state
->request
.data
.gid
) ||
381 !fill_grent_mem(domain
, group_rid
, name_type
,
382 &state
->response
.data
.gr
.num_gr_mem
,
383 &gr_mem
, &gr_mem_len
))
384 return WINBINDD_ERROR
;
386 /* Group membership lives at start of extra data */
388 state
->response
.data
.gr
.gr_mem_ofs
= 0;
390 state
->response
.length
+= gr_mem_len
;
391 state
->response
.extra_data
= gr_mem
;
393 /* Update cached group info */
395 winbindd_store_gid_cache_entry(domain
, state
->request
.data
.gid
,
396 &state
->response
.data
.gr
,
397 state
->response
.extra_data
,
404 * set/get/endgrent functions
407 /* "Rewind" file pointer for group database enumeration */
409 enum winbindd_result
winbindd_setgrent(struct winbindd_cli_state
*state
)
411 struct winbindd_domain
*tmp
;
413 DEBUG(3, ("[%5d]: setgrent\n", state
->pid
));
415 /* Check user has enabled this */
417 if (!lp_winbind_enum_groups())
418 return WINBINDD_ERROR
;
420 /* Free old static data if it exists */
422 if (state
->getgrent_state
!= NULL
) {
423 free_getent_state(state
->getgrent_state
);
424 state
->getgrent_state
= NULL
;
427 /* Create sam pipes for each domain we know about */
429 if (domain_list
== NULL
)
432 for (tmp
= domain_list
; tmp
!= NULL
; tmp
= tmp
->next
) {
433 struct getent_state
*domain_state
;
435 /* Skip domains other than WINBINDD_DOMAIN environment
438 if ((strcmp(state
->request
.domain
, "") != 0) &&
439 !check_domain_env(state
->request
.domain
, tmp
->name
)) {
440 DEBUG(5, ("skipping domain %s because of env var\n",
445 /* Create a state record for this domain */
446 if ((domain_state
= create_getent_state(tmp
)) == NULL
) {
447 DEBUG(5, ("error connecting to dc for domain %s\n",
452 /* Add to list of open domains */
454 DLIST_ADD(state
->getgrent_state
, domain_state
);
460 /* Close file pointer to ntdom group database */
462 enum winbindd_result
winbindd_endgrent(struct winbindd_cli_state
*state
)
464 DEBUG(3, ("[%5d]: endgrent\n", state
->pid
));
466 free_getent_state(state
->getgrent_state
);
467 state
->getgrent_state
= NULL
;
472 /* Get the list of domain groups and domain aliases for a domain. We fill in
473 the sam_entries and num_sam_entries fields with domain group information.
474 The dispinfo_ndx field is incremented to the index of the next group to
475 fetch. Return True if some groups were returned, False otherwise. */
477 #define MAX_FETCH_SAM_ENTRIES 100
479 static BOOL
get_sam_group_entries(struct getent_state
*ent
)
483 struct acct_info
*name_list
= NULL
, *tnl
;
487 if (ent
->got_all_sam_entries
)
491 if (winbindd_fetch_group_cache(ent
->domain
,
493 &ent
->num_sam_entries
))
497 if (!(mem_ctx
= talloc_init()))
500 /* Free any existing group info */
502 SAFE_FREE(ent
->sam_entries
);
503 ent
->num_sam_entries
= 0;
505 /* Enumerate domain groups */
508 struct acct_info
*sam_grp_entries
= NULL
;
513 if (!(hnd
= cm_get_sam_handle(ent
->domain
->name
)))
516 status
= cli_samr_enum_dom_groups(
517 hnd
->cli
, mem_ctx
, &ent
->dom_pol
,
518 &ent
->grp_query_start_ndx
,
519 0x8000, /* buffer size? */
520 (struct acct_info
**) &sam_grp_entries
, &num_entries
);
522 /* Copy entries into return buffer */
526 tnl
= Realloc(name_list
,
527 sizeof(struct acct_info
) *
528 (ent
->num_sam_entries
+
532 DEBUG(0,("get_sam_group_entries: unable to "
533 "realloc a structure!\n"));
534 SAFE_FREE(name_list
);
540 memcpy(&name_list
[ent
->num_sam_entries
],
542 num_entries
* sizeof(struct acct_info
));
545 ent
->num_sam_entries
+= num_entries
;
547 if (NT_STATUS_V(status
) != NT_STATUS_V(STATUS_MORE_ENTRIES
))
550 } while (ent
->num_sam_entries
< MAX_FETCH_SAM_ENTRIES
);
553 /* Fill cache with received entries */
555 winbindd_store_group_cache(ent
->domain
, ent
->sam_entries
,
556 ent
->num_sam_entries
);
559 /* Fill in remaining fields */
561 ent
->sam_entries
= name_list
;
562 ent
->sam_entry_index
= 0;
563 ent
->got_all_sam_entries
= (NT_STATUS_V(status
) !=
564 NT_STATUS_V(STATUS_MORE_ENTRIES
));
566 result
= (ent
->num_sam_entries
> 0);
570 talloc_destroy(mem_ctx
);
575 /* Fetch next group entry from ntdom database */
577 #define MAX_GETGRENT_GROUPS 500
579 enum winbindd_result
winbindd_getgrent(struct winbindd_cli_state
*state
)
581 struct getent_state
*ent
;
582 struct winbindd_gr
*group_list
= NULL
;
583 int num_groups
, group_list_ndx
= 0, i
, gr_mem_list_len
= 0;
584 char *new_extra_data
, *gr_mem_list
= NULL
;
586 DEBUG(3, ("[%5d]: getgrent\n", state
->pid
));
588 /* Check user has enabled this */
590 if (!lp_winbind_enum_groups())
591 return WINBINDD_ERROR
;
593 num_groups
= MIN(MAX_GETGRENT_GROUPS
, state
->request
.data
.num_entries
);
595 if ((state
->response
.extra_data
=
596 malloc(num_groups
* sizeof(struct winbindd_gr
))) == NULL
)
597 return WINBINDD_ERROR
;
599 state
->response
.data
.num_entries
= 0;
601 group_list
= (struct winbindd_gr
*)state
->response
.extra_data
;
603 if (!(ent
= state
->getgrent_state
))
604 return WINBINDD_ERROR
;
606 /* Start sending back groups */
608 for (i
= 0; i
< num_groups
; i
++) {
609 struct acct_info
*name_list
= NULL
;
610 fstring domain_group_name
;
614 char *gr_mem
, *new_gr_mem_list
;
616 /* Do we need to fetch another chunk of groups? */
620 DEBUG(10, ("getgrent(): entry_index = %d, num_entries = %d\n",
621 ent
->sam_entry_index
, ent
->num_sam_entries
));
623 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
625 while(ent
&& !get_sam_group_entries(ent
)) {
626 struct getent_state
*next_ent
;
628 DEBUG(10, ("getgrent(): freeing state info for "
629 "domain %s\n", ent
->domain
->name
));
631 /* Free state information for this domain */
633 SAFE_FREE(ent
->sam_entries
);
635 next_ent
= ent
->next
;
636 DLIST_REMOVE(state
->getgrent_state
, ent
);
642 /* No more domains */
648 name_list
= ent
->sam_entries
;
650 /* Lookup group info */
652 if (!winbindd_idmap_get_gid_from_rid(
654 name_list
[ent
->sam_entry_index
].rid
,
657 DEBUG(1, ("getgrent(): could not look up gid for group %s\n",
658 name_list
[ent
->sam_entry_index
].acct_name
));
660 ent
->sam_entry_index
++;
664 DEBUG(10, ("getgrent(): got gid %d for group %x\n", group_gid
,
665 name_list
[ent
->sam_entry_index
].rid
));
667 /* Fill in group entry */
669 slprintf(domain_group_name
, sizeof(domain_group_name
) - 1,
670 "%s%s%s", ent
->domain
->name
, lp_winbind_separator(),
671 name_list
[ent
->sam_entry_index
].acct_name
);
673 result
= fill_grent(&group_list
[group_list_ndx
],
674 domain_group_name
, group_gid
);
676 /* Fill in group membership entry */
680 /* Get group membership */
682 result
= fill_grent_mem(
684 name_list
[ent
->sam_entry_index
].rid
,
686 &group_list
[group_list_ndx
].num_gr_mem
,
687 &gr_mem
, &gr_mem_len
);
691 /* Append to group membership list */
693 new_gr_mem_list
= Realloc(
695 gr_mem_list_len
+ gr_mem_len
);
697 if (!new_gr_mem_list
&& (group_list
[group_list_ndx
].num_gr_mem
!= 0)) {
698 DEBUG(0, ("getgrent(): out of memory\n"));
699 SAFE_FREE(gr_mem_list
);
704 DEBUG(10, ("getgrent(): list_len = %d, mem_len = %d\n",
705 gr_mem_list_len
, gr_mem_len
));
707 gr_mem_list
= new_gr_mem_list
;
709 memcpy(&gr_mem_list
[gr_mem_list_len
], gr_mem
,
714 group_list
[group_list_ndx
].gr_mem_ofs
=
717 gr_mem_list_len
+= gr_mem_len
;
720 ent
->sam_entry_index
++;
722 /* Add group to return list */
726 DEBUG(10, ("getgrent(): adding group num_entries = %d\n",
727 state
->response
.data
.num_entries
));
730 state
->response
.data
.num_entries
++;
732 state
->response
.length
+=
733 sizeof(struct winbindd_gr
);
736 DEBUG(0, ("could not lookup domain group %s\n",
741 /* Copy the list of group memberships to the end of the extra data */
743 if (group_list_ndx
== 0)
746 new_extra_data
= Realloc(
747 state
->response
.extra_data
,
748 group_list_ndx
* sizeof(struct winbindd_gr
) + gr_mem_list_len
);
750 if (!new_extra_data
) {
751 DEBUG(0, ("out of memory\n"));
753 SAFE_FREE(state
->response
.extra_data
);
754 SAFE_FREE(gr_mem_list
);
756 return WINBINDD_ERROR
;
759 state
->response
.extra_data
= new_extra_data
;
761 memcpy(&((char *)state
->response
.extra_data
)
762 [group_list_ndx
* sizeof(struct winbindd_gr
)],
763 gr_mem_list
, gr_mem_list_len
);
765 SAFE_FREE(gr_mem_list
);
767 state
->response
.length
+= gr_mem_list_len
;
769 DEBUG(10, ("getgrent(): returning %d groups, length = %d\n",
770 group_list_ndx
, gr_mem_list_len
));
776 return (group_list_ndx
> 0) ? WINBINDD_OK
: WINBINDD_ERROR
;
779 /* List domain groups without mapping to unix ids */
781 enum winbindd_result
winbindd_list_groups(struct winbindd_cli_state
*state
)
783 uint32 total_entries
= 0;
784 uint32 num_domain_entries
;
785 struct winbindd_domain
*domain
;
786 struct getent_state
*groups
;
787 char *extra_data
= NULL
;
789 int extra_data_len
= 0, i
;
790 void *sam_entries
= NULL
;
792 DEBUG(3, ("[%5d]: list groups\n", state
->pid
));
794 /* Enumerate over trusted domains */
798 if (domain_list
== NULL
)
801 for (domain
= domain_list
; domain
; domain
= domain
->next
) {
803 /* Skip domains other than WINBINDD_DOMAIN environment
806 if ((strcmp(state
->request
.domain
, "") != 0) &&
807 !check_domain_env(state
->request
.domain
, domain
->name
))
810 /* Get list of sam groups */
812 if ((groups
= create_getent_state(domain
)) == NULL
)
816 * iterate through all groups
817 * total_entries: maintains a total count over **all domains**
818 * num_domain_entries: is the running count for this domain
821 num_domain_entries
= 0;
823 while (get_sam_group_entries(groups
)) {
827 offset
= sizeof(struct acct_info
) * num_domain_entries
;
828 new_size
= sizeof(struct acct_info
)
829 * (groups
->num_sam_entries
+ num_domain_entries
);
830 sam_entries
= Realloc(sam_entries
, new_size
);
833 free_getent_state(groups
);
834 return WINBINDD_ERROR
;
836 num_domain_entries
+= groups
->num_sam_entries
;
837 memcpy (((char *)sam_entries
)+offset
,
839 sizeof(struct acct_info
) *
840 groups
->num_sam_entries
);
842 SAFE_FREE(groups
->sam_entries
);
843 groups
->num_sam_entries
= 0;
846 /* skip remainder of loop if we idn;t retrieve any groups */
848 if (num_domain_entries
== 0)
851 /* setup the groups struct to contain all the groups
852 retrieved for this domain */
854 groups
->num_sam_entries
= num_domain_entries
;
855 groups
->sam_entries
= sam_entries
;
859 /* keep track the of the total number of groups seen so
860 far over all domains */
862 total_entries
+= groups
->num_sam_entries
;
864 /* Allocate some memory for extra data. Note that we limit
865 account names to sizeof(fstring) = 128 characters. */
867 ted
= Realloc(extra_data
, sizeof(fstring
) * total_entries
);
870 DEBUG(0,("winbindd_list_groups: failed to enlarge "
872 SAFE_FREE(extra_data
);
873 free_getent_state(groups
);
874 return WINBINDD_ERROR
;
878 /* Pack group list into extra data fields */
880 for (i
= 0; i
< groups
->num_sam_entries
; i
++) {
881 char *group_name
= ((struct acct_info
*)
882 groups
->sam_entries
)[i
].acct_name
;
885 /* Convert unistring to ascii */
887 snprintf(name
, sizeof(name
), "%s%s%s", domain
->name
,
888 lp_winbind_separator(), group_name
);
890 /* Append to extra data */
892 memcpy(&extra_data
[extra_data_len
], name
,
895 extra_data_len
+= strlen(name
);
897 extra_data
[extra_data_len
++] = ',';
900 free_getent_state(groups
);
903 /* Assign extra_data fields in response structure */
906 extra_data
[extra_data_len
- 1] = '\0';
907 state
->response
.extra_data
= extra_data
;
908 state
->response
.length
+= extra_data_len
;
911 /* No domains may have responded but that's still OK so don't
917 /* Get user supplementary groups. This is much quicker than trying to
918 invert the groups database. */
920 enum winbindd_result
winbindd_getgroups(struct winbindd_cli_state
*state
)
922 fstring name_domain
, name_user
, name
;
924 enum SID_NAME_USE name_type
;
925 uint32 user_rid
, num_groups
, num_gids
;
926 DOM_GID
*user_groups
= NULL
;
927 struct winbindd_domain
*domain
;
928 enum winbindd_result result
= WINBINDD_ERROR
;
933 DEBUG(3, ("[%5d]: getgroups %s\n", state
->pid
,
934 state
->request
.data
.username
));
936 if (!(mem_ctx
= talloc_init()))
937 return WINBINDD_ERROR
;
939 /* Parse domain and username */
941 if (!parse_domain_user(state
->request
.data
.username
, name_domain
,
945 /* Get info for the domain */
947 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
948 DEBUG(0, ("could not find domain entry for domain %s\n",
953 slprintf(name
, sizeof(name
) - 1, "%s\\%s", name_domain
, name_user
);
955 /* Get rid and name type from name. The following costs 1 packet */
957 if (!winbindd_lookup_sid_by_name(name
, &user_sid
, &name_type
)) {
958 DEBUG(1, ("user '%s' does not exist\n", name_user
));
962 if (name_type
!= SID_NAME_USER
) {
963 DEBUG(1, ("name '%s' is not a user name: %d\n", name_user
,
968 sid_split_rid(&user_sid
, &user_rid
);
970 if (!winbindd_lookup_usergroups(domain
, mem_ctx
, user_rid
,
971 &num_groups
, &user_groups
))
974 /* Copy data back to client */
977 gid_list
= malloc(sizeof(gid_t
) * num_groups
);
978 if (gid_list
== NULL
)
981 if (state
->response
.extra_data
)
984 for (i
= 0; i
< num_groups
; i
++) {
985 if (!winbindd_idmap_get_gid_from_rid(
986 domain
->name
, user_groups
[i
].g_rid
,
987 &gid_list
[num_gids
])) {
989 DEBUG(1, ("unable to convert group rid %d to gid\n",
990 user_groups
[i
].g_rid
));
997 state
->response
.data
.num_entries
= num_gids
;
998 state
->response
.extra_data
= gid_list
;
999 state
->response
.length
+= num_gids
* sizeof(gid_t
);
1001 result
= WINBINDD_OK
;
1005 talloc_destroy(mem_ctx
);