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 static BOOL winbindd_setgrent_internal(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()) {
390 /* Free old static data if it exists */
392 if (state->getgrent_state != NULL) {
393 free_getent_state(state->getgrent_state);
394 state->getgrent_state = NULL;
397 /* Create sam pipes for each domain we know about */
399 for (domain = domain_list(); domain != NULL; domain = domain->next) {
400 struct getent_state *domain_state;
402 /* Create a state record for this domain */
404 /* don't add our domaina if we are a PDC or if we
405 are a member of a Samba domain */
407 if ( lp_winbind_trusted_domains_only() && domain->primary )
413 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
414 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
418 ZERO_STRUCTP(domain_state);
420 fstrcpy(domain_state->domain_name, domain->name);
422 /* Add to list of open domains */
424 DLIST_ADD(state->getgrent_state, domain_state);
427 state->getgrent_initialized = True;
431 void winbindd_setgrent(struct winbindd_cli_state *state)
433 if (winbindd_setgrent_internal(state)) {
436 request_error(state);
440 /* Close file pointer to ntdom group database */
442 void winbindd_endgrent(struct winbindd_cli_state *state)
444 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
446 free_getent_state(state->getgrent_state);
447 state->getgrent_initialized = False;
448 state->getgrent_state = NULL;
452 /* Get the list of domain groups and domain aliases for a domain. We fill in
453 the sam_entries and num_sam_entries fields with domain group information.
454 The dispinfo_ndx field is incremented to the index of the next group to
455 fetch. Return True if some groups were returned, False otherwise. */
457 static BOOL get_sam_group_entries(struct getent_state *ent)
461 struct acct_info *name_list = NULL, *tmp_name_list = NULL;
464 struct acct_info *sam_grp_entries = NULL;
465 struct winbindd_domain *domain;
467 if (ent->got_sam_entries)
470 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
471 ent->domain_name))) {
472 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
476 /* Free any existing group info */
478 SAFE_FREE(ent->sam_entries);
479 ent->num_sam_entries = 0;
480 ent->got_sam_entries = True;
482 /* Enumerate domain groups */
486 if (!(domain = find_domain_from_name(ent->domain_name))) {
487 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
491 /* always get the domain global groups */
493 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
495 if (!NT_STATUS_IS_OK(status)) {
496 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
501 /* Copy entries into return buffer */
504 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
505 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
510 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
513 ent->num_sam_entries = num_entries;
515 /* get the domain local groups if we are a member of a native win2k domain
516 and are not using LDAP to get the groups */
518 if ( ( lp_security() != SEC_ADS && domain->native_mode
519 && domain->primary) || domain->internal )
521 DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
523 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
525 if ( !NT_STATUS_IS_OK(status) ) {
526 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
530 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
532 /* Copy entries into return buffer */
535 if ( !(tmp_name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
537 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
540 SAFE_FREE( name_list );
544 name_list = tmp_name_list;
546 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
547 num_entries * sizeof(struct acct_info) );
550 ent->num_sam_entries += num_entries;
554 /* Fill in remaining fields */
556 ent->sam_entries = name_list;
557 ent->sam_entry_index = 0;
559 result = (ent->num_sam_entries > 0);
562 talloc_destroy(mem_ctx);
567 /* Fetch next group entry from ntdom database */
569 #define MAX_GETGRENT_GROUPS 500
571 void winbindd_getgrent(struct winbindd_cli_state *state)
573 struct getent_state *ent;
574 struct winbindd_gr *group_list = NULL;
575 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
576 char *new_extra_data, *gr_mem_list = NULL;
578 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
580 /* Check user has enabled this */
582 if (!lp_winbind_enum_groups()) {
583 request_error(state);
587 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
589 if ((state->response.extra_data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
590 request_error(state);
594 memset(state->response.extra_data, '\0',
595 num_groups * sizeof(struct winbindd_gr) );
597 state->response.data.num_entries = 0;
599 group_list = (struct winbindd_gr *)state->response.extra_data;
601 if (!state->getgrent_initialized)
602 winbindd_setgrent_internal(state);
604 if (!(ent = state->getgrent_state)) {
605 request_error(state);
609 /* Start sending back groups */
611 for (i = 0; i < num_groups; i++) {
612 struct acct_info *name_list = NULL;
613 fstring domain_group_name;
617 char *gr_mem, *new_gr_mem_list;
619 struct winbindd_domain *domain;
621 /* Do we need to fetch another chunk of groups? */
625 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
626 ent->sam_entry_index, ent->num_sam_entries));
628 if (ent->num_sam_entries == ent->sam_entry_index) {
630 while(ent && !get_sam_group_entries(ent)) {
631 struct getent_state *next_ent;
633 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
635 /* Free state information for this domain */
637 SAFE_FREE(ent->sam_entries);
639 next_ent = ent->next;
640 DLIST_REMOVE(state->getgrent_state, ent);
646 /* No more domains */
652 name_list = ent->sam_entries;
655 find_domain_from_name(ent->domain_name))) {
656 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
661 /* Lookup group info */
663 sid_copy(&group_sid, &domain->sid);
664 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
666 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid, 0))) {
668 DEBUG(1, ("could not look up gid for group %s\n",
669 name_list[ent->sam_entry_index].acct_name));
671 ent->sam_entry_index++;
675 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
676 (unsigned long)name_list[ent->sam_entry_index].rid));
678 /* Fill in group entry */
680 fill_domain_username(domain_group_name, ent->domain_name,
681 name_list[ent->sam_entry_index].acct_name);
683 result = fill_grent(&group_list[group_list_ndx],
685 name_list[ent->sam_entry_index].acct_name,
688 /* Fill in group membership entry */
692 group_list[group_list_ndx].num_gr_mem = 0;
696 /* Get group membership */
697 if (state->request.cmd == WINBINDD_GETGRLST) {
700 sid_copy(&member_sid, &domain->sid);
701 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
702 result = fill_grent_mem(
706 &group_list[group_list_ndx].num_gr_mem,
707 &gr_mem, &gr_mem_len);
712 /* Append to group membership list */
713 new_gr_mem_list = SMB_REALLOC( gr_mem_list, gr_mem_list_len + gr_mem_len);
715 if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
716 DEBUG(0, ("out of memory\n"));
717 SAFE_FREE(gr_mem_list);
722 DEBUG(10, ("list_len = %d, mem_len = %d\n",
723 gr_mem_list_len, gr_mem_len));
725 gr_mem_list = new_gr_mem_list;
727 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
732 group_list[group_list_ndx].gr_mem_ofs =
735 gr_mem_list_len += gr_mem_len;
738 ent->sam_entry_index++;
740 /* Add group to return list */
744 DEBUG(10, ("adding group num_entries = %d\n",
745 state->response.data.num_entries));
748 state->response.data.num_entries++;
750 state->response.length +=
751 sizeof(struct winbindd_gr);
754 DEBUG(0, ("could not lookup domain group %s\n",
759 /* Copy the list of group memberships to the end of the extra data */
761 if (group_list_ndx == 0)
764 new_extra_data = SMB_REALLOC(
765 state->response.extra_data,
766 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
768 if (!new_extra_data) {
769 DEBUG(0, ("out of memory\n"));
771 SAFE_FREE(state->response.extra_data);
772 SAFE_FREE(gr_mem_list);
773 request_error(state);
777 state->response.extra_data = new_extra_data;
779 memcpy(&((char *)state->response.extra_data)
780 [group_list_ndx * sizeof(struct winbindd_gr)],
781 gr_mem_list, gr_mem_list_len);
783 SAFE_FREE(gr_mem_list);
785 state->response.length += gr_mem_list_len;
787 DEBUG(10, ("returning %d groups, length = %d\n",
788 group_list_ndx, gr_mem_list_len));
794 if (group_list_ndx > 0)
797 request_error(state);
800 /* List domain groups without mapping to unix ids */
802 void winbindd_list_groups(struct winbindd_cli_state *state)
804 uint32 total_entries = 0;
805 struct winbindd_domain *domain;
806 const char *which_domain;
807 char *extra_data = NULL;
809 unsigned int extra_data_len = 0, i;
811 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
813 /* Ensure null termination */
814 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
815 which_domain = state->request.domain_name;
817 /* Enumerate over trusted domains */
819 for (domain = domain_list(); domain; domain = domain->next) {
820 struct getent_state groups;
822 /* if we have a domain name restricting the request and this
823 one in the list doesn't match, then just bypass the remainder
826 if ( *which_domain && !strequal(which_domain, domain->name) )
831 /* Get list of sam groups */
833 fstrcpy(groups.domain_name, domain->name);
835 get_sam_group_entries(&groups);
837 if (groups.num_sam_entries == 0) {
838 /* this domain is empty or in an error state */
842 /* keep track the of the total number of groups seen so
843 far over all domains */
844 total_entries += groups.num_sam_entries;
846 /* Allocate some memory for extra data. Note that we limit
847 account names to sizeof(fstring) = 128 characters. */
848 ted = SMB_REALLOC(extra_data, sizeof(fstring) * total_entries);
851 DEBUG(0,("failed to enlarge buffer!\n"));
852 SAFE_FREE(extra_data);
853 request_error(state);
858 /* Pack group list into extra data fields */
859 for (i = 0; i < groups.num_sam_entries; i++) {
860 char *group_name = ((struct acct_info *)
861 groups.sam_entries)[i].acct_name;
864 fill_domain_username(name, domain->name, group_name);
865 /* Append to extra data */
866 memcpy(&extra_data[extra_data_len], name,
868 extra_data_len += strlen(name);
869 extra_data[extra_data_len++] = ',';
872 SAFE_FREE(groups.sam_entries);
875 /* Assign extra_data fields in response structure */
877 extra_data[extra_data_len - 1] = '\0';
878 state->response.extra_data = extra_data;
879 state->response.length += extra_data_len;
882 /* No domains may have responded but that's still OK so don't
888 /* Get user supplementary groups. This is much quicker than trying to
889 invert the groups database. We merge the groups from the gids and
890 other_sids info3 fields as trusted domain, universal group
891 memberships, and nested groups (win2k native mode only) are not
892 returned by the getgroups RPC call but are present in the info3. */
894 struct getgroups_state {
895 struct winbindd_cli_state *state;
896 struct winbindd_domain *domain;
901 const DOM_SID *token_sids;
902 int i, num_token_sids;
908 static void getgroups_usersid_recv(void *private, BOOL success,
909 const DOM_SID *sid, enum SID_NAME_USE type);
910 static void getgroups_tokensids_recv(void *private, BOOL success,
911 DOM_SID *token_sids, int num_token_sids);
912 static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid);
914 void winbindd_getgroups(struct winbindd_cli_state *state)
916 struct getgroups_state *s;
918 /* Ensure null termination */
919 state->request.data.username
920 [sizeof(state->request.data.username)-1]='\0';
922 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
923 state->request.data.username));
925 /* Parse domain and username */
927 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
929 DEBUG(0, ("talloc failed\n"));
930 request_error(state);
936 if (!parse_domain_user_talloc(state->mem_ctx,
937 state->request.data.username,
938 &s->domname, &s->username)) {
939 DEBUG(0, ("Could not parse domain user: %s\n",
940 state->request.data.username));
941 request_error(state);
945 /* Get info for the domain */
947 s->domain = find_domain_from_name_noinit(s->domname);
949 if (s->domain == NULL) {
950 DEBUG(7, ("could not find domain entry for domain %s\n",
952 request_error(state);
956 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
957 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
958 "getgroups() for %s\\%s.\n", s->domname,
960 request_error(state);
964 /* Get rid and name type from name. The following costs 1 packet */
966 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
967 getgroups_usersid_recv, s);
970 static void getgroups_usersid_recv(void *private, BOOL success,
971 const DOM_SID *sid, enum SID_NAME_USE type)
973 struct getgroups_state *s = private;
976 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
977 request_error(s->state);
981 sid_copy(&s->user_sid, sid);
983 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
984 getgroups_tokensids_recv, s);
987 static void getgroups_tokensids_recv(void *private, BOOL success,
988 DOM_SID *token_sids, int num_token_sids)
990 struct getgroups_state *s = private;
992 /* We need at least the user sid and the primary group in the token,
993 * otherwise it's an error */
995 if ((!success) || (num_token_sids < 2)) {
996 request_error(s->state);
1000 s->token_sids = token_sids;
1001 s->num_token_sids = num_token_sids;
1004 s->token_gids = NULL;
1005 s->num_token_gids = 0;
1007 getgroups_sid2gid_recv(s, False, 0);
1010 static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid)
1012 struct getgroups_state *s = private;
1015 add_gid_to_array_unique(NULL, gid,
1017 &s->num_token_gids);
1019 if (s->i < s->num_token_sids) {
1020 const DOM_SID *sid = &s->token_sids[s->i];
1023 if (sid_equal(sid, &s->user_sid)) {
1024 getgroups_sid2gid_recv(s, False, 0);
1028 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1029 getgroups_sid2gid_recv, s);
1033 s->state->response.data.num_entries = s->num_token_gids;
1034 s->state->response.extra_data = s->token_gids;
1035 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1036 request_ok(s->state);
1039 /* Get user supplementary sids. This is equivalent to the
1040 winbindd_getgroups() function but it involves a SID->SIDs mapping
1041 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1042 idmap. This call is designed to be used with applications that need
1043 to do ACL evaluation themselves. Note that the cached info3 data is
1046 this function assumes that the SID that comes in is a user SID. If
1047 you pass in another type of SID then you may get unpredictable
1051 static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
1054 void winbindd_getusersids(struct winbindd_cli_state *state)
1058 /* Ensure null termination */
1059 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1061 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1062 if (user_sid == NULL) {
1063 DEBUG(1, ("talloc failed\n"));
1064 request_error(state);
1068 if (!string_to_sid(user_sid, state->request.data.sid)) {
1069 DEBUG(1, ("Could not get convert sid %s from string\n",
1070 state->request.data.sid));
1071 request_error(state);
1075 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1079 static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
1082 struct winbindd_cli_state *state = private;
1084 unsigned ofs, ret_size = 0;
1088 request_error(state);
1092 /* work out the response size */
1093 for (i = 0; i < num_sids; i++) {
1094 const char *s = sid_string_static(&sids[i]);
1095 ret_size += strlen(s) + 1;
1098 /* build the reply */
1099 ret = SMB_MALLOC(ret_size);
1101 DEBUG(0, ("malloc failed\n"));
1102 request_error(state);
1106 for (i = 0; i < num_sids; i++) {
1107 const char *s = sid_string_static(&sids[i]);
1108 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1109 ofs += strlen(ret+ofs) + 1;
1112 /* Send data back to client */
1113 state->response.data.num_entries = num_sids;
1114 state->response.extra_data = ret;
1115 state->response.length += ret_size;
1119 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1122 struct winbindd_domain *domain;
1124 /* Ensure null termination */
1125 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1127 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1128 DEBUG(1, ("Could not get convert sid %s from string\n",
1129 state->request.data.sid));
1130 request_error(state);
1134 /* Get info for the domain */
1135 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1136 DEBUG(0,("could not find domain entry for sid %s\n",
1137 sid_string_static(&user_sid)));
1138 request_error(state);
1142 sendto_domain(state, domain);
1145 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1146 struct winbindd_cli_state *state)
1151 int i, num_groups, len, bufsize;
1154 /* Ensure null termination */
1155 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1157 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1158 DEBUG(1, ("Could not get convert sid %s from string\n",
1159 state->request.data.sid));
1160 return WINBINDD_ERROR;
1163 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1164 &user_sid, &num_groups,
1166 if (!NT_STATUS_IS_OK(status))
1167 return WINBINDD_ERROR;
1169 if (num_groups == 0) {
1170 state->response.data.num_entries = 0;
1171 state->response.extra_data = NULL;
1176 state->response.extra_data = NULL;
1178 for (i=0; i<num_groups; i++) {
1179 sprintf_append(NULL, (char **)&state->response.extra_data,
1181 "%s\n", sid_string_static(&groups[i]));
1184 if (state->response.extra_data == NULL) {
1185 /* Hmmm. Allocation failed somewhere */
1186 return WINBINDD_ERROR;
1189 state->response.data.num_entries = num_groups;
1190 state->response.length += len+1;