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 2 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, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 extern BOOL opt_nocache;
32 #define DBGC_CLASS DBGC_WINBIND
34 /***************************************************************
35 Empty static struct for negative caching.
36 ****************************************************************/
38 /* Fill a grent structure from various other information */
40 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
41 const char *gr_name, gid_t unix_gid)
43 fstring full_group_name;
45 fill_domain_username(full_group_name, dom_name, gr_name);
47 gr->gr_gid = unix_gid;
49 /* Group name and password */
51 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
52 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
57 /* Fill in the group membership field of a NT group given by group_sid */
59 static BOOL fill_grent_mem(struct winbindd_domain *domain,
61 enum SID_NAME_USE group_name_type,
62 int *num_gr_mem, char **gr_mem, int *gr_mem_len)
64 DOM_SID *sid_mem = NULL;
66 uint32 *name_types = NULL;
67 unsigned int buf_len, buf_ndx, i;
68 char **names = NULL, *buf;
74 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
77 /* Initialise group membership information */
79 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
83 /* HACK ALERT!! This whole routine does not cope with group members
84 * from more than one domain, ie aliases. Thus we have to work it out
85 * ourselves in a special routine. */
88 return fill_passdb_alias_grmem(domain, group_sid,
92 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
93 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
95 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
96 sid_to_string(sid_string, group_sid), domain->name,
101 /* Lookup group members */
102 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
103 &sid_mem, &names, &name_types);
104 if (!NT_STATUS_IS_OK(status)) {
105 DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n",
106 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
111 DEBUG(10, ("looked up %d names\n", num_names));
113 if (DEBUGLEVEL >= 10) {
114 for (i = 0; i < num_names; i++)
115 DEBUG(10, ("\t%20s %s %d\n", names[i],
116 sid_string_static(&sid_mem[i]),
120 /* Add members to list */
123 buf_len = buf_ndx = 0;
127 for (i = 0; i < num_names; i++) {
134 DEBUG(10, ("processing name %s\n", the_name));
136 /* FIXME: need to cope with groups within groups. These
137 occur in Universal groups on a Windows 2000 native mode
140 /* make sure to allow machine accounts */
142 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
143 DEBUG(3, ("name %s isn't a domain user\n", the_name));
147 /* Append domain name */
149 fill_domain_username(name, domain->name, the_name);
153 /* Add to list or calculate buffer length */
156 buf_len += len + 1; /* List is comma separated */
158 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
160 DEBUG(10, ("appending %s at ndx %d\n", name, len));
161 safe_strcpy(&buf[buf_ndx], name, len);
168 /* Allocate buffer */
170 if (!buf && buf_len != 0) {
171 if (!(buf = SMB_MALLOC(buf_len))) {
172 DEBUG(1, ("out of memory\n"));
176 memset(buf, 0, buf_len);
180 if (buf && buf_ndx > 0) {
181 buf[buf_ndx - 1] = '\0';
185 *gr_mem_len = buf_len;
187 DEBUG(10, ("num_mem = %d, len = %d, mem = %s\n", *num_gr_mem,
188 buf_len, *num_gr_mem ? buf : "NULL"));
193 talloc_destroy(mem_ctx);
195 DEBUG(10, ("fill_grent_mem returning %d\n", result));
200 /* Return a group structure from a group name */
202 void winbindd_getgrnam(struct winbindd_cli_state *state)
205 struct winbindd_domain *domain;
206 enum SID_NAME_USE name_type;
207 fstring name_domain, name_group;
212 /* Ensure null termination */
213 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
215 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
216 state->request.data.groupname));
218 /* Parse domain and groupname */
220 memset(name_group, 0, sizeof(fstring));
222 tmp = state->request.data.groupname;
224 parse_domain_user(tmp, name_domain, name_group);
226 /* if no domain or our local domain and no local tdb group, default to
227 * our local domain for aliases */
229 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
230 fstrcpy(name_domain, get_global_sam_name());
233 /* Get info for the domain */
235 if ((domain = find_domain_from_name(name_domain)) == NULL) {
236 DEBUG(3, ("could not get domain sid for domain %s\n",
238 request_error(state);
241 /* should we deal with users for our domain? */
243 if ( lp_winbind_trusted_domains_only() && domain->primary) {
244 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n",
245 name_domain, name_group));
246 request_error(state);
250 /* Get rid and name type from name */
252 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
253 name_group, &group_sid, &name_type)) {
254 DEBUG(1, ("group %s in domain %s does not exist\n",
255 name_group, name_domain));
256 request_error(state);
260 if ( !((name_type==SID_NAME_DOM_GRP) ||
261 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
262 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
264 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
265 name_group, name_type));
266 request_error(state);
270 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid, 0))) {
271 DEBUG(1, ("error converting unix gid to sid\n"));
272 request_error(state);
276 if (!fill_grent(&state->response.data.gr, name_domain,
278 !fill_grent_mem(domain, &group_sid, name_type,
279 &state->response.data.gr.num_gr_mem,
280 &gr_mem, &gr_mem_len)) {
281 request_error(state);
285 /* Group membership lives at start of extra data */
287 state->response.data.gr.gr_mem_ofs = 0;
289 state->response.length += gr_mem_len;
290 state->response.extra_data = gr_mem;
294 /* Return a group structure from a gid number */
296 void winbindd_getgrgid(struct winbindd_cli_state *state)
298 struct winbindd_domain *domain;
300 enum SID_NAME_USE name_type;
306 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
307 (unsigned long)state->request.data.gid));
309 /* Bug out if the gid isn't in the winbind range */
311 if ((state->request.data.gid < server_state.gid_low) ||
312 (state->request.data.gid > server_state.gid_high)) {
313 request_error(state);
317 /* Get rid from gid */
318 if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid, 0))) {
319 DEBUG(1, ("could not convert gid %lu to rid\n",
320 (unsigned long)state->request.data.gid));
321 request_error(state);
325 /* Get name from sid */
327 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
328 group_name, &name_type)) {
329 DEBUG(1, ("could not lookup sid\n"));
330 request_error(state);
334 /* Fill in group structure */
336 domain = find_domain_from_sid_noinit(&group_sid);
339 DEBUG(1,("Can't find domain from sid\n"));
340 request_error(state);
344 if ( !((name_type==SID_NAME_DOM_GRP) ||
345 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
346 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
348 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
349 group_name, name_type));
350 request_error(state);
354 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
355 state->request.data.gid) ||
356 !fill_grent_mem(domain, &group_sid, name_type,
357 &state->response.data.gr.num_gr_mem,
358 &gr_mem, &gr_mem_len)) {
359 request_error(state);
363 /* Group membership lives at start of extra data */
365 state->response.data.gr.gr_mem_ofs = 0;
367 state->response.length += gr_mem_len;
368 state->response.extra_data = gr_mem;
373 * set/get/endgrent functions
376 /* "Rewind" file pointer for group database enumeration */
378 void winbindd_setgrent(struct winbindd_cli_state *state)
380 struct winbindd_domain *domain;
382 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
384 /* Check user has enabled this */
386 if (!lp_winbind_enum_groups()) {
387 request_error(state);
391 /* Free old static data if it exists */
393 if (state->getgrent_state != NULL) {
394 free_getent_state(state->getgrent_state);
395 state->getgrent_state = NULL;
398 /* Create sam pipes for each domain we know about */
400 for (domain = domain_list(); domain != NULL; domain = domain->next) {
401 struct getent_state *domain_state;
403 /* Create a state record for this domain */
405 /* don't add our domaina if we are a PDC or if we
406 are a member of a Samba domain */
408 if ( lp_winbind_trusted_domains_only() && domain->primary )
414 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
415 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
416 request_error(state);
420 ZERO_STRUCTP(domain_state);
422 fstrcpy(domain_state->domain_name, domain->name);
424 /* Add to list of open domains */
426 DLIST_ADD(state->getgrent_state, domain_state);
429 state->getgrent_initialized = True;
433 /* Close file pointer to ntdom group database */
435 void winbindd_endgrent(struct winbindd_cli_state *state)
437 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
439 free_getent_state(state->getgrent_state);
440 state->getgrent_initialized = False;
441 state->getgrent_state = NULL;
445 /* Get the list of domain groups and domain aliases for a domain. We fill in
446 the sam_entries and num_sam_entries fields with domain group information.
447 The dispinfo_ndx field is incremented to the index of the next group to
448 fetch. Return True if some groups were returned, False otherwise. */
450 static BOOL get_sam_group_entries(struct getent_state *ent)
454 struct acct_info *name_list = NULL, *tmp_name_list = NULL;
457 struct acct_info *sam_grp_entries = NULL;
458 struct winbindd_domain *domain;
460 if (ent->got_sam_entries)
463 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
464 ent->domain_name))) {
465 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
469 /* Free any existing group info */
471 SAFE_FREE(ent->sam_entries);
472 ent->num_sam_entries = 0;
473 ent->got_sam_entries = True;
475 /* Enumerate domain groups */
479 if (!(domain = find_domain_from_name(ent->domain_name))) {
480 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
484 /* always get the domain global groups */
486 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
488 if (!NT_STATUS_IS_OK(status)) {
489 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
494 /* Copy entries into return buffer */
497 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
498 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
503 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
506 ent->num_sam_entries = num_entries;
508 /* get the domain local groups if we are a member of a native win2k domain
509 and are not using LDAP to get the groups */
511 if ( ( lp_security() != SEC_ADS && domain->native_mode
512 && domain->primary) || domain->internal )
514 DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
516 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
518 if ( !NT_STATUS_IS_OK(status) ) {
519 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
523 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
525 /* Copy entries into return buffer */
528 if ( !(tmp_name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
530 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
533 SAFE_FREE( name_list );
537 name_list = tmp_name_list;
539 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
540 num_entries * sizeof(struct acct_info) );
543 ent->num_sam_entries += num_entries;
547 /* Fill in remaining fields */
549 ent->sam_entries = name_list;
550 ent->sam_entry_index = 0;
552 result = (ent->num_sam_entries > 0);
555 talloc_destroy(mem_ctx);
560 /* Fetch next group entry from ntdom database */
562 #define MAX_GETGRENT_GROUPS 500
564 void winbindd_getgrent(struct winbindd_cli_state *state)
566 struct getent_state *ent;
567 struct winbindd_gr *group_list = NULL;
568 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
569 char *new_extra_data, *gr_mem_list = NULL;
571 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
573 /* Check user has enabled this */
575 if (!lp_winbind_enum_groups()) {
576 request_error(state);
580 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
582 if ((state->response.extra_data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
583 request_error(state);
587 memset(state->response.extra_data, '\0',
588 num_groups * sizeof(struct winbindd_gr) );
590 state->response.data.num_entries = 0;
592 group_list = (struct winbindd_gr *)state->response.extra_data;
594 if (!state->getgrent_initialized)
595 winbindd_setgrent(state);
597 if (!(ent = state->getgrent_state)) {
598 request_error(state);
602 /* Start sending back groups */
604 for (i = 0; i < num_groups; i++) {
605 struct acct_info *name_list = NULL;
606 fstring domain_group_name;
610 char *gr_mem, *new_gr_mem_list;
612 struct winbindd_domain *domain;
614 /* Do we need to fetch another chunk of groups? */
618 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
619 ent->sam_entry_index, ent->num_sam_entries));
621 if (ent->num_sam_entries == ent->sam_entry_index) {
623 while(ent && !get_sam_group_entries(ent)) {
624 struct getent_state *next_ent;
626 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
628 /* Free state information for this domain */
630 SAFE_FREE(ent->sam_entries);
632 next_ent = ent->next;
633 DLIST_REMOVE(state->getgrent_state, ent);
639 /* No more domains */
645 name_list = ent->sam_entries;
648 find_domain_from_name(ent->domain_name))) {
649 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
654 /* Lookup group info */
656 sid_copy(&group_sid, &domain->sid);
657 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
659 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid, 0))) {
661 DEBUG(1, ("could not look up gid for group %s\n",
662 name_list[ent->sam_entry_index].acct_name));
664 ent->sam_entry_index++;
668 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
669 (unsigned long)name_list[ent->sam_entry_index].rid));
671 /* Fill in group entry */
673 fill_domain_username(domain_group_name, ent->domain_name,
674 name_list[ent->sam_entry_index].acct_name);
676 result = fill_grent(&group_list[group_list_ndx],
678 name_list[ent->sam_entry_index].acct_name,
681 /* Fill in group membership entry */
685 group_list[group_list_ndx].num_gr_mem = 0;
689 /* Get group membership */
690 if (state->request.cmd == WINBINDD_GETGRLST) {
693 sid_copy(&member_sid, &domain->sid);
694 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
695 result = fill_grent_mem(
699 &group_list[group_list_ndx].num_gr_mem,
700 &gr_mem, &gr_mem_len);
705 /* Append to group membership list */
706 new_gr_mem_list = SMB_REALLOC( gr_mem_list, gr_mem_list_len + gr_mem_len);
708 if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
709 DEBUG(0, ("out of memory\n"));
710 SAFE_FREE(gr_mem_list);
715 DEBUG(10, ("list_len = %d, mem_len = %d\n",
716 gr_mem_list_len, gr_mem_len));
718 gr_mem_list = new_gr_mem_list;
720 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
725 group_list[group_list_ndx].gr_mem_ofs =
728 gr_mem_list_len += gr_mem_len;
731 ent->sam_entry_index++;
733 /* Add group to return list */
737 DEBUG(10, ("adding group num_entries = %d\n",
738 state->response.data.num_entries));
741 state->response.data.num_entries++;
743 state->response.length +=
744 sizeof(struct winbindd_gr);
747 DEBUG(0, ("could not lookup domain group %s\n",
752 /* Copy the list of group memberships to the end of the extra data */
754 if (group_list_ndx == 0)
757 new_extra_data = SMB_REALLOC(
758 state->response.extra_data,
759 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
761 if (!new_extra_data) {
762 DEBUG(0, ("out of memory\n"));
764 SAFE_FREE(state->response.extra_data);
765 SAFE_FREE(gr_mem_list);
766 request_error(state);
770 state->response.extra_data = new_extra_data;
772 memcpy(&((char *)state->response.extra_data)
773 [group_list_ndx * sizeof(struct winbindd_gr)],
774 gr_mem_list, gr_mem_list_len);
776 SAFE_FREE(gr_mem_list);
778 state->response.length += gr_mem_list_len;
780 DEBUG(10, ("returning %d groups, length = %d\n",
781 group_list_ndx, gr_mem_list_len));
787 if (group_list_ndx > 0)
790 request_error(state);
793 /* List domain groups without mapping to unix ids */
795 void winbindd_list_groups(struct winbindd_cli_state *state)
797 uint32 total_entries = 0;
798 struct winbindd_domain *domain;
799 const char *which_domain;
800 char *extra_data = NULL;
802 unsigned int extra_data_len = 0, i;
804 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
806 /* Ensure null termination */
807 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
808 which_domain = state->request.domain_name;
810 /* Enumerate over trusted domains */
812 for (domain = domain_list(); domain; domain = domain->next) {
813 struct getent_state groups;
815 /* if we have a domain name restricting the request and this
816 one in the list doesn't match, then just bypass the remainder
819 if ( *which_domain && !strequal(which_domain, domain->name) )
824 /* Get list of sam groups */
826 fstrcpy(groups.domain_name, domain->name);
828 get_sam_group_entries(&groups);
830 if (groups.num_sam_entries == 0) {
831 /* this domain is empty or in an error state */
835 /* keep track the of the total number of groups seen so
836 far over all domains */
837 total_entries += groups.num_sam_entries;
839 /* Allocate some memory for extra data. Note that we limit
840 account names to sizeof(fstring) = 128 characters. */
841 ted = SMB_REALLOC(extra_data, sizeof(fstring) * total_entries);
844 DEBUG(0,("failed to enlarge buffer!\n"));
845 SAFE_FREE(extra_data);
846 request_error(state);
851 /* Pack group list into extra data fields */
852 for (i = 0; i < groups.num_sam_entries; i++) {
853 char *group_name = ((struct acct_info *)
854 groups.sam_entries)[i].acct_name;
857 fill_domain_username(name, domain->name, group_name);
858 /* Append to extra data */
859 memcpy(&extra_data[extra_data_len], name,
861 extra_data_len += strlen(name);
862 extra_data[extra_data_len++] = ',';
865 SAFE_FREE(groups.sam_entries);
868 /* Assign extra_data fields in response structure */
870 extra_data[extra_data_len - 1] = '\0';
871 state->response.extra_data = extra_data;
872 state->response.length += extra_data_len;
875 /* No domains may have responded but that's still OK so don't
881 /* Get user supplementary groups. This is much quicker than trying to
882 invert the groups database. We merge the groups from the gids and
883 other_sids info3 fields as trusted domain, universal group
884 memberships, and nested groups (win2k native mode only) are not
885 returned by the getgroups RPC call but are present in the info3. */
887 struct getgroups_state {
888 struct winbindd_cli_state *state;
889 struct winbindd_domain *domain;
894 const DOM_SID *token_sids;
895 int i, num_token_sids;
901 static void getgroups_usersid_recv(void *private, BOOL success,
902 const DOM_SID *sid, enum SID_NAME_USE type);
903 static void getgroups_tokensids_recv(void *private, BOOL success,
904 DOM_SID *token_sids, int num_token_sids);
905 static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid);
907 void winbindd_getgroups(struct winbindd_cli_state *state)
909 struct getgroups_state *s;
911 /* Ensure null termination */
912 state->request.data.username
913 [sizeof(state->request.data.username)-1]='\0';
915 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
916 state->request.data.username));
918 /* Parse domain and username */
920 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
922 DEBUG(0, ("talloc failed\n"));
923 request_error(state);
929 if (!parse_domain_user_talloc(state->mem_ctx,
930 state->request.data.username,
931 &s->domname, &s->username)) {
932 DEBUG(0, ("Could not parse domain user: %s\n",
933 state->request.data.username));
934 request_error(state);
938 /* Get info for the domain */
940 s->domain = find_domain_from_name_noinit(s->domname);
942 if (s->domain == NULL) {
943 DEBUG(7, ("could not find domain entry for domain %s\n",
945 request_error(state);
949 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
950 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
951 "getgroups() for %s\\%s.\n", s->domname,
953 request_error(state);
957 /* Get rid and name type from name. The following costs 1 packet */
959 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
960 getgroups_usersid_recv, s);
963 static void getgroups_usersid_recv(void *private, BOOL success,
964 const DOM_SID *sid, enum SID_NAME_USE type)
966 struct getgroups_state *s = private;
969 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
970 request_error(s->state);
974 sid_copy(&s->user_sid, sid);
976 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
977 getgroups_tokensids_recv, s);
980 static void getgroups_tokensids_recv(void *private, BOOL success,
981 DOM_SID *token_sids, int num_token_sids)
983 struct getgroups_state *s = private;
985 /* We need at least the user sid and the primary group in the token,
986 * otherwise it's an error */
988 if ((!success) || (num_token_sids < 2)) {
989 request_error(s->state);
993 s->token_sids = token_sids;
994 s->num_token_sids = num_token_sids;
997 s->token_gids = NULL;
998 s->num_token_gids = 0;
1000 getgroups_sid2gid_recv(s, False, 0);
1003 static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid)
1005 struct getgroups_state *s = private;
1008 add_gid_to_array_unique(NULL, gid,
1010 &s->num_token_gids);
1012 if (s->i < s->num_token_sids) {
1013 const DOM_SID *sid = &s->token_sids[s->i];
1016 if (sid_equal(sid, &s->user_sid)) {
1017 getgroups_sid2gid_recv(s, False, 0);
1021 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1022 getgroups_sid2gid_recv, s);
1026 s->state->response.data.num_entries = s->num_token_gids;
1027 s->state->response.extra_data = s->token_gids;
1028 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1029 request_ok(s->state);
1032 /* Get user supplementary sids. This is equivalent to the
1033 winbindd_getgroups() function but it involves a SID->SIDs mapping
1034 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1035 idmap. This call is designed to be used with applications that need
1036 to do ACL evaluation themselves. Note that the cached info3 data is
1039 this function assumes that the SID that comes in is a user SID. If
1040 you pass in another type of SID then you may get unpredictable
1044 static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
1047 void winbindd_getusersids(struct winbindd_cli_state *state)
1051 /* Ensure null termination */
1052 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1054 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1055 if (user_sid == NULL) {
1056 DEBUG(1, ("talloc failed\n"));
1057 request_error(state);
1061 if (!string_to_sid(user_sid, state->request.data.sid)) {
1062 DEBUG(1, ("Could not get convert sid %s from string\n",
1063 state->request.data.sid));
1064 request_error(state);
1068 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1072 static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
1075 struct winbindd_cli_state *state = private;
1077 unsigned ofs, ret_size = 0;
1081 request_error(state);
1085 /* work out the response size */
1086 for (i = 0; i < num_sids; i++) {
1087 const char *s = sid_string_static(&sids[i]);
1088 ret_size += strlen(s) + 1;
1091 /* build the reply */
1092 ret = SMB_MALLOC(ret_size);
1094 DEBUG(0, ("malloc failed\n"));
1095 request_error(state);
1099 for (i = 0; i < num_sids; i++) {
1100 const char *s = sid_string_static(&sids[i]);
1101 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1102 ofs += strlen(ret+ofs) + 1;
1105 /* Send data back to client */
1106 state->response.data.num_entries = num_sids;
1107 state->response.extra_data = ret;
1108 state->response.length += ret_size;
1112 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1115 struct winbindd_domain *domain;
1117 /* Ensure null termination */
1118 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1120 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1121 DEBUG(1, ("Could not get convert sid %s from string\n",
1122 state->request.data.sid));
1123 request_error(state);
1127 /* Get info for the domain */
1128 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1129 DEBUG(0,("could not find domain entry for sid %s\n",
1130 sid_string_static(&user_sid)));
1131 request_error(state);
1135 sendto_domain(state, domain);
1138 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1139 struct winbindd_cli_state *state)
1144 int i, num_groups, len, bufsize;
1147 /* Ensure null termination */
1148 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1150 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1151 DEBUG(1, ("Could not get convert sid %s from string\n",
1152 state->request.data.sid));
1153 return WINBINDD_ERROR;
1156 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1157 &user_sid, &num_groups,
1159 if (!NT_STATUS_IS_OK(status))
1160 return WINBINDD_ERROR;
1162 if (num_groups == 0) {
1163 state->response.data.num_entries = 0;
1164 state->response.extra_data = NULL;
1169 state->response.extra_data = NULL;
1171 for (i=0; i<num_groups; i++) {
1172 sprintf_append(NULL, (char **)&state->response.extra_data,
1174 "%s\n", sid_string_static(&groups[i]));
1177 if (state->response.extra_data == NULL) {
1178 /* Hmmm. Allocation failed somewhere */
1179 return WINBINDD_ERROR;
1182 state->response.data.num_entries = num_groups;
1183 state->response.length += len+1;