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 static void add_member(const char *domain, const char *user,
35 char **pp_members, size_t *p_num_members)
39 fill_domain_username(name, domain, user, True);
40 safe_strcat(name, ",", sizeof(name)-1);
41 string_append(pp_members, name);
45 /**********************************************************************
46 Add member users resulting from sid. Expand if it is a domain group.
47 **********************************************************************/
49 static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
53 struct winbindd_domain *domain;
56 char *domain_name = NULL;
58 enum lsa_SidType type;
67 TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
69 if (mem_ctx == NULL) {
70 DEBUG(1, ("talloc_init failed\n"));
74 sid_copy(&dom_sid, sid);
75 sid_split_rid(&dom_sid, &rid);
77 domain = find_lookup_domain_from_sid(sid);
80 DEBUG(3, ("Could not find domain for sid %s\n",
81 sid_string_static(sid)));
85 result = domain->methods->sid_to_name(domain, mem_ctx, sid,
86 &domain_name, &name, &type);
88 if (!NT_STATUS_IS_OK(result)) {
89 DEBUG(3, ("sid_to_name failed for sid %s\n",
90 sid_string_static(sid)));
94 DEBUG(10, ("Found name %s, type %d\n", name, type));
96 if (type == SID_NAME_USER) {
97 add_member(domain_name, name, pp_members, p_num_members);
101 if (type != SID_NAME_DOM_GRP) {
102 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
107 /* Expand the domain group, this must be done via the target domain */
109 domain = find_domain_from_sid(sid);
111 if (domain == NULL) {
112 DEBUG(3, ("Could not find domain from SID %s\n",
113 sid_string_static(sid)));
117 result = domain->methods->lookup_groupmem(domain, mem_ctx,
122 if (!NT_STATUS_IS_OK(result)) {
123 DEBUG(10, ("Could not lookup group members for %s: %s\n",
124 name, nt_errstr(result)));
128 for (i=0; i<num_names; i++) {
129 DEBUG(10, ("Adding group member SID %s\n",
130 sid_string_static(&sid_mem[i])));
132 if (types[i] != SID_NAME_USER) {
133 DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
134 "Ignoring.\n", names[i], name));
138 add_member(domain->name, names[i], pp_members, p_num_members);
142 talloc_destroy(mem_ctx);
146 static BOOL fill_passdb_alias_grmem(struct winbindd_domain *domain,
148 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
151 size_t i, num_members;
157 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
161 for (i=0; i<num_members; i++) {
162 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
167 if (*gr_mem != NULL) {
170 /* We have at least one member, strip off the last "," */
171 len = strlen(*gr_mem);
172 (*gr_mem)[len-1] = '\0';
179 /* Fill a grent structure from various other information */
181 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
182 const char *gr_name, gid_t unix_gid)
184 fstring full_group_name;
186 fill_domain_username( full_group_name, dom_name, gr_name, True );
188 gr->gr_gid = unix_gid;
190 /* Group name and password */
192 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
193 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
198 /* Fill in the group membership field of a NT group given by group_sid */
200 static BOOL fill_grent_mem(struct winbindd_domain *domain,
201 struct winbindd_cli_state *state,
203 enum lsa_SidType group_name_type,
204 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
206 DOM_SID *sid_mem = NULL;
207 uint32 num_names = 0;
208 uint32 *name_types = NULL;
209 unsigned int buf_len = 0, buf_ndx = 0, i;
210 char **names = NULL, *buf = NULL;
217 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
220 /* Initialise group membership information */
222 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
226 /* HACK ALERT!! This whole routine does not cope with group members
227 * from more than one domain, ie aliases. Thus we have to work it out
228 * ourselves in a special routine. */
230 if (domain->internal)
231 return fill_passdb_alias_grmem(domain, group_sid,
235 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
236 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
238 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
239 sid_to_string(sid_string, group_sid), domain->name,
244 /* OPTIMIZATION / HACK. */
245 /* If "enum users" is set to false, and the group being looked
246 up is the Domain Users SID: S-1-5-domain-513, then for the
247 list of members check if the querying user is in that group,
248 and if so only return that user as the gr_mem array.
249 We can change this to a different parameter than "enum users"
250 if neccessaey, or parameterize the group list we do this for. */
252 sid_peek_rid( group_sid, &group_rid );
253 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
254 DOM_SID querying_user_sid;
255 DOM_SID *pquerying_user_sid = NULL;
256 uint32 num_groups = 0;
257 DOM_SID *user_sids = NULL;
258 BOOL u_in_group = False;
260 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
261 sid_to_string(sid_string, group_sid), domain->name ));
264 uid_t ret_uid = (uid_t)-1;
265 if (sys_getpeereid(state->sock, &ret_uid)==0) {
266 /* We know who's asking - look up their SID if
267 it's one we've mapped before. */
268 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
269 if (NT_STATUS_IS_OK(status)) {
270 pquerying_user_sid = &querying_user_sid;
271 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
272 (unsigned int)ret_uid,
273 sid_to_string(sid_string, pquerying_user_sid) ));
278 /* Only look up if it was a winbindd user in this domain. */
279 if (pquerying_user_sid &&
280 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
282 DEBUG(10,("fill_grent_mem: querying user = %s\n",
283 sid_to_string(sid_string, pquerying_user_sid) ));
285 status = domain->methods->lookup_usergroups(domain,
290 if (!NT_STATUS_IS_OK(status)) {
291 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
292 "for sid %s in domain %s (error: %s)\n",
293 sid_to_string(sid_string, pquerying_user_sid),
299 for (i = 0; i < num_groups; i++) {
300 if (sid_equal(group_sid, &user_sids[i])) {
301 /* User is in Domain Users, add their name
302 as the only group member. */
311 char *domainname = NULL;
312 char *username = NULL;
314 enum lsa_SidType type;
316 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
317 sid_to_string(sid_string, pquerying_user_sid), domain->name ));
319 status = domain->methods->sid_to_name(domain, mem_ctx,
324 if (!NT_STATUS_IS_OK(status)) {
325 DEBUG(1, ("could not lookup username for user "
326 "sid %s in domain %s (error: %s)\n",
327 sid_to_string(sid_string, pquerying_user_sid),
332 fill_domain_username(name, domain->name, username, True);
335 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
336 DEBUG(1, ("out of memory\n"));
339 memcpy(buf, name, buf_len);
341 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
342 name, domain->name ));
346 *gr_mem_len = buf_len;
349 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
350 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
355 /* Lookup group members */
356 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
357 &sid_mem, &names, &name_types);
358 if (!NT_STATUS_IS_OK(status)) {
359 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
360 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
364 DEBUG(10, ("looked up %d names\n", num_names));
366 if (DEBUGLEVEL >= 10) {
367 for (i = 0; i < num_names; i++)
368 DEBUG(10, ("\t%20s %s %d\n", names[i],
369 sid_string_static(&sid_mem[i]),
373 /* Add members to list */
377 for (i = 0; i < num_names; i++) {
384 DEBUG(10, ("processing name %s\n", the_name));
386 /* FIXME: need to cope with groups within groups. These
387 occur in Universal groups on a Windows 2000 native mode
390 /* make sure to allow machine accounts */
392 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
393 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
397 /* Append domain name */
399 fill_domain_username(name, domain->name, the_name, True);
403 /* Add to list or calculate buffer length */
406 buf_len += len + 1; /* List is comma separated */
408 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
410 DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
411 safe_strcpy(&buf[buf_ndx], name, len);
418 /* Allocate buffer */
420 if (!buf && buf_len != 0) {
421 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
422 DEBUG(1, ("out of memory\n"));
426 memset(buf, 0, buf_len);
430 if (buf && buf_ndx > 0) {
431 buf[buf_ndx - 1] = '\0';
435 *gr_mem_len = buf_len;
437 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
438 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
443 talloc_destroy(mem_ctx);
445 DEBUG(10, ("fill_grent_mem returning %d\n", result));
450 /* Return a group structure from a group name */
452 void winbindd_getgrnam(struct winbindd_cli_state *state)
454 DOM_SID group_sid, tmp_sid;
456 struct winbindd_domain *domain;
457 enum lsa_SidType name_type;
458 fstring name_domain, name_group;
466 /* Ensure null termination */
467 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
469 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
470 state->request.data.groupname));
472 /* Parse domain and groupname */
474 memset(name_group, 0, sizeof(fstring));
476 tmp = state->request.data.groupname;
478 parse_domain_user(tmp, name_domain, name_group);
480 /* if no domain or our local domain and no local tdb group, default to
481 * our local domain for aliases */
483 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
484 fstrcpy(name_domain, get_global_sam_name());
487 /* Get info for the domain */
489 if ((domain = find_domain_from_name(name_domain)) == NULL) {
490 DEBUG(3, ("could not get domain sid for domain %s\n",
492 request_error(state);
495 /* should we deal with users for our domain? */
497 if ( lp_winbind_trusted_domains_only() && domain->primary) {
498 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
499 "getgrnam() for %s\\%s.\n", name_domain, name_group));
500 request_error(state);
504 /* Get rid and name type from name */
506 ws_name_replace( name_group, '_' );
508 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
509 name_group, &group_sid, &name_type)) {
510 DEBUG(1, ("group %s in domain %s does not exist\n",
511 name_group, name_domain));
512 request_error(state);
516 if ( !((name_type==SID_NAME_DOM_GRP) ||
517 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
518 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
519 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
521 DEBUG(1, ("name '%s' is not a local, domain or builtin "
522 "group: %d\n", name_group, name_type));
523 request_error(state);
527 /* Make sure that the group SID is within the domain of the
530 sid_copy( &tmp_sid, &group_sid );
531 sid_split_rid( &tmp_sid, &grp_rid );
532 if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
533 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
534 state->request.data.groupname, sid_string_static(&group_sid)));
535 request_error(state);
541 /* Try to get the GID */
543 status = idmap_sid_to_gid(&group_sid, &gid);
545 if (NT_STATUS_IS_OK(status)) {
549 /* Maybe it's one of our aliases in passdb */
551 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
552 ((name_type == SID_NAME_ALIAS) ||
553 (name_type == SID_NAME_WKN_GRP))) {
558 DEBUG(1, ("error converting unix gid to sid\n"));
559 request_error(state);
564 if (!fill_grent(&state->response.data.gr, name_domain,
566 !fill_grent_mem(domain, state, &group_sid, name_type,
568 &gr_mem, &gr_mem_len)) {
569 request_error(state);
573 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
575 /* Group membership lives at start of extra data */
577 state->response.data.gr.gr_mem_ofs = 0;
579 state->response.length += gr_mem_len;
580 state->response.extra_data.data = gr_mem;
584 static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
586 struct winbindd_domain *domain;
587 enum lsa_SidType name_type;
594 /* Get name from sid */
596 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, &dom_name,
597 &group_name, &name_type)) {
598 DEBUG(1, ("could not lookup sid\n"));
599 request_error(state);
600 TALLOC_FREE(group_name);
601 TALLOC_FREE(dom_name);
605 /* Fill in group structure */
607 domain = find_domain_from_sid_noinit(&group_sid);
610 DEBUG(1,("Can't find domain from sid\n"));
611 request_error(state);
612 TALLOC_FREE(group_name);
613 TALLOC_FREE(dom_name);
617 if ( !((name_type==SID_NAME_DOM_GRP) ||
618 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
619 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
621 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
622 group_name, name_type));
623 request_error(state);
624 TALLOC_FREE(group_name);
625 TALLOC_FREE(dom_name);
629 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
630 state->request.data.gid) ||
631 !fill_grent_mem(domain, state, &group_sid, name_type,
633 &gr_mem, &gr_mem_len)) {
634 request_error(state);
635 TALLOC_FREE(group_name);
636 TALLOC_FREE(dom_name);
640 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
642 /* Group membership lives at start of extra data */
644 state->response.data.gr.gr_mem_ofs = 0;
646 state->response.length += gr_mem_len;
647 state->response.extra_data.data = gr_mem;
649 TALLOC_FREE(group_name);
650 TALLOC_FREE(dom_name);
655 static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
657 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
658 enum lsa_SidType name_type;
662 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
663 (unsigned long)(state->request.data.gid), sid));
665 string_to_sid(&group_sid, sid);
666 getgrgid_got_sid(state, group_sid);
670 /* Ok, this might be "ours", i.e. an alias */
671 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
672 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
673 (name_type == SID_NAME_ALIAS)) {
674 /* Hey, got an alias */
675 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
676 (unsigned long)(state->request.data.gid), sid));
677 getgrgid_got_sid(state, group_sid);
681 DEBUG(1, ("could not convert gid %lu to sid\n",
682 (unsigned long)state->request.data.gid));
683 request_error(state);
686 /* Return a group structure from a gid number */
687 void winbindd_getgrgid(struct winbindd_cli_state *state)
689 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
690 (unsigned long)state->request.data.gid));
692 /* always use the async interface */
693 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
697 * set/get/endgrent functions
700 /* "Rewind" file pointer for group database enumeration */
702 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
704 struct winbindd_domain *domain;
706 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
708 /* Check user has enabled this */
710 if (!lp_winbind_enum_groups()) {
714 /* Free old static data if it exists */
716 if (state->getgrent_state != NULL) {
717 free_getent_state(state->getgrent_state);
718 state->getgrent_state = NULL;
721 /* Create sam pipes for each domain we know about */
723 for (domain = domain_list(); domain != NULL; domain = domain->next) {
724 struct getent_state *domain_state;
726 /* Create a state record for this domain */
728 /* don't add our domaina if we are a PDC or if we
729 are a member of a Samba domain */
731 if ( lp_winbind_trusted_domains_only() && domain->primary )
737 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
738 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
742 ZERO_STRUCTP(domain_state);
744 fstrcpy(domain_state->domain_name, domain->name);
746 /* Add to list of open domains */
748 DLIST_ADD(state->getgrent_state, domain_state);
751 state->getgrent_initialized = True;
755 void winbindd_setgrent(struct winbindd_cli_state *state)
757 if (winbindd_setgrent_internal(state)) {
760 request_error(state);
764 /* Close file pointer to ntdom group database */
766 void winbindd_endgrent(struct winbindd_cli_state *state)
768 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
770 free_getent_state(state->getgrent_state);
771 state->getgrent_initialized = False;
772 state->getgrent_state = NULL;
776 /* Get the list of domain groups and domain aliases for a domain. We fill in
777 the sam_entries and num_sam_entries fields with domain group information.
778 The dispinfo_ndx field is incremented to the index of the next group to
779 fetch. Return True if some groups were returned, False otherwise. */
781 static BOOL get_sam_group_entries(struct getent_state *ent)
785 struct acct_info *name_list = NULL;
788 struct acct_info *sam_grp_entries = NULL;
789 struct winbindd_domain *domain;
791 if (ent->got_sam_entries)
794 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
795 ent->domain_name))) {
796 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
800 /* Free any existing group info */
802 SAFE_FREE(ent->sam_entries);
803 ent->num_sam_entries = 0;
804 ent->got_sam_entries = True;
806 /* Enumerate domain groups */
810 if (!(domain = find_domain_from_name(ent->domain_name))) {
811 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
815 /* always get the domain global groups */
817 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
819 if (!NT_STATUS_IS_OK(status)) {
820 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
825 /* Copy entries into return buffer */
828 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
829 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
834 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
837 ent->num_sam_entries = num_entries;
839 /* get the domain local groups if we are a member of a native win2k domain
840 and are not using LDAP to get the groups */
842 if ( ( lp_security() != SEC_ADS && domain->native_mode
843 && domain->primary) || domain->internal )
845 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
846 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
848 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
850 if ( !NT_STATUS_IS_OK(status) ) {
851 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
855 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
857 /* Copy entries into return buffer */
860 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
862 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
868 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
869 num_entries * sizeof(struct acct_info) );
872 ent->num_sam_entries += num_entries;
876 /* Fill in remaining fields */
878 ent->sam_entries = name_list;
879 ent->sam_entry_index = 0;
881 result = (ent->num_sam_entries > 0);
884 talloc_destroy(mem_ctx);
889 /* Fetch next group entry from ntdom database */
891 #define MAX_GETGRENT_GROUPS 500
893 void winbindd_getgrent(struct winbindd_cli_state *state)
895 struct getent_state *ent;
896 struct winbindd_gr *group_list = NULL;
897 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
898 char *gr_mem_list = NULL;
900 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
902 /* Check user has enabled this */
904 if (!lp_winbind_enum_groups()) {
905 request_error(state);
909 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
911 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
912 request_error(state);
916 memset(state->response.extra_data.data, '\0',
917 num_groups * sizeof(struct winbindd_gr) );
919 state->response.data.num_entries = 0;
921 group_list = (struct winbindd_gr *)state->response.extra_data.data;
923 if (!state->getgrent_initialized)
924 winbindd_setgrent_internal(state);
926 if (!(ent = state->getgrent_state)) {
927 request_error(state);
931 /* Start sending back groups */
933 for (i = 0; i < num_groups; i++) {
934 struct acct_info *name_list = NULL;
935 fstring domain_group_name;
941 struct winbindd_domain *domain;
943 /* Do we need to fetch another chunk of groups? */
947 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
948 ent->sam_entry_index, ent->num_sam_entries));
950 if (ent->num_sam_entries == ent->sam_entry_index) {
952 while(ent && !get_sam_group_entries(ent)) {
953 struct getent_state *next_ent;
955 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
957 /* Free state information for this domain */
959 SAFE_FREE(ent->sam_entries);
961 next_ent = ent->next;
962 DLIST_REMOVE(state->getgrent_state, ent);
968 /* No more domains */
974 name_list = (struct acct_info *)ent->sam_entries;
977 find_domain_from_name(ent->domain_name))) {
978 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
983 /* Lookup group info */
985 sid_copy(&group_sid, &domain->sid);
986 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
988 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
990 enum lsa_SidType type;
992 DEBUG(10, ("SID %s not in idmap\n",
993 sid_string_static(&group_sid)));
995 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
996 DEBUG(1, ("could not look up gid for group "
998 name_list[ent->sam_entry_index].acct_name));
999 ent->sam_entry_index++;
1003 if ((type != SID_NAME_DOM_GRP) &&
1004 (type != SID_NAME_ALIAS) &&
1005 (type != SID_NAME_WKN_GRP)) {
1006 DEBUG(1, ("Group %s is a %s, not a group\n",
1007 sid_type_lookup(type),
1008 name_list[ent->sam_entry_index].acct_name));
1009 ent->sam_entry_index++;
1015 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1016 (unsigned long)name_list[ent->sam_entry_index].rid));
1018 /* Fill in group entry */
1020 fill_domain_username(domain_group_name, ent->domain_name,
1021 name_list[ent->sam_entry_index].acct_name, True);
1023 result = fill_grent(&group_list[group_list_ndx],
1025 name_list[ent->sam_entry_index].acct_name,
1028 /* Fill in group membership entry */
1031 size_t num_gr_mem = 0;
1033 group_list[group_list_ndx].num_gr_mem = 0;
1037 /* Get group membership */
1038 if (state->request.cmd == WINBINDD_GETGRLST) {
1041 sid_copy(&member_sid, &domain->sid);
1042 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1043 result = fill_grent_mem(
1049 &gr_mem, &gr_mem_len);
1051 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1056 /* Append to group membership list */
1057 gr_mem_list = (char *)SMB_REALLOC(
1058 gr_mem_list, gr_mem_list_len + gr_mem_len);
1060 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
1061 DEBUG(0, ("out of memory\n"));
1062 gr_mem_list_len = 0;
1066 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1067 gr_mem_list_len, (unsigned int)gr_mem_len));
1069 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1074 group_list[group_list_ndx].gr_mem_ofs =
1077 gr_mem_list_len += gr_mem_len;
1080 ent->sam_entry_index++;
1082 /* Add group to return list */
1086 DEBUG(10, ("adding group num_entries = %d\n",
1087 state->response.data.num_entries));
1090 state->response.data.num_entries++;
1092 state->response.length +=
1093 sizeof(struct winbindd_gr);
1096 DEBUG(0, ("could not lookup domain group %s\n",
1097 domain_group_name));
1101 /* Copy the list of group memberships to the end of the extra data */
1103 if (group_list_ndx == 0)
1106 state->response.extra_data.data = SMB_REALLOC(
1107 state->response.extra_data.data,
1108 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1110 if (!state->response.extra_data.data) {
1111 DEBUG(0, ("out of memory\n"));
1113 SAFE_FREE(gr_mem_list);
1114 request_error(state);
1118 memcpy(&((char *)state->response.extra_data.data)
1119 [group_list_ndx * sizeof(struct winbindd_gr)],
1120 gr_mem_list, gr_mem_list_len);
1122 state->response.length += gr_mem_list_len;
1124 DEBUG(10, ("returning %d groups, length = %d\n",
1125 group_list_ndx, gr_mem_list_len));
1127 /* Out of domains */
1131 SAFE_FREE(gr_mem_list);
1133 if (group_list_ndx > 0)
1136 request_error(state);
1139 /* List domain groups without mapping to unix ids */
1141 void winbindd_list_groups(struct winbindd_cli_state *state)
1143 uint32 total_entries = 0;
1144 struct winbindd_domain *domain;
1145 const char *which_domain;
1146 char *extra_data = NULL;
1147 unsigned int extra_data_len = 0, i;
1149 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1151 /* Ensure null termination */
1152 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1153 which_domain = state->request.domain_name;
1155 /* Enumerate over trusted domains */
1157 for (domain = domain_list(); domain; domain = domain->next) {
1158 struct getent_state groups;
1160 /* if we have a domain name restricting the request and this
1161 one in the list doesn't match, then just bypass the remainder
1164 if ( *which_domain && !strequal(which_domain, domain->name) )
1167 ZERO_STRUCT(groups);
1169 /* Get list of sam groups */
1171 fstrcpy(groups.domain_name, domain->name);
1173 get_sam_group_entries(&groups);
1175 if (groups.num_sam_entries == 0) {
1176 /* this domain is empty or in an error state */
1180 /* keep track the of the total number of groups seen so
1181 far over all domains */
1182 total_entries += groups.num_sam_entries;
1184 /* Allocate some memory for extra data. Note that we limit
1185 account names to sizeof(fstring) = 128 characters. */
1186 extra_data = (char *)SMB_REALLOC(
1187 extra_data, sizeof(fstring) * total_entries);
1190 DEBUG(0,("failed to enlarge buffer!\n"));
1191 request_error(state);
1195 /* Pack group list into extra data fields */
1196 for (i = 0; i < groups.num_sam_entries; i++) {
1197 char *group_name = ((struct acct_info *)
1198 groups.sam_entries)[i].acct_name;
1201 fill_domain_username(name, domain->name, group_name, True);
1202 /* Append to extra data */
1203 memcpy(&extra_data[extra_data_len], name,
1205 extra_data_len += strlen(name);
1206 extra_data[extra_data_len++] = ',';
1209 SAFE_FREE(groups.sam_entries);
1212 /* Assign extra_data fields in response structure */
1214 extra_data[extra_data_len - 1] = '\0';
1215 state->response.extra_data.data = extra_data;
1216 state->response.length += extra_data_len;
1219 /* No domains may have responded but that's still OK so don't
1225 /* Get user supplementary groups. This is much quicker than trying to
1226 invert the groups database. We merge the groups from the gids and
1227 other_sids info3 fields as trusted domain, universal group
1228 memberships, and nested groups (win2k native mode only) are not
1229 returned by the getgroups RPC call but are present in the info3. */
1231 struct getgroups_state {
1232 struct winbindd_cli_state *state;
1233 struct winbindd_domain *domain;
1238 const DOM_SID *token_sids;
1239 size_t i, num_token_sids;
1242 size_t num_token_gids;
1245 static void getgroups_usersid_recv(void *private_data, BOOL success,
1246 const DOM_SID *sid, enum lsa_SidType type);
1247 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1248 DOM_SID *token_sids, size_t num_token_sids);
1249 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
1251 void winbindd_getgroups(struct winbindd_cli_state *state)
1253 struct getgroups_state *s;
1255 /* Ensure null termination */
1256 state->request.data.username
1257 [sizeof(state->request.data.username)-1]='\0';
1259 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1260 state->request.data.username));
1262 /* Parse domain and username */
1264 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1266 DEBUG(0, ("talloc failed\n"));
1267 request_error(state);
1273 if (!parse_domain_user_talloc(state->mem_ctx,
1274 state->request.data.username,
1275 &s->domname, &s->username)) {
1276 DEBUG(5, ("Could not parse domain user: %s\n",
1277 state->request.data.username));
1279 /* error out if we do not have nested group support */
1281 if ( !lp_winbind_nested_groups() ) {
1282 request_error(state);
1286 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1287 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1290 /* Get info for the domain */
1292 s->domain = find_domain_from_name_noinit(s->domname);
1294 if (s->domain == NULL) {
1295 DEBUG(7, ("could not find domain entry for domain %s\n",
1297 request_error(state);
1301 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1302 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
1303 "getgroups() for %s\\%s.\n", s->domname,
1305 request_error(state);
1309 /* Get rid and name type from name. The following costs 1 packet */
1311 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1312 getgroups_usersid_recv, s);
1315 static void getgroups_usersid_recv(void *private_data, BOOL success,
1316 const DOM_SID *sid, enum lsa_SidType type)
1318 struct getgroups_state *s =
1319 (struct getgroups_state *)private_data;
1322 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1323 request_error(s->state);
1327 sid_copy(&s->user_sid, sid);
1329 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1330 getgroups_tokensids_recv, s);
1333 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1334 DOM_SID *token_sids, size_t num_token_sids)
1336 struct getgroups_state *s =
1337 (struct getgroups_state *)private_data;
1339 /* We need at least the user sid and the primary group in the token,
1340 * otherwise it's an error */
1342 if ((!success) || (num_token_sids < 2)) {
1343 request_error(s->state);
1347 s->token_sids = token_sids;
1348 s->num_token_sids = num_token_sids;
1351 s->token_gids = NULL;
1352 s->num_token_gids = 0;
1354 getgroups_sid2gid_recv(s, False, 0);
1357 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1359 struct getgroups_state *s =
1360 (struct getgroups_state *)private_data;
1363 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1365 &s->num_token_gids)) {
1370 if (s->i < s->num_token_sids) {
1371 const DOM_SID *sid = &s->token_sids[s->i];
1374 if (sid_equal(sid, &s->user_sid)) {
1375 getgroups_sid2gid_recv(s, False, 0);
1379 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1380 getgroups_sid2gid_recv, s);
1384 s->state->response.data.num_entries = s->num_token_gids;
1385 /* s->token_gids are talloced */
1386 s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
1387 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1388 request_ok(s->state);
1391 /* Get user supplementary sids. This is equivalent to the
1392 winbindd_getgroups() function but it involves a SID->SIDs mapping
1393 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1394 idmap. This call is designed to be used with applications that need
1395 to do ACL evaluation themselves. Note that the cached info3 data is
1398 this function assumes that the SID that comes in is a user SID. If
1399 you pass in another type of SID then you may get unpredictable
1403 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1406 void winbindd_getusersids(struct winbindd_cli_state *state)
1410 /* Ensure null termination */
1411 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1413 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1414 if (user_sid == NULL) {
1415 DEBUG(1, ("talloc failed\n"));
1416 request_error(state);
1420 if (!string_to_sid(user_sid, state->request.data.sid)) {
1421 DEBUG(1, ("Could not get convert sid %s from string\n",
1422 state->request.data.sid));
1423 request_error(state);
1427 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1431 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1434 struct winbindd_cli_state *state =
1435 (struct winbindd_cli_state *)private_data;
1437 unsigned ofs, ret_size = 0;
1441 request_error(state);
1445 /* work out the response size */
1446 for (i = 0; i < num_sids; i++) {
1447 const char *s = sid_string_static(&sids[i]);
1448 ret_size += strlen(s) + 1;
1451 /* build the reply */
1452 ret = (char *)SMB_MALLOC(ret_size);
1454 DEBUG(0, ("malloc failed\n"));
1455 request_error(state);
1459 for (i = 0; i < num_sids; i++) {
1460 const char *s = sid_string_static(&sids[i]);
1461 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1462 ofs += strlen(ret+ofs) + 1;
1465 /* Send data back to client */
1466 state->response.data.num_entries = num_sids;
1467 state->response.extra_data.data = ret;
1468 state->response.length += ret_size;
1472 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1475 struct winbindd_domain *domain;
1477 /* Ensure null termination */
1478 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1480 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1481 DEBUG(1, ("Could not get convert sid %s from string\n",
1482 state->request.data.sid));
1483 request_error(state);
1487 /* Get info for the domain */
1488 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1489 DEBUG(0,("could not find domain entry for sid %s\n",
1490 sid_string_static(&user_sid)));
1491 request_error(state);
1495 sendto_domain(state, domain);
1498 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1499 struct winbindd_cli_state *state)
1509 /* Ensure null termination */
1510 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1512 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1513 DEBUG(1, ("Could not get convert sid %s from string\n",
1514 state->request.data.sid));
1515 return WINBINDD_ERROR;
1518 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1519 &user_sid, &num_groups,
1521 if (!NT_STATUS_IS_OK(status))
1522 return WINBINDD_ERROR;
1524 if (num_groups == 0) {
1525 state->response.data.num_entries = 0;
1526 state->response.extra_data.data = NULL;
1530 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1531 DEBUG(0, ("talloc failed\n"));
1532 return WINBINDD_ERROR;
1535 state->response.extra_data.data = SMB_STRDUP(sidstring);
1536 if (!state->response.extra_data.data) {
1537 return WINBINDD_ERROR;
1539 state->response.length += len+1;
1540 state->response.data.num_entries = num_groups;