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], sid_to_string(sid_string, sid_mem[i]),
119 /* Add members to list */
122 buf_len = buf_ndx = 0;
126 for (i = 0; i < num_names; i++) {
133 DEBUG(10, ("processing name %s\n", the_name));
135 /* FIXME: need to cope with groups within groups. These
136 occur in Universal groups on a Windows 2000 native mode
139 /* make sure to allow machine accounts */
141 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
142 DEBUG(3, ("name %s isn't a domain user\n", the_name));
146 /* Append domain name */
148 fill_domain_username(name, domain->name, the_name);
152 /* Add to list or calculate buffer length */
155 buf_len += len + 1; /* List is comma separated */
157 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
159 DEBUG(10, ("appending %s at ndx %d\n", name, len));
160 safe_strcpy(&buf[buf_ndx], name, len);
167 /* Allocate buffer */
169 if (!buf && buf_len != 0) {
170 if (!(buf = SMB_MALLOC(buf_len))) {
171 DEBUG(1, ("out of memory\n"));
175 memset(buf, 0, buf_len);
179 if (buf && buf_ndx > 0) {
180 buf[buf_ndx - 1] = '\0';
184 *gr_mem_len = buf_len;
186 DEBUG(10, ("num_mem = %d, len = %d, mem = %s\n", *num_gr_mem,
187 buf_len, *num_gr_mem ? buf : "NULL"));
192 talloc_destroy(mem_ctx);
194 DEBUG(10, ("fill_grent_mem returning %d\n", result));
199 /* Return a group structure from a group name */
201 enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
204 struct winbindd_domain *domain;
205 enum SID_NAME_USE name_type;
206 fstring name_domain, name_group;
211 /* Ensure null termination */
212 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
214 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
215 state->request.data.groupname));
217 /* Parse domain and groupname */
219 memset(name_group, 0, sizeof(fstring));
221 tmp = state->request.data.groupname;
223 parse_domain_user(tmp, name_domain, name_group);
225 /* if no domain or our local domain, default to our local domain for aliases */
227 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
228 fstrcpy(name_domain, get_global_sam_name());
231 /* Get info for the domain */
233 if ((domain = find_domain_from_name(name_domain)) == NULL) {
234 DEBUG(3, ("could not get domain sid for domain %s\n",
236 return WINBINDD_ERROR;
238 /* should we deal with users for our domain? */
240 if ( lp_winbind_trusted_domains_only() && domain->primary) {
241 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n",
242 name_domain, name_group));
243 return WINBINDD_ERROR;
246 /* Get rid and name type from name */
248 if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid,
250 DEBUG(1, ("group %s in domain %s does not exist\n",
251 name_group, name_domain));
252 return WINBINDD_ERROR;
255 if ( !((name_type==SID_NAME_DOM_GRP) ||
256 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
257 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
259 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
260 name_group, name_type));
261 return WINBINDD_ERROR;
264 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid, 0))) {
265 DEBUG(1, ("error converting unix gid to sid\n"));
266 return WINBINDD_ERROR;
269 if (!fill_grent(&state->response.data.gr, name_domain,
271 !fill_grent_mem(domain, &group_sid, name_type,
272 &state->response.data.gr.num_gr_mem,
273 &gr_mem, &gr_mem_len)) {
274 return WINBINDD_ERROR;
277 /* Group membership lives at start of extra data */
279 state->response.data.gr.gr_mem_ofs = 0;
281 state->response.length += gr_mem_len;
282 state->response.extra_data = gr_mem;
287 /* Return a group structure from a gid number */
289 enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
291 struct winbindd_domain *domain;
293 enum SID_NAME_USE name_type;
299 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
300 (unsigned long)state->request.data.gid));
302 /* Bug out if the gid isn't in the winbind range */
304 if ((state->request.data.gid < server_state.gid_low) ||
305 (state->request.data.gid > server_state.gid_high))
306 return WINBINDD_ERROR;
308 /* Get rid from gid */
309 if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
310 DEBUG(1, ("could not convert gid %lu to rid\n",
311 (unsigned long)state->request.data.gid));
312 return WINBINDD_ERROR;
315 /* Get name from sid */
317 if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
318 DEBUG(1, ("could not lookup sid\n"));
319 return WINBINDD_ERROR;
322 /* Fill in group structure */
324 domain = find_domain_from_sid(&group_sid);
327 DEBUG(1,("Can't find domain from sid\n"));
328 return WINBINDD_ERROR;
331 if ( !((name_type==SID_NAME_DOM_GRP) ||
332 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
333 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
335 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
336 group_name, name_type));
337 return WINBINDD_ERROR;
340 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
341 state->request.data.gid) ||
342 !fill_grent_mem(domain, &group_sid, name_type,
343 &state->response.data.gr.num_gr_mem,
344 &gr_mem, &gr_mem_len))
345 return WINBINDD_ERROR;
347 /* Group membership lives at start of extra data */
349 state->response.data.gr.gr_mem_ofs = 0;
351 state->response.length += gr_mem_len;
352 state->response.extra_data = gr_mem;
358 * set/get/endgrent functions
361 /* "Rewind" file pointer for group database enumeration */
363 enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
365 struct winbindd_domain *domain;
367 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
369 /* Check user has enabled this */
371 if (!lp_winbind_enum_groups())
372 return WINBINDD_ERROR;
374 /* Free old static data if it exists */
376 if (state->getgrent_state != NULL) {
377 free_getent_state(state->getgrent_state);
378 state->getgrent_state = NULL;
381 /* Create sam pipes for each domain we know about */
383 for (domain = domain_list(); domain != NULL; domain = domain->next) {
384 struct getent_state *domain_state;
386 /* Create a state record for this domain */
388 /* don't add our domaina if we are a PDC or if we
389 are a member of a Samba domain */
391 if ( lp_winbind_trusted_domains_only() && domain->primary )
397 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
398 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
399 return WINBINDD_ERROR;
402 ZERO_STRUCTP(domain_state);
404 fstrcpy(domain_state->domain_name, domain->name);
406 /* Add to list of open domains */
408 DLIST_ADD(state->getgrent_state, domain_state);
411 state->getgrent_initialized = True;
416 /* Close file pointer to ntdom group database */
418 enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
420 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
422 free_getent_state(state->getgrent_state);
423 state->getgrent_initialized = False;
424 state->getgrent_state = NULL;
429 /* Get the list of domain groups and domain aliases for a domain. We fill in
430 the sam_entries and num_sam_entries fields with domain group information.
431 The dispinfo_ndx field is incremented to the index of the next group to
432 fetch. Return True if some groups were returned, False otherwise. */
434 static BOOL get_sam_group_entries(struct getent_state *ent)
438 struct acct_info *name_list = NULL, *tmp_name_list = NULL;
441 struct acct_info *sam_grp_entries = NULL;
442 struct winbindd_domain *domain;
444 if (ent->got_sam_entries)
447 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
448 ent->domain_name))) {
449 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
453 /* Free any existing group info */
455 SAFE_FREE(ent->sam_entries);
456 ent->num_sam_entries = 0;
457 ent->got_sam_entries = True;
459 /* Enumerate domain groups */
463 if (!(domain = find_domain_from_name(ent->domain_name))) {
464 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
468 /* always get the domain global groups */
470 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
472 if (!NT_STATUS_IS_OK(status)) {
473 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
478 /* Copy entries into return buffer */
481 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
482 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
487 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
490 ent->num_sam_entries = num_entries;
492 /* get the domain local groups if we are a member of a native win2k domain
493 and are not using LDAP to get the groups */
495 if ( ( lp_security() != SEC_ADS && domain->native_mode
496 && domain->primary) || domain->internal )
498 DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
500 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
502 if ( !NT_STATUS_IS_OK(status) ) {
503 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
507 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
509 /* Copy entries into return buffer */
512 if ( !(tmp_name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
514 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
517 SAFE_FREE( name_list );
521 name_list = tmp_name_list;
523 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
524 num_entries * sizeof(struct acct_info) );
527 ent->num_sam_entries += num_entries;
531 /* Fill in remaining fields */
533 ent->sam_entries = name_list;
534 ent->sam_entry_index = 0;
536 result = (ent->num_sam_entries > 0);
539 talloc_destroy(mem_ctx);
544 /* Fetch next group entry from ntdom database */
546 #define MAX_GETGRENT_GROUPS 500
548 enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
550 struct getent_state *ent;
551 struct winbindd_gr *group_list = NULL;
552 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
553 char *new_extra_data, *gr_mem_list = NULL;
555 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
557 /* Check user has enabled this */
559 if (!lp_winbind_enum_groups())
560 return WINBINDD_ERROR;
562 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
564 if ((state->response.extra_data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL)
565 return WINBINDD_ERROR;
567 memset(state->response.extra_data, '\0',
568 num_groups * sizeof(struct winbindd_gr) );
570 state->response.data.num_entries = 0;
572 group_list = (struct winbindd_gr *)state->response.extra_data;
574 if (!state->getgrent_initialized)
575 winbindd_setgrent(state);
577 if (!(ent = state->getgrent_state))
578 return WINBINDD_ERROR;
580 /* Start sending back groups */
582 for (i = 0; i < num_groups; i++) {
583 struct acct_info *name_list = NULL;
584 fstring domain_group_name;
588 char *gr_mem, *new_gr_mem_list;
590 struct winbindd_domain *domain;
592 /* Do we need to fetch another chunk of groups? */
596 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
597 ent->sam_entry_index, ent->num_sam_entries));
599 if (ent->num_sam_entries == ent->sam_entry_index) {
601 while(ent && !get_sam_group_entries(ent)) {
602 struct getent_state *next_ent;
604 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
606 /* Free state information for this domain */
608 SAFE_FREE(ent->sam_entries);
610 next_ent = ent->next;
611 DLIST_REMOVE(state->getgrent_state, ent);
617 /* No more domains */
623 name_list = ent->sam_entries;
626 find_domain_from_name(ent->domain_name))) {
627 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
632 /* Lookup group info */
634 sid_copy(&group_sid, &domain->sid);
635 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
637 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid, 0))) {
639 DEBUG(1, ("could not look up gid for group %s\n",
640 name_list[ent->sam_entry_index].acct_name));
642 ent->sam_entry_index++;
646 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
647 (unsigned long)name_list[ent->sam_entry_index].rid));
649 /* Fill in group entry */
651 fill_domain_username(domain_group_name, ent->domain_name,
652 name_list[ent->sam_entry_index].acct_name);
654 result = fill_grent(&group_list[group_list_ndx],
656 name_list[ent->sam_entry_index].acct_name,
659 /* Fill in group membership entry */
663 group_list[group_list_ndx].num_gr_mem = 0;
667 /* Get group membership */
668 if (state->request.cmd == WINBINDD_GETGRLST) {
671 sid_copy(&member_sid, &domain->sid);
672 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
673 result = fill_grent_mem(
677 &group_list[group_list_ndx].num_gr_mem,
678 &gr_mem, &gr_mem_len);
683 /* Append to group membership list */
684 new_gr_mem_list = SMB_REALLOC( gr_mem_list, gr_mem_list_len + gr_mem_len);
686 if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
687 DEBUG(0, ("out of memory\n"));
688 SAFE_FREE(gr_mem_list);
693 DEBUG(10, ("list_len = %d, mem_len = %d\n",
694 gr_mem_list_len, gr_mem_len));
696 gr_mem_list = new_gr_mem_list;
698 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
703 group_list[group_list_ndx].gr_mem_ofs =
706 gr_mem_list_len += gr_mem_len;
709 ent->sam_entry_index++;
711 /* Add group to return list */
715 DEBUG(10, ("adding group num_entries = %d\n",
716 state->response.data.num_entries));
719 state->response.data.num_entries++;
721 state->response.length +=
722 sizeof(struct winbindd_gr);
725 DEBUG(0, ("could not lookup domain group %s\n",
730 /* Copy the list of group memberships to the end of the extra data */
732 if (group_list_ndx == 0)
735 new_extra_data = SMB_REALLOC(
736 state->response.extra_data,
737 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
739 if (!new_extra_data) {
740 DEBUG(0, ("out of memory\n"));
742 SAFE_FREE(state->response.extra_data);
743 SAFE_FREE(gr_mem_list);
745 return WINBINDD_ERROR;
748 state->response.extra_data = new_extra_data;
750 memcpy(&((char *)state->response.extra_data)
751 [group_list_ndx * sizeof(struct winbindd_gr)],
752 gr_mem_list, gr_mem_list_len);
754 SAFE_FREE(gr_mem_list);
756 state->response.length += gr_mem_list_len;
758 DEBUG(10, ("returning %d groups, length = %d\n",
759 group_list_ndx, gr_mem_list_len));
765 return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
768 /* List domain groups without mapping to unix ids */
770 enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
772 uint32 total_entries = 0;
773 struct winbindd_domain *domain;
774 const char *which_domain;
775 char *extra_data = NULL;
777 unsigned int extra_data_len = 0, i;
779 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
781 /* Ensure null termination */
782 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
783 which_domain = state->request.domain_name;
785 /* Enumerate over trusted domains */
787 for (domain = domain_list(); domain; domain = domain->next) {
788 struct getent_state groups;
790 /* if we have a domain name restricting the request and this
791 one in the list doesn't match, then just bypass the remainder
794 if ( *which_domain && !strequal(which_domain, domain->name) )
797 if ( !domain->initialized )
798 set_dc_type_and_flags( domain );
803 /* Get list of sam groups */
805 fstrcpy(groups.domain_name, domain->name);
807 get_sam_group_entries(&groups);
809 if (groups.num_sam_entries == 0) {
810 /* this domain is empty or in an error state */
814 /* keep track the of the total number of groups seen so
815 far over all domains */
816 total_entries += groups.num_sam_entries;
818 /* Allocate some memory for extra data. Note that we limit
819 account names to sizeof(fstring) = 128 characters. */
820 ted = SMB_REALLOC(extra_data, sizeof(fstring) * total_entries);
823 DEBUG(0,("failed to enlarge buffer!\n"));
824 SAFE_FREE(extra_data);
825 return WINBINDD_ERROR;
829 /* Pack group list into extra data fields */
830 for (i = 0; i < groups.num_sam_entries; i++) {
831 char *group_name = ((struct acct_info *)
832 groups.sam_entries)[i].acct_name;
835 fill_domain_username(name, domain->name, group_name);
836 /* Append to extra data */
837 memcpy(&extra_data[extra_data_len], name,
839 extra_data_len += strlen(name);
840 extra_data[extra_data_len++] = ',';
843 SAFE_FREE(groups.sam_entries);
846 /* Assign extra_data fields in response structure */
848 extra_data[extra_data_len - 1] = '\0';
849 state->response.extra_data = extra_data;
850 state->response.length += extra_data_len;
853 /* No domains may have responded but that's still OK so don't
859 static BOOL enum_alias_memberships(const DOM_SID *member_sid,
860 DOM_SID **aliases, int *num_aliases)
862 TALLOC_CTX *mem_ctx = talloc_init("enum_alias_memberships");
875 if (!pdb_enum_alias_memberships(mem_ctx, get_global_sam_sid(),
876 member_sid, 1, &rids, &num_rids))
879 for (i=0; i<num_rids; i++) {
881 sid_copy(&alias_sid, get_global_sam_sid());
882 sid_append_rid(&alias_sid, rids[i]);
883 add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
886 if (!pdb_enum_alias_memberships(mem_ctx, &global_sid_Builtin,
887 member_sid, 1, &rids, &num_rids))
890 for (i=0; i<num_rids; i++) {
892 sid_copy(&alias_sid, &global_sid_Builtin);
893 sid_append_rid(&alias_sid, rids[i]);
894 add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
900 talloc_destroy(mem_ctx);
905 static void add_local_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
911 DEBUG(10, ("Adding local gids from SID: %s\n",
912 sid_string_static(sid)));
914 /* Don't expand aliases if not explicitly activated -- for now
917 if (!lp_winbind_nested_groups())
920 /* Add nested group memberships */
922 if (!enum_alias_memberships(sid, &aliases, &num_aliases))
925 for (j=0; j<num_aliases; j++) {
926 enum SID_NAME_USE type;
928 if (!local_sid_to_gid(&gid, &aliases[j], &type)) {
929 DEBUG(1, ("Got an alias membership with no alias\n"));
933 if ((type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) {
934 DEBUG(1, ("Got an alias membership in a non-alias\n"));
938 add_gid_to_array_unique(NULL, gid, gids, num);
943 static void add_gids_from_user_sid(DOM_SID *sid, gid_t **gids, int *num)
945 DEBUG(10, ("Adding gids from user SID: %s\n",
946 sid_string_static(sid)));
948 add_local_gids_from_sid(sid, gids, num);
951 static void add_gids_from_group_sid(DOM_SID *sid, gid_t **gids, int *num)
955 DEBUG(10, ("Adding gids from group SID: %s\n",
956 sid_string_static(sid)));
958 if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0)))
959 add_gid_to_array_unique(NULL, gid, gids, num);
961 add_local_gids_from_sid(sid, gids, num);
964 /* Get user supplementary groups. This is much quicker than trying to
965 invert the groups database. We merge the groups from the gids and
966 other_sids info3 fields as trusted domain, universal group
967 memberships, and nested groups (win2k native mode only) are not
968 returned by the getgroups RPC call but are present in the info3. */
970 enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
972 fstring name_domain, name_user;
973 DOM_SID user_sid, group_sid;
974 enum SID_NAME_USE name_type;
975 uint32 num_groups = 0;
978 DOM_SID **user_grpsids;
979 struct winbindd_domain *domain;
980 enum winbindd_result result = WINBINDD_ERROR;
981 gid_t *gid_list = NULL;
984 NET_USER_INFO_3 *info3 = NULL;
986 /* Ensure null termination */
987 state->request.data.username[sizeof(state->request.data.username)-1]='\0';
989 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
990 state->request.data.username));
992 if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
993 state->request.data.username)))
994 return WINBINDD_ERROR;
996 /* Parse domain and username */
998 parse_domain_user(state->request.data.username,
999 name_domain, name_user);
1001 /* Get info for the domain */
1003 if ((domain = find_domain_from_name(name_domain)) == NULL) {
1004 DEBUG(7, ("could not find domain entry for domain %s\n",
1009 if ( domain->primary && lp_winbind_trusted_domains_only()) {
1010 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1011 "getgroups() for %s\\%s.\n", name_domain, name_user));
1012 return WINBINDD_ERROR;
1015 /* Get rid and name type from name. The following costs 1 packet */
1017 if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid,
1019 DEBUG(4, ("user '%s' does not exist\n", name_user));
1023 if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) {
1024 DEBUG(1, ("name '%s' is not a user name: %d\n",
1025 name_user, name_type));
1029 add_gids_from_user_sid(&user_sid, &gid_list, &num_gids);
1031 /* Treat the info3 cache as authoritative as the
1032 lookup_usergroups() function may return cached data. */
1034 if ( !opt_nocache && (info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) {
1036 struct winbindd_domain *our_domain = find_our_domain();
1038 if (our_domain == NULL) {
1039 DEBUG(0, ("Could not find our domain\n"));
1043 DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n",
1044 info3->num_groups2, info3->num_other_sids));
1046 num_groups = info3->num_other_sids + info3->num_groups2;
1048 /* Go through each other sid and convert it to a gid */
1050 for (i = 0; i < info3->num_other_sids; i++) {
1051 DOM_SID *sid = &info3->other_sids[i].sid;
1054 enum SID_NAME_USE sid_type;
1056 /* Is this sid known to us? It can either be
1057 a trusted domain sid or a foreign sid. */
1059 if (!winbindd_lookup_name_by_sid( sid, dom_name,
1061 DEBUG(10, ("winbindd_getgroups: could not "
1062 "lookup name for %s\n",
1063 sid_string_static(sid)));
1067 /* Check it is a domain group or an alias (domain
1068 local group) in a win2k native mode domain. */
1070 if (!((sid_type==SID_NAME_DOM_GRP) ||
1071 ((sid_type==SID_NAME_ALIAS) &&
1072 (our_domain->active_directory) &&
1073 (our_domain->native_mode) &&
1074 (sid_compare_domain(sid, &our_domain->sid)
1076 DEBUG(10, ("winbindd_getgroups: sid type %d "
1077 "for %s is not a domain group\n",
1078 sid_type, sid_string_static(sid)));
1082 add_gids_from_group_sid(sid, &gid_list, &num_gids);
1085 for (i = 0; i < info3->num_groups2; i++) {
1087 /* create the group SID */
1089 sid_copy( &group_sid, &domain->sid );
1090 sid_append_rid( &group_sid, info3->gids[i].g_rid );
1092 add_gids_from_group_sid(&group_sid, &gid_list,
1099 status = domain->methods->lookup_usergroups(domain, mem_ctx,
1100 &user_sid, &num_groups,
1102 if (!NT_STATUS_IS_OK(status))
1105 if (state->response.extra_data)
1108 for (i = 0; i < num_groups; i++) {
1109 add_gids_from_group_sid(user_grpsids[i],
1110 &gid_list, &num_gids);
1114 /* We want at least one group... */
1115 if (gid_list == NULL)
1118 remove_duplicate_gids( &num_gids, gid_list );
1120 /* Send data back to client */
1122 state->response.data.num_entries = num_gids;
1123 state->response.extra_data = gid_list;
1124 state->response.length += num_gids * sizeof(gid_t);
1126 result = WINBINDD_OK;
1130 talloc_destroy(mem_ctx);
1135 static void add_sid_to_parray_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
1136 DOM_SID ***sids, int *num_sids)
1140 for (i=0; i<(*num_sids); i++) {
1141 if (sid_compare(sid, (*sids)[i]) == 0)
1145 *sids = TALLOC_REALLOC_ARRAY(mem_ctx, *sids, DOM_SID *, *num_sids+1);
1150 (*sids)[*num_sids] = TALLOC_P(mem_ctx, DOM_SID);
1151 sid_copy((*sids)[*num_sids], sid);
1156 static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
1157 DOM_SID ***user_grpsids,
1160 DOM_SID *aliases = NULL;
1161 int i, num_aliases = 0;
1163 if (!enum_alias_memberships(sid, &aliases, &num_aliases))
1166 if (num_aliases == 0)
1169 for (i=0; i<num_aliases; i++)
1170 add_sid_to_parray_unique(mem_ctx, &aliases[i], user_grpsids,
1178 /* Get user supplementary sids. This is equivalent to the
1179 winbindd_getgroups() function but it involves a SID->SIDs mapping
1180 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1181 idmap. This call is designed to be used with applications that need
1182 to do ACL evaluation themselves. Note that the cached info3 data is
1185 this function assumes that the SID that comes in is a user SID. If
1186 you pass in another type of SID then you may get unpredictable
1189 enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
1193 DOM_SID **user_grpsids;
1194 struct winbindd_domain *domain;
1195 enum winbindd_result result = WINBINDD_ERROR;
1197 TALLOC_CTX *mem_ctx;
1200 unsigned ofs, ret_size = 0;
1202 /* Ensure null termination */
1203 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1205 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1206 DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
1207 return WINBINDD_ERROR;
1210 if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)",
1211 state->request.data.username))) {
1212 return WINBINDD_ERROR;
1215 /* Get info for the domain */
1216 if ((domain = find_domain_from_sid(&user_sid)) == NULL) {
1217 DEBUG(0,("could not find domain entry for sid %s\n",
1218 sid_string_static(&user_sid)));
1222 status = domain->methods->lookup_usergroups(domain, mem_ctx,
1223 &user_sid, &num_groups,
1225 if (!NT_STATUS_IS_OK(status))
1228 if (num_groups == 0) {
1232 domain = find_our_domain();
1234 if (domain == NULL) {
1235 DEBUG(0, ("Could not find our domain\n"));
1239 /* Note that I do not check for AD or its mode. XP in a real NT4
1240 * domain also asks for this info. -- vl */
1243 uint32 *alias_rids = NULL;
1246 /* We need to include the user SID to expand */
1247 user_grpsids = TALLOC_REALLOC_ARRAY(mem_ctx, user_grpsids,
1248 DOM_SID *, num_groups+1);
1249 user_grpsids[num_groups] = &user_sid;
1251 status = domain->methods->lookup_useraliases(domain, mem_ctx,
1257 if (!NT_STATUS_IS_OK(status)) {
1258 DEBUG(3, ("Could not expand alias sids: %s\n",
1259 nt_errstr(status)));
1263 for (i=0; i<num_aliases; i++) {
1265 sid_copy(&sid, &domain->sid);
1266 sid_append_rid(&sid, alias_rids[i]);
1267 add_sid_to_parray_unique(mem_ctx, &sid, &user_grpsids,
1272 if (lp_winbind_nested_groups()) {
1274 /* num_groups is changed during the loop, that's why we have
1275 to count down here.*/
1277 for (k=num_groups-1; k>=0; k--) {
1278 add_local_sids_from_sid(mem_ctx, user_grpsids[k],
1279 &user_grpsids, &num_groups);
1282 add_local_sids_from_sid(mem_ctx, &user_sid, &user_grpsids,
1286 /* work out the response size */
1287 for (i = 0; i < num_groups; i++) {
1288 const char *s = sid_string_static(user_grpsids[i]);
1289 ret_size += strlen(s) + 1;
1292 /* build the reply */
1293 ret = SMB_MALLOC(ret_size);
1294 if (!ret) goto done;
1296 for (i = 0; i < num_groups; i++) {
1297 const char *s = sid_string_static(user_grpsids[i]);
1298 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1299 ofs += strlen(ret+ofs) + 1;
1303 /* Send data back to client */
1304 state->response.data.num_entries = num_groups;
1305 state->response.extra_data = ret;
1306 state->response.length += ret_size;
1307 result = WINBINDD_OK;
1310 talloc_destroy(mem_ctx);