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.
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.
29 #define DBGC_CLASS DBGC_WINBIND
31 /*********************************************************************
32 *********************************************************************/
34 static int gr_mem_buffer( char **buffer, char **members, int num_members )
40 if ( num_members == 0 ) {
45 for ( i=0; i<num_members; i++ )
46 len += strlen(members[i])+1;
48 *buffer = (char*)smb_xmalloc(len);
49 for ( i=0; i<num_members; i++ ) {
50 snprintf( &(*buffer)[idx], len-idx, "%s,", members[i]);
51 idx += strlen(members[i])+1;
53 /* terminate with NULL */
54 (*buffer)[len-1] = '\0';
59 /***************************************************************
60 Empty static struct for negative caching.
61 ****************************************************************/
63 /* Fill a grent structure from various other information */
65 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
66 const char *gr_name, gid_t unix_gid)
68 fstring full_group_name;
70 fill_domain_username(full_group_name, dom_name, gr_name);
72 gr->gr_gid = unix_gid;
74 /* Group name and password */
76 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
77 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
82 /* Fill in the group membership field of a NT group given by group_sid */
84 static BOOL fill_grent_mem(struct winbindd_domain *domain,
86 enum SID_NAME_USE group_name_type,
87 int *num_gr_mem, char **gr_mem, int *gr_mem_len)
89 DOM_SID **sid_mem = NULL;
91 uint32 *name_types = NULL;
92 unsigned int buf_len, buf_ndx, i;
93 char **names = NULL, *buf;
99 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
102 /* Initialise group membership information */
104 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
108 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
109 ((group_name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
111 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
112 sid_to_string(sid_string, group_sid), domain->name,
117 /* Lookup group members */
118 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
119 &sid_mem, &names, &name_types);
120 if (!NT_STATUS_IS_OK(status)) {
121 DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n",
122 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
127 DEBUG(10, ("looked up %d names\n", num_names));
129 if (DEBUGLEVEL >= 10) {
130 for (i = 0; i < num_names; i++)
131 DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
135 /* Add members to list */
138 buf_len = buf_ndx = 0;
142 for (i = 0; i < num_names; i++) {
149 DEBUG(10, ("processing name %s\n", the_name));
151 /* FIXME: need to cope with groups within groups. These
152 occur in Universal groups on a Windows 2000 native mode
155 if (name_types[i] != SID_NAME_USER) {
156 DEBUG(3, ("name %s isn't a domain user\n", the_name));
160 /* Don't bother with machine accounts */
162 if (the_name[strlen(the_name) - 1] == '$') {
163 DEBUG(10, ("%s is machine account\n", the_name));
167 /* Append domain name */
169 fill_domain_username(name, domain->name, the_name);
173 /* Add to list or calculate buffer length */
176 buf_len += len + 1; /* List is comma separated */
178 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
180 DEBUG(10, ("appending %s at ndx %d\n", name, len));
181 safe_strcpy(&buf[buf_ndx], name, len);
188 /* Allocate buffer */
190 if (!buf && buf_len != 0) {
191 if (!(buf = malloc(buf_len))) {
192 DEBUG(1, ("out of memory\n"));
196 memset(buf, 0, buf_len);
200 if (buf && buf_ndx > 0) {
201 buf[buf_ndx - 1] = '\0';
205 *gr_mem_len = buf_len;
207 DEBUG(10, ("num_mem = %d, len = %d, mem = %s\n", *num_gr_mem,
208 buf_len, *num_gr_mem ? buf : "NULL"));
213 talloc_destroy(mem_ctx);
215 DEBUG(10, ("fill_grent_mem returning %d\n", result));
220 /* Return a group structure from a group name */
222 enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
226 struct winbindd_domain *domain;
227 enum SID_NAME_USE name_type;
228 fstring name_domain, name_group;
233 /* Ensure null termination */
234 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
236 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
237 state->request.data.groupname));
239 /* Parse domain and groupname */
241 memset(name_group, 0, sizeof(fstring));
243 tmp = state->request.data.groupname;
245 parse_domain_user(tmp, name_domain, name_group);
247 /* if no domain or our local domain, then do a local tdb search */
249 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
252 if ( !(grp=wb_getgrnam(name_group)) ) {
253 DEBUG(5,("winbindd_getgrnam: lookup for %s\\%s failed\n",
254 name_domain, name_group));
255 return WINBINDD_ERROR;
257 memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) );
259 gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem );
261 state->response.data.gr.gr_mem_ofs = 0;
262 state->response.length += gr_mem_len;
263 state->response.extra_data = buffer; /* give the memory away */
268 /* should we deal with users for our domain? */
270 if ( lp_winbind_trusted_domains_only() && strequal(name_domain, lp_workgroup())) {
271 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n",
272 name_domain, name_group));
273 return WINBINDD_ERROR;
277 /* Get info for the domain */
279 if ((domain = find_domain_from_name(name_domain)) == NULL) {
280 DEBUG(0, ("could not get domain sid for domain %s\n",
282 return WINBINDD_ERROR;
285 /* Get rid and name type from name */
287 if (!winbindd_lookup_sid_by_name(domain, name_group, &group_sid,
289 DEBUG(1, ("group %s in domain %s does not exist\n",
290 name_group, name_domain));
291 return WINBINDD_ERROR;
294 if ( !((name_type==SID_NAME_DOM_GRP) ||
295 ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
297 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
298 name_group, name_type));
299 return WINBINDD_ERROR;
302 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid, 0))) {
303 DEBUG(1, ("error converting unix gid to sid\n"));
304 return WINBINDD_ERROR;
307 if (!fill_grent(&state->response.data.gr, name_domain,
309 !fill_grent_mem(domain, &group_sid, name_type,
310 &state->response.data.gr.num_gr_mem,
311 &gr_mem, &gr_mem_len)) {
312 return WINBINDD_ERROR;
315 /* Group membership lives at start of extra data */
317 state->response.data.gr.gr_mem_ofs = 0;
319 state->response.length += gr_mem_len;
320 state->response.extra_data = gr_mem;
325 /* Return a group structure from a gid number */
327 enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
329 struct winbindd_domain *domain;
332 enum SID_NAME_USE name_type;
338 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
339 (unsigned long)state->request.data.gid));
341 /* Bug out if the gid isn't in the winbind range */
343 if ((state->request.data.gid < server_state.gid_low) ||
344 (state->request.data.gid > server_state.gid_high))
345 return WINBINDD_ERROR;
347 /* alway try local tdb lookup first */
348 if ( ( grp=wb_getgrgid(state->request.data.gid)) != NULL ) {
351 memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) );
353 gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem );
355 state->response.data.gr.gr_mem_ofs = 0;
356 state->response.length += gr_mem_len;
357 state->response.extra_data = buffer; /* give away the memory */
362 /* Get rid from gid */
363 if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
364 DEBUG(1, ("could not convert gid %lu to rid\n",
365 (unsigned long)state->request.data.gid));
366 return WINBINDD_ERROR;
369 /* Get name from sid */
371 if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
372 DEBUG(1, ("could not lookup sid\n"));
373 return WINBINDD_ERROR;
376 /* Fill in group structure */
378 domain = find_domain_from_sid(&group_sid);
381 DEBUG(1,("Can't find domain from sid\n"));
382 return WINBINDD_ERROR;
385 if ( !((name_type==SID_NAME_DOM_GRP) ||
386 ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
388 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
389 group_name, name_type));
390 return WINBINDD_ERROR;
393 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
394 state->request.data.gid) ||
395 !fill_grent_mem(domain, &group_sid, name_type,
396 &state->response.data.gr.num_gr_mem,
397 &gr_mem, &gr_mem_len))
398 return WINBINDD_ERROR;
400 /* Group membership lives at start of extra data */
402 state->response.data.gr.gr_mem_ofs = 0;
404 state->response.length += gr_mem_len;
405 state->response.extra_data = gr_mem;
411 * set/get/endgrent functions
414 /* "Rewind" file pointer for group database enumeration */
416 enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
418 struct winbindd_domain *domain;
420 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
422 /* Check user has enabled this */
424 if (!lp_winbind_enum_groups())
425 return WINBINDD_ERROR;
427 /* Free old static data if it exists */
429 if (state->getgrent_state != NULL) {
430 free_getent_state(state->getgrent_state);
431 state->getgrent_state = NULL;
434 /* Create sam pipes for each domain we know about */
436 for (domain = domain_list(); domain != NULL; domain = domain->next) {
437 struct getent_state *domain_state;
440 /* don't add our domaina if we are a PDC or if we
441 are a member of a Samba domain */
443 if ( (IS_DC || lp_winbind_trusted_domains_only())
444 && strequal(domain->name, lp_workgroup()) )
449 /* Create a state record for this domain */
451 if ((domain_state = (struct getent_state *)
452 malloc(sizeof(struct getent_state))) == NULL) {
453 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
454 return WINBINDD_ERROR;
457 ZERO_STRUCTP(domain_state);
459 fstrcpy(domain_state->domain_name, domain->name);
461 /* Add to list of open domains */
463 DLIST_ADD(state->getgrent_state, domain_state);
469 /* Close file pointer to ntdom group database */
471 enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
473 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
475 free_getent_state(state->getgrent_state);
476 state->getgrent_state = NULL;
481 /* Get the list of domain groups and domain aliases for a domain. We fill in
482 the sam_entries and num_sam_entries fields with domain group information.
483 The dispinfo_ndx field is incremented to the index of the next group to
484 fetch. Return True if some groups were returned, False otherwise. */
486 #define MAX_FETCH_SAM_ENTRIES 100
488 static BOOL get_sam_group_entries(struct getent_state *ent)
492 struct acct_info *name_list = NULL, *tmp_name_list = NULL;
495 struct acct_info *sam_grp_entries = NULL;
496 struct winbindd_domain *domain;
498 if (ent->got_sam_entries)
501 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
502 ent->domain_name))) {
503 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
507 /* Free any existing group info */
509 SAFE_FREE(ent->sam_entries);
510 ent->num_sam_entries = 0;
511 ent->got_sam_entries = True;
513 /* Enumerate domain groups */
517 if (!(domain = find_domain_from_name(ent->domain_name))) {
518 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
522 /* always get the domain global groups */
524 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
526 if (!NT_STATUS_IS_OK(status)) {
527 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
532 /* Copy entries into return buffer */
535 if ( !(name_list = malloc(sizeof(struct acct_info) * num_entries)) ) {
536 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
541 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
544 ent->num_sam_entries = num_entries;
546 /* get the domain local groups if we are a member of a native win2k domain
547 and are not using LDAP to get the groups */
549 if ( lp_security() != SEC_ADS && domain->native_mode
550 && strequal(lp_workgroup(), domain->name) )
552 DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
554 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
556 if ( !NT_STATUS_IS_OK(status) ) {
557 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
561 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
563 /* Copy entries into return buffer */
566 if ( !(tmp_name_list = Realloc( name_list, sizeof(struct acct_info) * (ent->num_sam_entries+num_entries))) )
568 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
571 SAFE_FREE( name_list );
575 name_list = tmp_name_list;
577 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
578 num_entries * sizeof(struct acct_info) );
581 ent->num_sam_entries += num_entries;
585 /* Fill in remaining fields */
587 ent->sam_entries = name_list;
588 ent->sam_entry_index = 0;
590 result = (ent->num_sam_entries > 0);
593 talloc_destroy(mem_ctx);
598 /* Fetch next group entry from ntdom database */
600 #define MAX_GETGRENT_GROUPS 500
602 enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
604 struct getent_state *ent;
605 struct winbindd_gr *group_list = NULL;
606 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
607 char *new_extra_data, *gr_mem_list = NULL;
609 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
611 /* Check user has enabled this */
613 if (!lp_winbind_enum_groups())
614 return WINBINDD_ERROR;
616 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
618 if ((state->response.extra_data =
619 malloc(num_groups * sizeof(struct winbindd_gr))) == NULL)
620 return WINBINDD_ERROR;
622 state->response.data.num_entries = 0;
624 group_list = (struct winbindd_gr *)state->response.extra_data;
626 if (!(ent = state->getgrent_state))
627 return WINBINDD_ERROR;
629 /* Start sending back groups */
631 for (i = 0; i < num_groups; i++) {
632 struct acct_info *name_list = NULL;
633 fstring domain_group_name;
637 char *gr_mem, *new_gr_mem_list;
639 struct winbindd_domain *domain;
641 /* Do we need to fetch another chunk of groups? */
645 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
646 ent->sam_entry_index, ent->num_sam_entries));
648 if (ent->num_sam_entries == ent->sam_entry_index) {
650 while(ent && !get_sam_group_entries(ent)) {
651 struct getent_state *next_ent;
653 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
655 /* Free state information for this domain */
657 SAFE_FREE(ent->sam_entries);
659 next_ent = ent->next;
660 DLIST_REMOVE(state->getgrent_state, ent);
666 /* No more domains */
672 name_list = ent->sam_entries;
675 find_domain_from_name(ent->domain_name))) {
676 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
681 /* Lookup group info */
683 sid_copy(&group_sid, &domain->sid);
684 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
686 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid, 0))) {
688 DEBUG(1, ("could not look up gid for group %s\n",
689 name_list[ent->sam_entry_index].acct_name));
691 ent->sam_entry_index++;
695 DEBUG(10, ("got gid %lu for group %x\n", (unsigned long)group_gid,
696 name_list[ent->sam_entry_index].rid));
698 /* Fill in group entry */
700 fill_domain_username(domain_group_name, ent->domain_name,
701 name_list[ent->sam_entry_index].acct_name);
703 result = fill_grent(&group_list[group_list_ndx],
705 name_list[ent->sam_entry_index].acct_name,
708 /* Fill in group membership entry */
712 group_list[group_list_ndx].num_gr_mem = 0;
716 /* Get group membership */
717 if (state->request.cmd == WINBINDD_GETGRLST) {
720 sid_copy(&member_sid, &domain->sid);
721 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
722 result = fill_grent_mem(
726 &group_list[group_list_ndx].num_gr_mem,
727 &gr_mem, &gr_mem_len);
732 /* Append to group membership list */
733 new_gr_mem_list = Realloc(
735 gr_mem_list_len + gr_mem_len);
737 if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
738 DEBUG(0, ("out of memory\n"));
739 SAFE_FREE(gr_mem_list);
744 DEBUG(10, ("list_len = %d, mem_len = %d\n",
745 gr_mem_list_len, gr_mem_len));
747 gr_mem_list = new_gr_mem_list;
749 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
754 group_list[group_list_ndx].gr_mem_ofs =
757 gr_mem_list_len += gr_mem_len;
760 ent->sam_entry_index++;
762 /* Add group to return list */
766 DEBUG(10, ("adding group num_entries = %d\n",
767 state->response.data.num_entries));
770 state->response.data.num_entries++;
772 state->response.length +=
773 sizeof(struct winbindd_gr);
776 DEBUG(0, ("could not lookup domain group %s\n",
781 /* Copy the list of group memberships to the end of the extra data */
783 if (group_list_ndx == 0)
786 new_extra_data = Realloc(
787 state->response.extra_data,
788 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
790 if (!new_extra_data) {
791 DEBUG(0, ("out of memory\n"));
793 SAFE_FREE(state->response.extra_data);
794 SAFE_FREE(gr_mem_list);
796 return WINBINDD_ERROR;
799 state->response.extra_data = new_extra_data;
801 memcpy(&((char *)state->response.extra_data)
802 [group_list_ndx * sizeof(struct winbindd_gr)],
803 gr_mem_list, gr_mem_list_len);
805 SAFE_FREE(gr_mem_list);
807 state->response.length += gr_mem_list_len;
809 DEBUG(10, ("returning %d groups, length = %d\n",
810 group_list_ndx, gr_mem_list_len));
816 return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
819 /* List domain groups without mapping to unix ids */
821 enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
823 uint32 total_entries = 0;
824 struct winbindd_domain *domain;
825 const char *which_domain;
826 char *extra_data = NULL;
828 unsigned int extra_data_len = 0, i;
830 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
832 /* Ensure null termination */
833 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
834 which_domain = state->request.domain_name;
836 /* Enumerate over trusted domains */
838 for (domain = domain_list(); domain; domain = domain->next) {
839 struct getent_state groups;
841 /* if we have a domain name restricting the request and this
842 one in the list doesn't match, then just bypass the remainder
845 if ( *which_domain && !strequal(which_domain, domain->name) )
850 /* Get list of sam groups */
852 fstrcpy(groups.domain_name, domain->name);
854 get_sam_group_entries(&groups);
856 if (groups.num_sam_entries == 0) {
857 /* this domain is empty or in an error state */
861 /* keep track the of the total number of groups seen so
862 far over all domains */
863 total_entries += groups.num_sam_entries;
865 /* Allocate some memory for extra data. Note that we limit
866 account names to sizeof(fstring) = 128 characters. */
867 ted = Realloc(extra_data, sizeof(fstring) * total_entries);
870 DEBUG(0,("failed to enlarge buffer!\n"));
871 SAFE_FREE(extra_data);
872 return WINBINDD_ERROR;
876 /* Pack group list into extra data fields */
877 for (i = 0; i < groups.num_sam_entries; i++) {
878 char *group_name = ((struct acct_info *)
879 groups.sam_entries)[i].acct_name;
882 fill_domain_username(name, domain->name, group_name);
883 /* Append to extra data */
884 memcpy(&extra_data[extra_data_len], name,
886 extra_data_len += strlen(name);
887 extra_data[extra_data_len++] = ',';
890 free(groups.sam_entries);
893 /* Assign extra_data fields in response structure */
895 extra_data[extra_data_len - 1] = '\0';
896 state->response.extra_data = extra_data;
897 state->response.length += extra_data_len;
900 /* No domains may have responded but that's still OK so don't
906 /* Get user supplementary groups. This is much quicker than trying to
907 invert the groups database. We merge the groups from the gids and
908 other_sids info3 fields as trusted domain, universal group
909 memberships, and nested groups (win2k native mode only) are not
910 returned by the getgroups RPC call but are present in the info3. */
912 enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
914 fstring name_domain, name_user;
915 DOM_SID user_sid, group_sid;
916 enum SID_NAME_USE name_type;
917 uint32 num_groups = 0;
920 DOM_SID **user_grpsids;
921 struct winbindd_domain *domain;
922 enum winbindd_result result = WINBINDD_ERROR;
926 NET_USER_INFO_3 *info3 = NULL;
928 /* Ensure null termination */
929 state->request.data.username[sizeof(state->request.data.username)-1]='\0';
931 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
932 state->request.data.username));
934 if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
935 state->request.data.username)))
936 return WINBINDD_ERROR;
938 /* Parse domain and username */
940 parse_domain_user(state->request.data.username,
941 name_domain, name_user);
943 /* bail if there is no domain */
948 /* Get info for the domain */
950 if ((domain = find_domain_from_name(name_domain)) == NULL) {
951 DEBUG(0, ("could not find domain entry for domain %s\n",
956 /* Get rid and name type from name. The following costs 1 packet */
958 if (!winbindd_lookup_sid_by_name(domain, name_user, &user_sid,
960 DEBUG(1, ("user '%s' does not exist\n", name_user));
964 if (name_type != SID_NAME_USER) {
965 DEBUG(1, ("name '%s' is not a user name: %d\n",
966 name_user, name_type));
970 /* Treat the info3 cache as authoritative as the
971 lookup_usergroups() function may return cached data. */
973 if ((info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) {
975 DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n",
976 info3->num_groups2, info3->num_other_sids));
978 num_groups = info3->num_other_sids + info3->num_groups2;
979 gid_list = calloc(sizeof(gid_t), num_groups);
981 /* Go through each other sid and convert it to a gid */
983 for (i = 0; i < info3->num_other_sids; i++) {
986 enum SID_NAME_USE sid_type;
988 /* Is this sid known to us? It can either be
989 a trusted domain sid or a foreign sid. */
991 if (!winbindd_lookup_name_by_sid( &info3->other_sids[i].sid,
992 dom_name, name, &sid_type))
994 DEBUG(10, ("winbindd_getgroups: could not lookup name for %s\n",
995 sid_string_static(&info3->other_sids[i].sid)));
999 /* Check it is a domain group or an alias (domain local group)
1000 in a win2k native mode domain. */
1002 if ( !((sid_type==SID_NAME_DOM_GRP) ||
1003 ((sid_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
1005 DEBUG(10, ("winbindd_getgroups: sid type %d "
1006 "for %s is not a domain group\n",
1009 &info3->other_sids[i].sid)));
1015 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&info3->other_sids[i].sid, &gid_list[num_gids], 0)) )
1017 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
1018 sid_string_static(&info3->other_sids[i].sid)));
1022 /* We've jumped through a lot of hoops to get here */
1024 DEBUG(10, ("winbindd_getgroups: mapped other sid %s to "
1025 "gid %lu\n", sid_string_static(
1026 &info3->other_sids[i].sid),
1027 (unsigned long)gid_list[num_gids]));
1032 for (i = 0; i < info3->num_groups2; i++) {
1034 /* create the group SID */
1036 sid_copy( &group_sid, &domain->sid );
1037 sid_append_rid( &group_sid, info3->gids[i].g_rid );
1039 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid_list[num_gids], 0)) ) {
1040 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
1041 sid_string_static(&group_sid)));
1050 status = domain->methods->lookup_usergroups(domain, mem_ctx,
1051 &user_sid, &num_groups,
1053 if (!NT_STATUS_IS_OK(status))
1056 gid_list = malloc(sizeof(gid_t) * num_groups);
1058 if (state->response.extra_data)
1061 for (i = 0; i < num_groups; i++) {
1062 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_grpsids[i], &gid_list[num_gids], 0))) {
1063 DEBUG(1, ("unable to convert group sid %s to gid\n",
1064 sid_string_static(user_grpsids[i])));
1071 /* Send data back to client */
1073 state->response.data.num_entries = num_gids;
1074 state->response.extra_data = gid_list;
1075 state->response.length += num_gids * sizeof(gid_t);
1077 result = WINBINDD_OK;
1081 talloc_destroy(mem_ctx);
1087 /* Get user supplementary sids. This is equivalent to the
1088 winbindd_getgroups() function but it involves a SID->SIDs mapping
1089 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1090 idmap. This call is designed to be used with applications that need
1091 to do ACL evaluation themselves. Note that the cached info3 data is
1094 this function assumes that the SID that comes in is a user SID. If
1095 you pass in another type of SID then you may get unpredictable
1098 enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
1102 DOM_SID **user_grpsids;
1103 struct winbindd_domain *domain;
1104 enum winbindd_result result = WINBINDD_ERROR;
1106 TALLOC_CTX *mem_ctx;
1109 unsigned ofs, ret_size = 0;
1111 /* Ensure null termination */
1112 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1114 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1115 DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
1116 return WINBINDD_ERROR;
1119 if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)",
1120 state->request.data.username))) {
1121 return WINBINDD_ERROR;
1124 /* Get info for the domain */
1125 if ((domain = find_domain_from_sid(&user_sid)) == NULL) {
1126 DEBUG(0,("could not find domain entry for sid %s\n",
1127 sid_string_static(&user_sid)));
1131 status = domain->methods->lookup_usergroups(domain, mem_ctx,
1132 &user_sid, &num_groups,
1134 if (!NT_STATUS_IS_OK(status))
1137 if (num_groups == 0) {
1141 /* work out the response size */
1142 for (i = 0; i < num_groups; i++) {
1143 const char *s = sid_string_static(user_grpsids[i]);
1144 ret_size += strlen(s) + 1;
1147 /* build the reply */
1148 ret = malloc(ret_size);
1149 if (!ret) goto done;
1151 for (i = 0; i < num_groups; i++) {
1152 const char *s = sid_string_static(user_grpsids[i]);
1153 safe_strcpy(ret + ofs, s, ret_size - ofs);
1154 ofs += strlen(ret+ofs) + 1;
1158 /* Send data back to client */
1159 state->response.data.num_entries = num_groups;
1160 state->response.extra_data = ret;
1161 state->response.length += ret_size;
1162 result = WINBINDD_OK;
1165 talloc_destroy(mem_ctx);