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);
165 TALLOC_FREE(members);
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)));
224 /* Initialize with no members */
227 /* HACK ALERT!! This whole routine does not cope with group members
228 * from more than one domain, ie aliases. Thus we have to work it out
229 * ourselves in a special routine. */
231 if (domain->internal) {
232 result = fill_passdb_alias_grmem(domain, group_sid,
238 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
239 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
241 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
242 sid_to_string(sid_string, group_sid), domain->name,
247 /* OPTIMIZATION / HACK. */
248 /* If "enum users" is set to false, and the group being looked
249 up is the Domain Users SID: S-1-5-domain-513, then for the
250 list of members check if the querying user is in that group,
251 and if so only return that user as the gr_mem array.
252 We can change this to a different parameter than "enum users"
253 if neccessaey, or parameterize the group list we do this for. */
255 sid_peek_rid( group_sid, &group_rid );
256 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
257 DOM_SID querying_user_sid;
258 DOM_SID *pquerying_user_sid = NULL;
259 uint32 num_groups = 0;
260 DOM_SID *user_sids = NULL;
261 BOOL u_in_group = False;
263 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
264 sid_to_string(sid_string, group_sid), domain->name ));
267 uid_t ret_uid = (uid_t)-1;
268 if (sys_getpeereid(state->sock, &ret_uid)==0) {
269 /* We know who's asking - look up their SID if
270 it's one we've mapped before. */
271 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
272 if (NT_STATUS_IS_OK(status)) {
273 pquerying_user_sid = &querying_user_sid;
274 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
275 (unsigned int)ret_uid,
276 sid_to_string(sid_string, pquerying_user_sid) ));
281 /* Only look up if it was a winbindd user in this domain. */
282 if (pquerying_user_sid &&
283 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
285 DEBUG(10,("fill_grent_mem: querying user = %s\n",
286 sid_to_string(sid_string, pquerying_user_sid) ));
288 status = domain->methods->lookup_usergroups(domain,
293 if (!NT_STATUS_IS_OK(status)) {
294 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
295 "for sid %s in domain %s (error: %s)\n",
296 sid_to_string(sid_string, pquerying_user_sid),
302 for (i = 0; i < num_groups; i++) {
303 if (sid_equal(group_sid, &user_sids[i])) {
304 /* User is in Domain Users, add their name
305 as the only group member. */
314 char *domainname = NULL;
315 char *username = NULL;
317 enum lsa_SidType type;
319 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
320 sid_to_string(sid_string, pquerying_user_sid), domain->name ));
322 status = domain->methods->sid_to_name(domain, mem_ctx,
327 if (!NT_STATUS_IS_OK(status)) {
328 DEBUG(1, ("could not lookup username for user "
329 "sid %s in domain %s (error: %s)\n",
330 sid_to_string(sid_string, pquerying_user_sid),
335 fill_domain_username(name, domain->name, username, True);
338 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
339 DEBUG(1, ("out of memory\n"));
342 memcpy(buf, name, buf_len);
344 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
345 name, domain->name ));
347 /* user is the only member */
352 *gr_mem_len = buf_len;
354 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
355 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
360 /* Lookup group members */
361 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
362 &sid_mem, &names, &name_types);
363 if (!NT_STATUS_IS_OK(status)) {
364 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
365 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
369 DEBUG(10, ("looked up %d names\n", num_names));
371 if (DEBUGLEVEL >= 10) {
372 for (i = 0; i < num_names; i++)
373 DEBUG(10, ("\t%20s %s %d\n", names[i],
374 sid_string_static(&sid_mem[i]),
378 /* Add members to list */
382 for (i = 0; i < num_names; i++) {
389 DEBUG(10, ("processing name %s\n", the_name));
391 /* FIXME: need to cope with groups within groups. These
392 occur in Universal groups on a Windows 2000 native mode
395 /* make sure to allow machine accounts */
397 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
398 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
402 /* Append domain name */
404 fill_domain_username(name, domain->name, the_name, True);
408 /* Add to list or calculate buffer length */
411 buf_len += len + 1; /* List is comma separated */
413 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
415 DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
416 safe_strcpy(&buf[buf_ndx], name, len);
423 /* Allocate buffer */
425 if (!buf && buf_len != 0) {
426 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
427 DEBUG(1, ("out of memory\n"));
431 memset(buf, 0, buf_len);
435 if (buf && buf_ndx > 0) {
436 buf[buf_ndx - 1] = '\0';
440 *gr_mem_len = buf_len;
442 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
443 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
448 talloc_destroy(mem_ctx);
450 DEBUG(10, ("fill_grent_mem returning %d\n", result));
455 /* Return a group structure from a group name */
457 void winbindd_getgrnam(struct winbindd_cli_state *state)
459 DOM_SID group_sid, tmp_sid;
461 struct winbindd_domain *domain;
462 enum lsa_SidType name_type;
463 fstring name_domain, name_group;
471 /* Ensure null termination */
472 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
474 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
475 state->request.data.groupname));
477 /* Parse domain and groupname */
479 memset(name_group, 0, sizeof(fstring));
481 tmp = state->request.data.groupname;
483 parse_domain_user(tmp, name_domain, name_group);
485 /* if no domain or our local domain and no local tdb group, default to
486 * our local domain for aliases */
488 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
489 fstrcpy(name_domain, get_global_sam_name());
492 /* Get info for the domain */
494 if ((domain = find_domain_from_name(name_domain)) == NULL) {
495 DEBUG(3, ("could not get domain sid for domain %s\n",
497 request_error(state);
500 /* should we deal with users for our domain? */
502 if ( lp_winbind_trusted_domains_only() && domain->primary) {
503 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
504 "getgrnam() for %s\\%s.\n", name_domain, name_group));
505 request_error(state);
509 /* Get rid and name type from name */
511 ws_name_replace( name_group, WB_REPLACE_CHAR );
513 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
514 name_group, &group_sid, &name_type)) {
515 DEBUG(1, ("group %s in domain %s does not exist\n",
516 name_group, name_domain));
517 request_error(state);
521 if ( !((name_type==SID_NAME_DOM_GRP) ||
522 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
523 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
524 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
526 DEBUG(1, ("name '%s' is not a local, domain or builtin "
527 "group: %d\n", name_group, name_type));
528 request_error(state);
532 /* Make sure that the group SID is within the domain of the
535 sid_copy( &tmp_sid, &group_sid );
536 sid_split_rid( &tmp_sid, &grp_rid );
537 if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
538 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
539 state->request.data.groupname, sid_string_static(&group_sid)));
540 request_error(state);
546 /* Try to get the GID */
548 status = idmap_sid_to_gid(&group_sid, &gid);
550 if (NT_STATUS_IS_OK(status)) {
554 /* Maybe it's one of our aliases in passdb */
556 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
557 ((name_type == SID_NAME_ALIAS) ||
558 (name_type == SID_NAME_WKN_GRP))) {
563 DEBUG(1, ("error converting unix gid to sid\n"));
564 request_error(state);
569 if (!fill_grent(&state->response.data.gr, name_domain,
571 !fill_grent_mem(domain, state, &group_sid, name_type,
573 &gr_mem, &gr_mem_len)) {
574 request_error(state);
578 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
580 /* Group membership lives at start of extra data */
582 state->response.data.gr.gr_mem_ofs = 0;
584 state->response.length += gr_mem_len;
585 state->response.extra_data.data = gr_mem;
589 static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
591 struct winbindd_domain *domain;
592 enum lsa_SidType name_type;
599 /* Get name from sid */
601 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, &dom_name,
602 &group_name, &name_type)) {
603 DEBUG(1, ("could not lookup sid\n"));
604 request_error(state);
605 TALLOC_FREE(group_name);
606 TALLOC_FREE(dom_name);
610 /* Fill in group structure */
612 domain = find_domain_from_sid_noinit(&group_sid);
615 DEBUG(1,("Can't find domain from sid\n"));
616 request_error(state);
617 TALLOC_FREE(group_name);
618 TALLOC_FREE(dom_name);
622 if ( !((name_type==SID_NAME_DOM_GRP) ||
623 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
624 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
626 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
627 group_name, name_type));
628 request_error(state);
629 TALLOC_FREE(group_name);
630 TALLOC_FREE(dom_name);
634 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
635 state->request.data.gid) ||
636 !fill_grent_mem(domain, state, &group_sid, name_type,
638 &gr_mem, &gr_mem_len)) {
639 request_error(state);
640 TALLOC_FREE(group_name);
641 TALLOC_FREE(dom_name);
645 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
647 /* Group membership lives at start of extra data */
649 state->response.data.gr.gr_mem_ofs = 0;
651 state->response.length += gr_mem_len;
652 state->response.extra_data.data = gr_mem;
654 TALLOC_FREE(group_name);
655 TALLOC_FREE(dom_name);
660 static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
662 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
663 enum lsa_SidType name_type;
667 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
668 (unsigned long)(state->request.data.gid), sid));
670 string_to_sid(&group_sid, sid);
671 getgrgid_got_sid(state, group_sid);
675 /* Ok, this might be "ours", i.e. an alias */
676 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
677 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
678 (name_type == SID_NAME_ALIAS)) {
679 /* Hey, got an alias */
680 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
681 (unsigned long)(state->request.data.gid), sid));
682 getgrgid_got_sid(state, group_sid);
686 DEBUG(1, ("could not convert gid %lu to sid\n",
687 (unsigned long)state->request.data.gid));
688 request_error(state);
691 /* Return a group structure from a gid number */
692 void winbindd_getgrgid(struct winbindd_cli_state *state)
694 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
695 (unsigned long)state->request.data.gid));
697 /* always use the async interface */
698 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
702 * set/get/endgrent functions
705 /* "Rewind" file pointer for group database enumeration */
707 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
709 struct winbindd_domain *domain;
711 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
713 /* Check user has enabled this */
715 if (!lp_winbind_enum_groups()) {
719 /* Free old static data if it exists */
721 if (state->getgrent_state != NULL) {
722 free_getent_state(state->getgrent_state);
723 state->getgrent_state = NULL;
726 /* Create sam pipes for each domain we know about */
728 for (domain = domain_list(); domain != NULL; domain = domain->next) {
729 struct getent_state *domain_state;
731 /* Create a state record for this domain */
733 /* don't add our domaina if we are a PDC or if we
734 are a member of a Samba domain */
736 if ( lp_winbind_trusted_domains_only() && domain->primary )
742 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
743 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
747 ZERO_STRUCTP(domain_state);
749 fstrcpy(domain_state->domain_name, domain->name);
751 /* Add to list of open domains */
753 DLIST_ADD(state->getgrent_state, domain_state);
756 state->getgrent_initialized = True;
760 void winbindd_setgrent(struct winbindd_cli_state *state)
762 if (winbindd_setgrent_internal(state)) {
765 request_error(state);
769 /* Close file pointer to ntdom group database */
771 void winbindd_endgrent(struct winbindd_cli_state *state)
773 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
775 free_getent_state(state->getgrent_state);
776 state->getgrent_initialized = False;
777 state->getgrent_state = NULL;
781 /* Get the list of domain groups and domain aliases for a domain. We fill in
782 the sam_entries and num_sam_entries fields with domain group information.
783 The dispinfo_ndx field is incremented to the index of the next group to
784 fetch. Return True if some groups were returned, False otherwise. */
786 static BOOL get_sam_group_entries(struct getent_state *ent)
790 struct acct_info *name_list = NULL;
793 struct acct_info *sam_grp_entries = NULL;
794 struct winbindd_domain *domain;
796 if (ent->got_sam_entries)
799 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
800 ent->domain_name))) {
801 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
805 /* Free any existing group info */
807 SAFE_FREE(ent->sam_entries);
808 ent->num_sam_entries = 0;
809 ent->got_sam_entries = True;
811 /* Enumerate domain groups */
815 if (!(domain = find_domain_from_name(ent->domain_name))) {
816 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
820 /* always get the domain global groups */
822 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
824 if (!NT_STATUS_IS_OK(status)) {
825 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
830 /* Copy entries into return buffer */
833 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
834 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
839 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
842 ent->num_sam_entries = num_entries;
844 /* get the domain local groups if we are a member of a native win2k domain
845 and are not using LDAP to get the groups */
847 if ( ( lp_security() != SEC_ADS && domain->native_mode
848 && domain->primary) || domain->internal )
850 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
851 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
853 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
855 if ( !NT_STATUS_IS_OK(status) ) {
856 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
860 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
862 /* Copy entries into return buffer */
865 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
867 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
873 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
874 num_entries * sizeof(struct acct_info) );
877 ent->num_sam_entries += num_entries;
881 /* Fill in remaining fields */
883 ent->sam_entries = name_list;
884 ent->sam_entry_index = 0;
886 result = (ent->num_sam_entries > 0);
889 talloc_destroy(mem_ctx);
894 /* Fetch next group entry from ntdom database */
896 #define MAX_GETGRENT_GROUPS 500
898 void winbindd_getgrent(struct winbindd_cli_state *state)
900 struct getent_state *ent;
901 struct winbindd_gr *group_list = NULL;
902 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
903 char *gr_mem_list = NULL;
905 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
907 /* Check user has enabled this */
909 if (!lp_winbind_enum_groups()) {
910 request_error(state);
914 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
916 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
917 request_error(state);
921 memset(state->response.extra_data.data, '\0',
922 num_groups * sizeof(struct winbindd_gr) );
924 state->response.data.num_entries = 0;
926 group_list = (struct winbindd_gr *)state->response.extra_data.data;
928 if (!state->getgrent_initialized)
929 winbindd_setgrent_internal(state);
931 if (!(ent = state->getgrent_state)) {
932 request_error(state);
936 /* Start sending back groups */
938 for (i = 0; i < num_groups; i++) {
939 struct acct_info *name_list = NULL;
940 fstring domain_group_name;
946 struct winbindd_domain *domain;
948 /* Do we need to fetch another chunk of groups? */
952 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
953 ent->sam_entry_index, ent->num_sam_entries));
955 if (ent->num_sam_entries == ent->sam_entry_index) {
957 while(ent && !get_sam_group_entries(ent)) {
958 struct getent_state *next_ent;
960 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
962 /* Free state information for this domain */
964 SAFE_FREE(ent->sam_entries);
966 next_ent = ent->next;
967 DLIST_REMOVE(state->getgrent_state, ent);
973 /* No more domains */
979 name_list = (struct acct_info *)ent->sam_entries;
982 find_domain_from_name(ent->domain_name))) {
983 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
988 /* Lookup group info */
990 sid_copy(&group_sid, &domain->sid);
991 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
993 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
995 enum lsa_SidType type;
997 DEBUG(10, ("SID %s not in idmap\n",
998 sid_string_static(&group_sid)));
1000 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1001 DEBUG(1, ("could not look up gid for group "
1003 name_list[ent->sam_entry_index].acct_name));
1004 ent->sam_entry_index++;
1008 if ((type != SID_NAME_DOM_GRP) &&
1009 (type != SID_NAME_ALIAS) &&
1010 (type != SID_NAME_WKN_GRP)) {
1011 DEBUG(1, ("Group %s is a %s, not a group\n",
1012 sid_type_lookup(type),
1013 name_list[ent->sam_entry_index].acct_name));
1014 ent->sam_entry_index++;
1020 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1021 (unsigned long)name_list[ent->sam_entry_index].rid));
1023 /* Fill in group entry */
1025 fill_domain_username(domain_group_name, ent->domain_name,
1026 name_list[ent->sam_entry_index].acct_name, True);
1028 result = fill_grent(&group_list[group_list_ndx],
1030 name_list[ent->sam_entry_index].acct_name,
1033 /* Fill in group membership entry */
1036 size_t num_gr_mem = 0;
1038 group_list[group_list_ndx].num_gr_mem = 0;
1042 /* Get group membership */
1043 if (state->request.cmd == WINBINDD_GETGRLST) {
1046 sid_copy(&member_sid, &domain->sid);
1047 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1048 result = fill_grent_mem(
1054 &gr_mem, &gr_mem_len);
1056 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1061 /* Append to group membership list */
1062 gr_mem_list = (char *)SMB_REALLOC(
1063 gr_mem_list, gr_mem_list_len + gr_mem_len);
1065 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
1066 DEBUG(0, ("out of memory\n"));
1067 gr_mem_list_len = 0;
1071 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1072 gr_mem_list_len, (unsigned int)gr_mem_len));
1074 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1079 group_list[group_list_ndx].gr_mem_ofs =
1082 gr_mem_list_len += gr_mem_len;
1085 ent->sam_entry_index++;
1087 /* Add group to return list */
1091 DEBUG(10, ("adding group num_entries = %d\n",
1092 state->response.data.num_entries));
1095 state->response.data.num_entries++;
1097 state->response.length +=
1098 sizeof(struct winbindd_gr);
1101 DEBUG(0, ("could not lookup domain group %s\n",
1102 domain_group_name));
1106 /* Copy the list of group memberships to the end of the extra data */
1108 if (group_list_ndx == 0)
1111 state->response.extra_data.data = SMB_REALLOC(
1112 state->response.extra_data.data,
1113 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1115 if (!state->response.extra_data.data) {
1116 DEBUG(0, ("out of memory\n"));
1118 SAFE_FREE(gr_mem_list);
1119 request_error(state);
1123 memcpy(&((char *)state->response.extra_data.data)
1124 [group_list_ndx * sizeof(struct winbindd_gr)],
1125 gr_mem_list, gr_mem_list_len);
1127 state->response.length += gr_mem_list_len;
1129 DEBUG(10, ("returning %d groups, length = %d\n",
1130 group_list_ndx, gr_mem_list_len));
1132 /* Out of domains */
1136 SAFE_FREE(gr_mem_list);
1138 if (group_list_ndx > 0)
1141 request_error(state);
1144 /* List domain groups without mapping to unix ids */
1146 void winbindd_list_groups(struct winbindd_cli_state *state)
1148 uint32 total_entries = 0;
1149 struct winbindd_domain *domain;
1150 const char *which_domain;
1151 char *extra_data = NULL;
1152 unsigned int extra_data_len = 0, i;
1154 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1156 /* Ensure null termination */
1157 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1158 which_domain = state->request.domain_name;
1160 /* Enumerate over trusted domains */
1162 for (domain = domain_list(); domain; domain = domain->next) {
1163 struct getent_state groups;
1165 /* if we have a domain name restricting the request and this
1166 one in the list doesn't match, then just bypass the remainder
1169 if ( *which_domain && !strequal(which_domain, domain->name) )
1172 ZERO_STRUCT(groups);
1174 /* Get list of sam groups */
1176 fstrcpy(groups.domain_name, domain->name);
1178 get_sam_group_entries(&groups);
1180 if (groups.num_sam_entries == 0) {
1181 /* this domain is empty or in an error state */
1185 /* keep track the of the total number of groups seen so
1186 far over all domains */
1187 total_entries += groups.num_sam_entries;
1189 /* Allocate some memory for extra data. Note that we limit
1190 account names to sizeof(fstring) = 128 characters. */
1191 extra_data = (char *)SMB_REALLOC(
1192 extra_data, sizeof(fstring) * total_entries);
1195 DEBUG(0,("failed to enlarge buffer!\n"));
1196 request_error(state);
1200 /* Pack group list into extra data fields */
1201 for (i = 0; i < groups.num_sam_entries; i++) {
1202 char *group_name = ((struct acct_info *)
1203 groups.sam_entries)[i].acct_name;
1206 fill_domain_username(name, domain->name, group_name, True);
1207 /* Append to extra data */
1208 memcpy(&extra_data[extra_data_len], name,
1210 extra_data_len += strlen(name);
1211 extra_data[extra_data_len++] = ',';
1214 SAFE_FREE(groups.sam_entries);
1217 /* Assign extra_data fields in response structure */
1219 extra_data[extra_data_len - 1] = '\0';
1220 state->response.extra_data.data = extra_data;
1221 state->response.length += extra_data_len;
1224 /* No domains may have responded but that's still OK so don't
1230 /* Get user supplementary groups. This is much quicker than trying to
1231 invert the groups database. We merge the groups from the gids and
1232 other_sids info3 fields as trusted domain, universal group
1233 memberships, and nested groups (win2k native mode only) are not
1234 returned by the getgroups RPC call but are present in the info3. */
1236 struct getgroups_state {
1237 struct winbindd_cli_state *state;
1238 struct winbindd_domain *domain;
1243 const DOM_SID *token_sids;
1244 size_t i, num_token_sids;
1247 size_t num_token_gids;
1250 static void getgroups_usersid_recv(void *private_data, BOOL success,
1251 const DOM_SID *sid, enum lsa_SidType type);
1252 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1253 DOM_SID *token_sids, size_t num_token_sids);
1254 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
1256 void winbindd_getgroups(struct winbindd_cli_state *state)
1258 struct getgroups_state *s;
1260 /* Ensure null termination */
1261 state->request.data.username
1262 [sizeof(state->request.data.username)-1]='\0';
1264 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1265 state->request.data.username));
1267 /* Parse domain and username */
1269 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1271 DEBUG(0, ("talloc failed\n"));
1272 request_error(state);
1278 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
1280 if (!parse_domain_user_talloc(state->mem_ctx,
1281 state->request.data.username,
1282 &s->domname, &s->username)) {
1283 DEBUG(5, ("Could not parse domain user: %s\n",
1284 state->request.data.username));
1286 /* error out if we do not have nested group support */
1288 if ( !lp_winbind_nested_groups() ) {
1289 request_error(state);
1293 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1294 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1297 /* Get info for the domain */
1299 s->domain = find_domain_from_name_noinit(s->domname);
1301 if (s->domain == NULL) {
1302 DEBUG(7, ("could not find domain entry for domain %s\n",
1304 request_error(state);
1308 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1309 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1310 "getgroups() for %s\\%s.\n", s->domname,
1312 request_error(state);
1316 /* Get rid and name type from name. The following costs 1 packet */
1318 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1319 getgroups_usersid_recv, s);
1322 static void getgroups_usersid_recv(void *private_data, BOOL success,
1323 const DOM_SID *sid, enum lsa_SidType type)
1325 struct getgroups_state *s =
1326 (struct getgroups_state *)private_data;
1329 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1330 request_error(s->state);
1334 sid_copy(&s->user_sid, sid);
1336 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1337 getgroups_tokensids_recv, s);
1340 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1341 DOM_SID *token_sids, size_t num_token_sids)
1343 struct getgroups_state *s =
1344 (struct getgroups_state *)private_data;
1346 /* We need at least the user sid and the primary group in the token,
1347 * otherwise it's an error */
1349 if ((!success) || (num_token_sids < 2)) {
1350 request_error(s->state);
1354 s->token_sids = token_sids;
1355 s->num_token_sids = num_token_sids;
1358 s->token_gids = NULL;
1359 s->num_token_gids = 0;
1361 getgroups_sid2gid_recv(s, False, 0);
1364 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1366 struct getgroups_state *s =
1367 (struct getgroups_state *)private_data;
1370 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1372 &s->num_token_gids)) {
1377 if (s->i < s->num_token_sids) {
1378 const DOM_SID *sid = &s->token_sids[s->i];
1381 if (sid_equal(sid, &s->user_sid)) {
1382 getgroups_sid2gid_recv(s, False, 0);
1386 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1387 getgroups_sid2gid_recv, s);
1391 s->state->response.data.num_entries = s->num_token_gids;
1392 /* s->token_gids are talloced */
1393 s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
1394 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1395 request_ok(s->state);
1398 /* Get user supplementary sids. This is equivalent to the
1399 winbindd_getgroups() function but it involves a SID->SIDs mapping
1400 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1401 idmap. This call is designed to be used with applications that need
1402 to do ACL evaluation themselves. Note that the cached info3 data is
1405 this function assumes that the SID that comes in is a user SID. If
1406 you pass in another type of SID then you may get unpredictable
1410 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1413 void winbindd_getusersids(struct winbindd_cli_state *state)
1417 /* Ensure null termination */
1418 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1420 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1421 if (user_sid == NULL) {
1422 DEBUG(1, ("talloc failed\n"));
1423 request_error(state);
1427 if (!string_to_sid(user_sid, state->request.data.sid)) {
1428 DEBUG(1, ("Could not get convert sid %s from string\n",
1429 state->request.data.sid));
1430 request_error(state);
1434 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1438 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1441 struct winbindd_cli_state *state =
1442 (struct winbindd_cli_state *)private_data;
1444 unsigned ofs, ret_size = 0;
1448 request_error(state);
1452 /* work out the response size */
1453 for (i = 0; i < num_sids; i++) {
1454 const char *s = sid_string_static(&sids[i]);
1455 ret_size += strlen(s) + 1;
1458 /* build the reply */
1459 ret = (char *)SMB_MALLOC(ret_size);
1461 DEBUG(0, ("malloc failed\n"));
1462 request_error(state);
1466 for (i = 0; i < num_sids; i++) {
1467 const char *s = sid_string_static(&sids[i]);
1468 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1469 ofs += strlen(ret+ofs) + 1;
1472 /* Send data back to client */
1473 state->response.data.num_entries = num_sids;
1474 state->response.extra_data.data = ret;
1475 state->response.length += ret_size;
1479 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1482 struct winbindd_domain *domain;
1484 /* Ensure null termination */
1485 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1487 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1488 DEBUG(1, ("Could not get convert sid %s from string\n",
1489 state->request.data.sid));
1490 request_error(state);
1494 /* Get info for the domain */
1495 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1496 DEBUG(0,("could not find domain entry for sid %s\n",
1497 sid_string_static(&user_sid)));
1498 request_error(state);
1502 sendto_domain(state, domain);
1505 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1506 struct winbindd_cli_state *state)
1516 /* Ensure null termination */
1517 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1519 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1520 DEBUG(1, ("Could not get convert sid %s from string\n",
1521 state->request.data.sid));
1522 return WINBINDD_ERROR;
1525 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1526 &user_sid, &num_groups,
1528 if (!NT_STATUS_IS_OK(status))
1529 return WINBINDD_ERROR;
1531 if (num_groups == 0) {
1532 state->response.data.num_entries = 0;
1533 state->response.extra_data.data = NULL;
1537 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1538 DEBUG(0, ("talloc failed\n"));
1539 return WINBINDD_ERROR;
1542 state->response.extra_data.data = SMB_STRDUP(sidstring);
1543 if (!state->response.extra_data.data) {
1544 return WINBINDD_ERROR;
1546 state->response.length += len+1;
1547 state->response.data.num_entries = num_groups;