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, True );
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,
60 struct winbindd_cli_state *state,
62 enum lsa_SidType group_name_type,
63 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
65 DOM_SID *sid_mem = NULL;
67 uint32 *name_types = NULL;
68 unsigned int buf_len = 0, buf_ndx = 0, i;
69 char **names = NULL, *buf = NULL;
76 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
79 /* Initialise group membership information */
81 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
85 /* HACK ALERT!! This whole routine does not cope with group members
86 * from more than one domain, ie aliases. Thus we have to work it out
87 * ourselves in a special routine. */
90 return fill_passdb_alias_grmem(domain, group_sid,
94 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
95 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
97 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
98 sid_to_string(sid_string, group_sid), domain->name,
103 /* OPTIMIZATION / HACK. */
104 /* If "enum users" is set to false, and the group being looked
105 up is the Domain Users SID: S-1-5-domain-513, then for the
106 list of members check if the querying user is in that group,
107 and if so only return that user as the gr_mem array.
108 We can change this to a different parameter than "enum users"
109 if neccessaey, or parameterize the group list we do this for. */
111 sid_peek_rid( group_sid, &group_rid );
112 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
113 DOM_SID querying_user_sid;
114 DOM_SID *pquerying_user_sid = NULL;
115 uint32 num_groups = 0;
116 DOM_SID *user_sids = NULL;
117 BOOL u_in_group = False;
119 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
120 sid_to_string(sid_string, group_sid), domain->name ));
123 uid_t ret_uid = (uid_t)-1;
124 if (sys_getpeereid(state->sock, &ret_uid)==0) {
125 /* We know who's asking - look up their SID if
126 it's one we've mapped before. */
127 status = idmap_uid_to_sid(&querying_user_sid,
129 IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
130 if (NT_STATUS_IS_OK(status)) {
131 pquerying_user_sid = &querying_user_sid;
132 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
133 (unsigned int)ret_uid,
134 sid_to_string(sid_string, pquerying_user_sid) ));
139 /* Only look up if it was a winbindd user in this domain. */
140 if (pquerying_user_sid &&
141 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
143 DEBUG(10,("fill_grent_mem: querying user = %s\n",
144 sid_to_string(sid_string, pquerying_user_sid) ));
146 status = domain->methods->lookup_usergroups(domain,
151 if (!NT_STATUS_IS_OK(status)) {
152 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
153 "for sid %s in domain %s (error: %s)\n",
154 sid_to_string(sid_string, pquerying_user_sid),
160 for (i = 0; i < num_groups; i++) {
161 if (sid_equal(group_sid, &user_sids[i])) {
162 /* User is in Domain Users, add their name
163 as the only group member. */
172 char *domainname = NULL;
173 char *username = NULL;
175 enum lsa_SidType type;
177 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
178 sid_to_string(sid_string, pquerying_user_sid), domain->name ));
180 status = domain->methods->sid_to_name(domain, mem_ctx,
185 if (!NT_STATUS_IS_OK(status)) {
186 DEBUG(1, ("could not lookup username for user "
187 "sid %s in domain %s (error: %s)\n",
188 sid_to_string(sid_string, pquerying_user_sid),
193 fill_domain_username(name, domain->name, username, True);
196 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
197 DEBUG(1, ("out of memory\n"));
200 memcpy(buf, name, buf_len);
202 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
203 name, domain->name ));
207 *gr_mem_len = buf_len;
209 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
210 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
215 /* Lookup group members */
216 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
217 &sid_mem, &names, &name_types);
218 if (!NT_STATUS_IS_OK(status)) {
219 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
220 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
224 DEBUG(10, ("looked up %d names\n", num_names));
226 if (DEBUGLEVEL >= 10) {
227 for (i = 0; i < num_names; i++)
228 DEBUG(10, ("\t%20s %s %d\n", names[i],
229 sid_string_static(&sid_mem[i]),
233 /* Add members to list */
237 for (i = 0; i < num_names; i++) {
244 DEBUG(10, ("processing name %s\n", the_name));
246 /* FIXME: need to cope with groups within groups. These
247 occur in Universal groups on a Windows 2000 native mode
250 /* make sure to allow machine accounts */
252 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
253 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
257 /* Append domain name */
259 fill_domain_username(name, domain->name, the_name, True);
263 /* Add to list or calculate buffer length */
266 buf_len += len + 1; /* List is comma separated */
268 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
270 DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
271 safe_strcpy(&buf[buf_ndx], name, len);
278 /* Allocate buffer */
280 if (!buf && buf_len != 0) {
281 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
282 DEBUG(1, ("out of memory\n"));
286 memset(buf, 0, buf_len);
290 if (buf && buf_ndx > 0) {
291 buf[buf_ndx - 1] = '\0';
295 *gr_mem_len = buf_len;
297 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
298 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
303 talloc_destroy(mem_ctx);
305 DEBUG(10, ("fill_grent_mem returning %d\n", result));
310 /* Return a group structure from a group name */
312 void winbindd_getgrnam(struct winbindd_cli_state *state)
314 DOM_SID group_sid, tmp_sid;
316 struct winbindd_domain *domain;
317 enum lsa_SidType name_type;
318 fstring name_domain, name_group;
326 /* Ensure null termination */
327 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
329 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
330 state->request.data.groupname));
332 /* Parse domain and groupname */
334 memset(name_group, 0, sizeof(fstring));
336 tmp = state->request.data.groupname;
338 parse_domain_user(tmp, name_domain, name_group);
340 /* if no domain or our local domain and no local tdb group, default to
341 * our local domain for aliases */
343 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
344 fstrcpy(name_domain, get_global_sam_name());
347 /* Get info for the domain */
349 if ((domain = find_domain_from_name(name_domain)) == NULL) {
350 DEBUG(3, ("could not get domain sid for domain %s\n",
352 request_error(state);
355 /* should we deal with users for our domain? */
357 if ( lp_winbind_trusted_domains_only() && domain->primary) {
358 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
359 "getgrnam() for %s\\%s.\n", name_domain, name_group));
360 request_error(state);
364 /* Get rid and name type from name */
366 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
367 name_group, &group_sid, &name_type)) {
368 DEBUG(1, ("group %s in domain %s does not exist\n",
369 name_group, name_domain));
370 request_error(state);
374 if ( !((name_type==SID_NAME_DOM_GRP) ||
375 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
376 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
377 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
379 DEBUG(1, ("name '%s' is not a local, domain or builtin "
380 "group: %d\n", name_group, name_type));
381 request_error(state);
385 /* Make sure that the group SID is within the domain of the
388 sid_copy( &tmp_sid, &group_sid );
389 sid_split_rid( &tmp_sid, &grp_rid );
390 if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
391 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
392 state->request.data.groupname, sid_string_static(&group_sid)));
393 request_error(state);
399 /* Try to get the GID */
401 status = idmap_sid_to_gid(&group_sid, &gid, 0);
403 if (NT_STATUS_IS_OK(status)) {
407 /* Maybe it's one of our aliases in passdb */
409 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
410 ((name_type == SID_NAME_ALIAS) ||
411 (name_type == SID_NAME_WKN_GRP))) {
416 DEBUG(1, ("error converting unix gid to sid\n"));
417 request_error(state);
422 if (!fill_grent(&state->response.data.gr, name_domain,
424 !fill_grent_mem(domain, state, &group_sid, name_type,
426 &gr_mem, &gr_mem_len)) {
427 request_error(state);
431 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
433 /* Group membership lives at start of extra data */
435 state->response.data.gr.gr_mem_ofs = 0;
437 state->response.length += gr_mem_len;
438 state->response.extra_data.data = gr_mem;
442 static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
444 struct winbindd_domain *domain;
445 enum lsa_SidType name_type;
452 /* Get name from sid */
454 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
455 group_name, &name_type)) {
456 DEBUG(1, ("could not lookup sid\n"));
457 request_error(state);
461 /* Fill in group structure */
463 domain = find_domain_from_sid_noinit(&group_sid);
466 DEBUG(1,("Can't find domain from sid\n"));
467 request_error(state);
471 if ( !((name_type==SID_NAME_DOM_GRP) ||
472 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
473 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
475 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
476 group_name, name_type));
477 request_error(state);
481 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
482 state->request.data.gid) ||
483 !fill_grent_mem(domain, state, &group_sid, name_type,
485 &gr_mem, &gr_mem_len)) {
486 request_error(state);
490 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
492 /* Group membership lives at start of extra data */
494 state->response.data.gr.gr_mem_ofs = 0;
496 state->response.length += gr_mem_len;
497 state->response.extra_data.data = gr_mem;
502 static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
504 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
505 enum lsa_SidType name_type;
509 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
510 (unsigned long)(state->request.data.gid), sid));
512 string_to_sid(&group_sid, sid);
513 getgrgid_got_sid(state, group_sid);
517 /* Ok, this might be "ours", i.e. an alias */
518 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
519 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
520 (name_type == SID_NAME_ALIAS)) {
521 /* Hey, got an alias */
522 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
523 (unsigned long)(state->request.data.gid), sid));
524 getgrgid_got_sid(state, group_sid);
528 DEBUG(1, ("could not convert gid %lu to sid\n",
529 (unsigned long)state->request.data.gid));
530 request_error(state);
533 /* Return a group structure from a gid number */
534 void winbindd_getgrgid(struct winbindd_cli_state *state)
539 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
540 (unsigned long)state->request.data.gid));
542 /* Bug out if the gid isn't in the winbind range */
544 if ((state->request.data.gid < server_state.gid_low) ||
545 (state->request.data.gid > server_state.gid_high)) {
546 request_error(state);
550 /* Get sid from gid */
552 status = idmap_gid_to_sid(&group_sid, state->request.data.gid, IDMAP_FLAG_NONE);
553 if (NT_STATUS_IS_OK(status)) {
554 /* This is a remote one */
555 getgrgid_got_sid(state, group_sid);
559 DEBUG(10,("winbindd_getgrgid: gid %lu not found in cache, try with the async interface\n",
560 (unsigned long)state->request.data.gid));
562 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
566 * set/get/endgrent functions
569 /* "Rewind" file pointer for group database enumeration */
571 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
573 struct winbindd_domain *domain;
575 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
577 /* Check user has enabled this */
579 if (!lp_winbind_enum_groups()) {
583 /* Free old static data if it exists */
585 if (state->getgrent_state != NULL) {
586 free_getent_state(state->getgrent_state);
587 state->getgrent_state = NULL;
590 /* Create sam pipes for each domain we know about */
592 for (domain = domain_list(); domain != NULL; domain = domain->next) {
593 struct getent_state *domain_state;
595 /* Create a state record for this domain */
597 /* don't add our domaina if we are a PDC or if we
598 are a member of a Samba domain */
600 if ( lp_winbind_trusted_domains_only() && domain->primary )
606 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
607 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
611 ZERO_STRUCTP(domain_state);
613 fstrcpy(domain_state->domain_name, domain->name);
615 /* Add to list of open domains */
617 DLIST_ADD(state->getgrent_state, domain_state);
620 state->getgrent_initialized = True;
624 void winbindd_setgrent(struct winbindd_cli_state *state)
626 if (winbindd_setgrent_internal(state)) {
629 request_error(state);
633 /* Close file pointer to ntdom group database */
635 void winbindd_endgrent(struct winbindd_cli_state *state)
637 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
639 free_getent_state(state->getgrent_state);
640 state->getgrent_initialized = False;
641 state->getgrent_state = NULL;
645 /* Get the list of domain groups and domain aliases for a domain. We fill in
646 the sam_entries and num_sam_entries fields with domain group information.
647 The dispinfo_ndx field is incremented to the index of the next group to
648 fetch. Return True if some groups were returned, False otherwise. */
650 static BOOL get_sam_group_entries(struct getent_state *ent)
654 struct acct_info *name_list = NULL;
657 struct acct_info *sam_grp_entries = NULL;
658 struct winbindd_domain *domain;
660 if (ent->got_sam_entries)
663 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
664 ent->domain_name))) {
665 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
669 /* Free any existing group info */
671 SAFE_FREE(ent->sam_entries);
672 ent->num_sam_entries = 0;
673 ent->got_sam_entries = True;
675 /* Enumerate domain groups */
679 if (!(domain = find_domain_from_name(ent->domain_name))) {
680 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
684 /* always get the domain global groups */
686 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
688 if (!NT_STATUS_IS_OK(status)) {
689 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
694 /* Copy entries into return buffer */
697 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
698 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
703 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
706 ent->num_sam_entries = num_entries;
708 /* get the domain local groups if we are a member of a native win2k domain
709 and are not using LDAP to get the groups */
711 if ( ( lp_security() != SEC_ADS && domain->native_mode
712 && domain->primary) || domain->internal )
714 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
715 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
717 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
719 if ( !NT_STATUS_IS_OK(status) ) {
720 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
724 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
726 /* Copy entries into return buffer */
729 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
731 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
737 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
738 num_entries * sizeof(struct acct_info) );
741 ent->num_sam_entries += num_entries;
745 /* Fill in remaining fields */
747 ent->sam_entries = name_list;
748 ent->sam_entry_index = 0;
750 result = (ent->num_sam_entries > 0);
753 talloc_destroy(mem_ctx);
758 /* Fetch next group entry from ntdom database */
760 #define MAX_GETGRENT_GROUPS 500
762 void winbindd_getgrent(struct winbindd_cli_state *state)
764 struct getent_state *ent;
765 struct winbindd_gr *group_list = NULL;
766 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
767 char *gr_mem_list = NULL;
769 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
771 /* Check user has enabled this */
773 if (!lp_winbind_enum_groups()) {
774 request_error(state);
778 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
780 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
781 request_error(state);
785 memset(state->response.extra_data.data, '\0',
786 num_groups * sizeof(struct winbindd_gr) );
788 state->response.data.num_entries = 0;
790 group_list = (struct winbindd_gr *)state->response.extra_data.data;
792 if (!state->getgrent_initialized)
793 winbindd_setgrent_internal(state);
795 if (!(ent = state->getgrent_state)) {
796 request_error(state);
800 /* Start sending back groups */
802 for (i = 0; i < num_groups; i++) {
803 struct acct_info *name_list = NULL;
804 fstring domain_group_name;
810 struct winbindd_domain *domain;
812 /* Do we need to fetch another chunk of groups? */
816 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
817 ent->sam_entry_index, ent->num_sam_entries));
819 if (ent->num_sam_entries == ent->sam_entry_index) {
821 while(ent && !get_sam_group_entries(ent)) {
822 struct getent_state *next_ent;
824 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
826 /* Free state information for this domain */
828 SAFE_FREE(ent->sam_entries);
830 next_ent = ent->next;
831 DLIST_REMOVE(state->getgrent_state, ent);
837 /* No more domains */
843 name_list = (struct acct_info *)ent->sam_entries;
846 find_domain_from_name(ent->domain_name))) {
847 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
852 /* Lookup group info */
854 sid_copy(&group_sid, &domain->sid);
855 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
857 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid,
860 enum lsa_SidType type;
862 DEBUG(10, ("SID %s not in idmap\n",
863 sid_string_static(&group_sid)));
865 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
866 DEBUG(1, ("could not look up gid for group "
868 name_list[ent->sam_entry_index].acct_name));
869 ent->sam_entry_index++;
873 if ((type != SID_NAME_DOM_GRP) &&
874 (type != SID_NAME_ALIAS) &&
875 (type != SID_NAME_WKN_GRP)) {
876 DEBUG(1, ("Group %s is a %s, not a group\n",
877 sid_type_lookup(type),
878 name_list[ent->sam_entry_index].acct_name));
879 ent->sam_entry_index++;
885 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
886 (unsigned long)name_list[ent->sam_entry_index].rid));
888 /* Fill in group entry */
890 fill_domain_username(domain_group_name, ent->domain_name,
891 name_list[ent->sam_entry_index].acct_name, True);
893 result = fill_grent(&group_list[group_list_ndx],
895 name_list[ent->sam_entry_index].acct_name,
898 /* Fill in group membership entry */
901 size_t num_gr_mem = 0;
903 group_list[group_list_ndx].num_gr_mem = 0;
907 /* Get group membership */
908 if (state->request.cmd == WINBINDD_GETGRLST) {
911 sid_copy(&member_sid, &domain->sid);
912 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
913 result = fill_grent_mem(
919 &gr_mem, &gr_mem_len);
921 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
926 /* Append to group membership list */
927 gr_mem_list = (char *)SMB_REALLOC(
928 gr_mem_list, gr_mem_list_len + gr_mem_len);
930 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
931 DEBUG(0, ("out of memory\n"));
936 DEBUG(10, ("list_len = %d, mem_len = %u\n",
937 gr_mem_list_len, (unsigned int)gr_mem_len));
939 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
944 group_list[group_list_ndx].gr_mem_ofs =
947 gr_mem_list_len += gr_mem_len;
950 ent->sam_entry_index++;
952 /* Add group to return list */
956 DEBUG(10, ("adding group num_entries = %d\n",
957 state->response.data.num_entries));
960 state->response.data.num_entries++;
962 state->response.length +=
963 sizeof(struct winbindd_gr);
966 DEBUG(0, ("could not lookup domain group %s\n",
971 /* Copy the list of group memberships to the end of the extra data */
973 if (group_list_ndx == 0)
976 state->response.extra_data.data = SMB_REALLOC(
977 state->response.extra_data.data,
978 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
980 if (!state->response.extra_data.data) {
981 DEBUG(0, ("out of memory\n"));
983 SAFE_FREE(gr_mem_list);
984 request_error(state);
988 memcpy(&((char *)state->response.extra_data.data)
989 [group_list_ndx * sizeof(struct winbindd_gr)],
990 gr_mem_list, gr_mem_list_len);
992 state->response.length += gr_mem_list_len;
994 DEBUG(10, ("returning %d groups, length = %d\n",
995 group_list_ndx, gr_mem_list_len));
1001 SAFE_FREE(gr_mem_list);
1003 if (group_list_ndx > 0)
1006 request_error(state);
1009 /* List domain groups without mapping to unix ids */
1011 void winbindd_list_groups(struct winbindd_cli_state *state)
1013 uint32 total_entries = 0;
1014 struct winbindd_domain *domain;
1015 const char *which_domain;
1016 char *extra_data = NULL;
1017 unsigned int extra_data_len = 0, i;
1019 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1021 /* Ensure null termination */
1022 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1023 which_domain = state->request.domain_name;
1025 /* Enumerate over trusted domains */
1027 for (domain = domain_list(); domain; domain = domain->next) {
1028 struct getent_state groups;
1030 /* if we have a domain name restricting the request and this
1031 one in the list doesn't match, then just bypass the remainder
1034 if ( *which_domain && !strequal(which_domain, domain->name) )
1037 ZERO_STRUCT(groups);
1039 /* Get list of sam groups */
1041 fstrcpy(groups.domain_name, domain->name);
1043 get_sam_group_entries(&groups);
1045 if (groups.num_sam_entries == 0) {
1046 /* this domain is empty or in an error state */
1050 /* keep track the of the total number of groups seen so
1051 far over all domains */
1052 total_entries += groups.num_sam_entries;
1054 /* Allocate some memory for extra data. Note that we limit
1055 account names to sizeof(fstring) = 128 characters. */
1056 extra_data = (char *)SMB_REALLOC(
1057 extra_data, sizeof(fstring) * total_entries);
1060 DEBUG(0,("failed to enlarge buffer!\n"));
1061 request_error(state);
1065 /* Pack group list into extra data fields */
1066 for (i = 0; i < groups.num_sam_entries; i++) {
1067 char *group_name = ((struct acct_info *)
1068 groups.sam_entries)[i].acct_name;
1071 fill_domain_username(name, domain->name, group_name, True);
1072 /* Append to extra data */
1073 memcpy(&extra_data[extra_data_len], name,
1075 extra_data_len += strlen(name);
1076 extra_data[extra_data_len++] = ',';
1079 SAFE_FREE(groups.sam_entries);
1082 /* Assign extra_data fields in response structure */
1084 extra_data[extra_data_len - 1] = '\0';
1085 state->response.extra_data.data = extra_data;
1086 state->response.length += extra_data_len;
1089 /* No domains may have responded but that's still OK so don't
1095 /* Get user supplementary groups. This is much quicker than trying to
1096 invert the groups database. We merge the groups from the gids and
1097 other_sids info3 fields as trusted domain, universal group
1098 memberships, and nested groups (win2k native mode only) are not
1099 returned by the getgroups RPC call but are present in the info3. */
1101 struct getgroups_state {
1102 struct winbindd_cli_state *state;
1103 struct winbindd_domain *domain;
1108 const DOM_SID *token_sids;
1109 size_t i, num_token_sids;
1112 size_t num_token_gids;
1115 static void getgroups_usersid_recv(void *private_data, BOOL success,
1116 const DOM_SID *sid, enum lsa_SidType type);
1117 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1118 DOM_SID *token_sids, size_t num_token_sids);
1119 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
1121 void winbindd_getgroups(struct winbindd_cli_state *state)
1123 struct getgroups_state *s;
1125 /* Ensure null termination */
1126 state->request.data.username
1127 [sizeof(state->request.data.username)-1]='\0';
1129 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1130 state->request.data.username));
1132 /* when using "winbind use default domain" we need to avoid that
1133 * initgroups() requests from NSS hit our DC too badly for accounts
1134 * that will never be on the remote DC */
1136 if (lp_winbind_use_default_domain()) {
1138 const char **list = lp_winbind_initgroups_blacklist();
1141 if (!list || !list[0]) {
1145 for (i=0; list[i] != NULL; i++) {
1147 if (strequal(state->request.data.username, list[i])) {
1148 DEBUG(3,("ignoring blacklisted user [%s] for getgroups\n",
1149 state->request.data.username));
1156 /* Parse domain and username */
1158 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1160 DEBUG(0, ("talloc failed\n"));
1161 request_error(state);
1167 if (!parse_domain_user_talloc(state->mem_ctx,
1168 state->request.data.username,
1169 &s->domname, &s->username)) {
1170 DEBUG(5, ("Could not parse domain user: %s\n",
1171 state->request.data.username));
1173 /* error out if we do not have nested group support */
1175 if ( !lp_winbind_nested_groups() ) {
1176 request_error(state);
1180 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1181 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1184 /* Get info for the domain */
1186 s->domain = find_domain_from_name_noinit(s->domname);
1188 if (s->domain == NULL) {
1189 DEBUG(7, ("could not find domain entry for domain %s\n",
1191 request_error(state);
1195 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1196 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
1197 "getgroups() for %s\\%s.\n", s->domname,
1199 request_error(state);
1203 /* Get rid and name type from name. The following costs 1 packet */
1205 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1206 getgroups_usersid_recv, s);
1209 static void getgroups_usersid_recv(void *private_data, BOOL success,
1210 const DOM_SID *sid, enum lsa_SidType type)
1212 struct getgroups_state *s =
1213 (struct getgroups_state *)private_data;
1216 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1217 request_error(s->state);
1221 sid_copy(&s->user_sid, sid);
1223 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1224 getgroups_tokensids_recv, s);
1227 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1228 DOM_SID *token_sids, size_t num_token_sids)
1230 struct getgroups_state *s =
1231 (struct getgroups_state *)private_data;
1233 /* We need at least the user sid and the primary group in the token,
1234 * otherwise it's an error */
1236 if ((!success) || (num_token_sids < 2)) {
1237 request_error(s->state);
1241 s->token_sids = token_sids;
1242 s->num_token_sids = num_token_sids;
1245 s->token_gids = NULL;
1246 s->num_token_gids = 0;
1248 getgroups_sid2gid_recv(s, False, 0);
1251 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1253 struct getgroups_state *s =
1254 (struct getgroups_state *)private_data;
1257 add_gid_to_array_unique(NULL, gid,
1259 &s->num_token_gids);
1261 if (s->i < s->num_token_sids) {
1262 const DOM_SID *sid = &s->token_sids[s->i];
1265 if (sid_equal(sid, &s->user_sid)) {
1266 getgroups_sid2gid_recv(s, False, 0);
1270 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1271 getgroups_sid2gid_recv, s);
1275 s->state->response.data.num_entries = s->num_token_gids;
1276 s->state->response.extra_data.data = s->token_gids;
1277 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1278 request_ok(s->state);
1281 /* Get user supplementary sids. This is equivalent to the
1282 winbindd_getgroups() function but it involves a SID->SIDs mapping
1283 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1284 idmap. This call is designed to be used with applications that need
1285 to do ACL evaluation themselves. Note that the cached info3 data is
1288 this function assumes that the SID that comes in is a user SID. If
1289 you pass in another type of SID then you may get unpredictable
1293 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1296 void winbindd_getusersids(struct winbindd_cli_state *state)
1300 /* Ensure null termination */
1301 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1303 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1304 if (user_sid == NULL) {
1305 DEBUG(1, ("talloc failed\n"));
1306 request_error(state);
1310 if (!string_to_sid(user_sid, state->request.data.sid)) {
1311 DEBUG(1, ("Could not get convert sid %s from string\n",
1312 state->request.data.sid));
1313 request_error(state);
1317 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1321 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1324 struct winbindd_cli_state *state =
1325 (struct winbindd_cli_state *)private_data;
1327 unsigned ofs, ret_size = 0;
1331 request_error(state);
1335 /* work out the response size */
1336 for (i = 0; i < num_sids; i++) {
1337 const char *s = sid_string_static(&sids[i]);
1338 ret_size += strlen(s) + 1;
1341 /* build the reply */
1342 ret = (char *)SMB_MALLOC(ret_size);
1344 DEBUG(0, ("malloc failed\n"));
1345 request_error(state);
1349 for (i = 0; i < num_sids; i++) {
1350 const char *s = sid_string_static(&sids[i]);
1351 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1352 ofs += strlen(ret+ofs) + 1;
1355 /* Send data back to client */
1356 state->response.data.num_entries = num_sids;
1357 state->response.extra_data.data = ret;
1358 state->response.length += ret_size;
1362 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1365 struct winbindd_domain *domain;
1367 /* Ensure null termination */
1368 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1370 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1371 DEBUG(1, ("Could not get convert sid %s from string\n",
1372 state->request.data.sid));
1373 request_error(state);
1377 /* Get info for the domain */
1378 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1379 DEBUG(0,("could not find domain entry for sid %s\n",
1380 sid_string_static(&user_sid)));
1381 request_error(state);
1385 sendto_domain(state, domain);
1388 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1389 struct winbindd_cli_state *state)
1399 /* Ensure null termination */
1400 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1402 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1403 DEBUG(1, ("Could not get convert sid %s from string\n",
1404 state->request.data.sid));
1405 return WINBINDD_ERROR;
1408 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1409 &user_sid, &num_groups,
1411 if (!NT_STATUS_IS_OK(status))
1412 return WINBINDD_ERROR;
1414 if (num_groups == 0) {
1415 state->response.data.num_entries = 0;
1416 state->response.extra_data.data = NULL;
1420 if (!print_sidlist(NULL, groups, num_groups, &sidstring, &len)) {
1421 DEBUG(0, ("malloc failed\n"));
1422 return WINBINDD_ERROR;
1425 state->response.extra_data.data = sidstring;
1426 state->response.length += len+1;
1427 state->response.data.num_entries = num_groups;