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 return fill_passdb_alias_grmem(domain, group_sid,
236 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
237 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
239 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
240 sid_to_string(sid_string, group_sid), domain->name,
245 /* OPTIMIZATION / HACK. */
246 /* If "enum users" is set to false, and the group being looked
247 up is the Domain Users SID: S-1-5-domain-513, then for the
248 list of members check if the querying user is in that group,
249 and if so only return that user as the gr_mem array.
250 We can change this to a different parameter than "enum users"
251 if neccessaey, or parameterize the group list we do this for. */
253 sid_peek_rid( group_sid, &group_rid );
254 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
255 DOM_SID querying_user_sid;
256 DOM_SID *pquerying_user_sid = NULL;
257 uint32 num_groups = 0;
258 DOM_SID *user_sids = NULL;
259 BOOL u_in_group = False;
261 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
262 sid_to_string(sid_string, group_sid), domain->name ));
265 uid_t ret_uid = (uid_t)-1;
266 if (sys_getpeereid(state->sock, &ret_uid)==0) {
267 /* We know who's asking - look up their SID if
268 it's one we've mapped before. */
269 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
270 if (NT_STATUS_IS_OK(status)) {
271 pquerying_user_sid = &querying_user_sid;
272 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
273 (unsigned int)ret_uid,
274 sid_to_string(sid_string, pquerying_user_sid) ));
279 /* Only look up if it was a winbindd user in this domain. */
280 if (pquerying_user_sid &&
281 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
283 DEBUG(10,("fill_grent_mem: querying user = %s\n",
284 sid_to_string(sid_string, pquerying_user_sid) ));
286 status = domain->methods->lookup_usergroups(domain,
291 if (!NT_STATUS_IS_OK(status)) {
292 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
293 "for sid %s in domain %s (error: %s)\n",
294 sid_to_string(sid_string, pquerying_user_sid),
300 for (i = 0; i < num_groups; i++) {
301 if (sid_equal(group_sid, &user_sids[i])) {
302 /* User is in Domain Users, add their name
303 as the only group member. */
312 char *domainname = NULL;
313 char *username = NULL;
315 enum lsa_SidType type;
317 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
318 sid_to_string(sid_string, pquerying_user_sid), domain->name ));
320 status = domain->methods->sid_to_name(domain, mem_ctx,
325 if (!NT_STATUS_IS_OK(status)) {
326 DEBUG(1, ("could not lookup username for user "
327 "sid %s in domain %s (error: %s)\n",
328 sid_to_string(sid_string, pquerying_user_sid),
333 fill_domain_username(name, domain->name, username, True);
336 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
337 DEBUG(1, ("out of memory\n"));
340 memcpy(buf, name, buf_len);
342 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
343 name, domain->name ));
345 /* user is the only member */
350 *gr_mem_len = buf_len;
352 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
353 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
358 /* Lookup group members */
359 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
360 &sid_mem, &names, &name_types);
361 if (!NT_STATUS_IS_OK(status)) {
362 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
363 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
367 DEBUG(10, ("looked up %d names\n", num_names));
369 if (DEBUGLEVEL >= 10) {
370 for (i = 0; i < num_names; i++)
371 DEBUG(10, ("\t%20s %s %d\n", names[i],
372 sid_string_static(&sid_mem[i]),
376 /* Add members to list */
380 for (i = 0; i < num_names; i++) {
387 DEBUG(10, ("processing name %s\n", the_name));
389 /* FIXME: need to cope with groups within groups. These
390 occur in Universal groups on a Windows 2000 native mode
393 /* make sure to allow machine accounts */
395 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
396 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
400 /* Append domain name */
402 fill_domain_username(name, domain->name, the_name, True);
406 /* Add to list or calculate buffer length */
409 buf_len += len + 1; /* List is comma separated */
411 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
413 DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
414 safe_strcpy(&buf[buf_ndx], name, len);
421 /* Allocate buffer */
423 if (!buf && buf_len != 0) {
424 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
425 DEBUG(1, ("out of memory\n"));
429 memset(buf, 0, buf_len);
433 if (buf && buf_ndx > 0) {
434 buf[buf_ndx - 1] = '\0';
438 *gr_mem_len = buf_len;
440 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
441 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
446 talloc_destroy(mem_ctx);
448 DEBUG(10, ("fill_grent_mem returning %d\n", result));
453 /* Return a group structure from a group name */
455 void winbindd_getgrnam(struct winbindd_cli_state *state)
457 DOM_SID group_sid, tmp_sid;
459 struct winbindd_domain *domain;
460 enum lsa_SidType name_type;
461 fstring name_domain, name_group;
469 /* Ensure null termination */
470 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
472 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
473 state->request.data.groupname));
475 /* Parse domain and groupname */
477 memset(name_group, 0, sizeof(fstring));
479 tmp = state->request.data.groupname;
481 parse_domain_user(tmp, name_domain, name_group);
483 /* if no domain or our local domain and no local tdb group, default to
484 * our local domain for aliases */
486 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
487 fstrcpy(name_domain, get_global_sam_name());
490 /* Get info for the domain */
492 if ((domain = find_domain_from_name(name_domain)) == NULL) {
493 DEBUG(3, ("could not get domain sid for domain %s\n",
495 request_error(state);
498 /* should we deal with users for our domain? */
500 if ( lp_winbind_trusted_domains_only() && domain->primary) {
501 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
502 "getgrnam() for %s\\%s.\n", name_domain, name_group));
503 request_error(state);
507 /* Get rid and name type from name */
509 ws_name_replace( name_group, '_' );
511 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
512 name_group, &group_sid, &name_type)) {
513 DEBUG(1, ("group %s in domain %s does not exist\n",
514 name_group, name_domain));
515 request_error(state);
519 if ( !((name_type==SID_NAME_DOM_GRP) ||
520 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
521 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
522 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
524 DEBUG(1, ("name '%s' is not a local, domain or builtin "
525 "group: %d\n", name_group, name_type));
526 request_error(state);
530 /* Make sure that the group SID is within the domain of the
533 sid_copy( &tmp_sid, &group_sid );
534 sid_split_rid( &tmp_sid, &grp_rid );
535 if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
536 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
537 state->request.data.groupname, sid_string_static(&group_sid)));
538 request_error(state);
544 /* Try to get the GID */
546 status = idmap_sid_to_gid(&group_sid, &gid);
548 if (NT_STATUS_IS_OK(status)) {
552 /* Maybe it's one of our aliases in passdb */
554 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
555 ((name_type == SID_NAME_ALIAS) ||
556 (name_type == SID_NAME_WKN_GRP))) {
561 DEBUG(1, ("error converting unix gid to sid\n"));
562 request_error(state);
567 if (!fill_grent(&state->response.data.gr, name_domain,
569 !fill_grent_mem(domain, state, &group_sid, name_type,
571 &gr_mem, &gr_mem_len)) {
572 request_error(state);
576 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
578 /* Group membership lives at start of extra data */
580 state->response.data.gr.gr_mem_ofs = 0;
582 state->response.length += gr_mem_len;
583 state->response.extra_data.data = gr_mem;
587 static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
589 struct winbindd_domain *domain;
590 enum lsa_SidType name_type;
597 /* Get name from sid */
599 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, &dom_name,
600 &group_name, &name_type)) {
601 DEBUG(1, ("could not lookup sid\n"));
602 request_error(state);
603 TALLOC_FREE(group_name);
604 TALLOC_FREE(dom_name);
608 /* Fill in group structure */
610 domain = find_domain_from_sid_noinit(&group_sid);
613 DEBUG(1,("Can't find domain from sid\n"));
614 request_error(state);
615 TALLOC_FREE(group_name);
616 TALLOC_FREE(dom_name);
620 if ( !((name_type==SID_NAME_DOM_GRP) ||
621 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
622 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
624 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
625 group_name, name_type));
626 request_error(state);
627 TALLOC_FREE(group_name);
628 TALLOC_FREE(dom_name);
632 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
633 state->request.data.gid) ||
634 !fill_grent_mem(domain, state, &group_sid, name_type,
636 &gr_mem, &gr_mem_len)) {
637 request_error(state);
638 TALLOC_FREE(group_name);
639 TALLOC_FREE(dom_name);
643 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
645 /* Group membership lives at start of extra data */
647 state->response.data.gr.gr_mem_ofs = 0;
649 state->response.length += gr_mem_len;
650 state->response.extra_data.data = gr_mem;
652 TALLOC_FREE(group_name);
653 TALLOC_FREE(dom_name);
658 static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
660 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
661 enum lsa_SidType name_type;
665 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
666 (unsigned long)(state->request.data.gid), sid));
668 string_to_sid(&group_sid, sid);
669 getgrgid_got_sid(state, group_sid);
673 /* Ok, this might be "ours", i.e. an alias */
674 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
675 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
676 (name_type == SID_NAME_ALIAS)) {
677 /* Hey, got an alias */
678 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
679 (unsigned long)(state->request.data.gid), sid));
680 getgrgid_got_sid(state, group_sid);
684 DEBUG(1, ("could not convert gid %lu to sid\n",
685 (unsigned long)state->request.data.gid));
686 request_error(state);
689 /* Return a group structure from a gid number */
690 void winbindd_getgrgid(struct winbindd_cli_state *state)
692 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
693 (unsigned long)state->request.data.gid));
695 /* always use the async interface */
696 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
700 * set/get/endgrent functions
703 /* "Rewind" file pointer for group database enumeration */
705 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
707 struct winbindd_domain *domain;
709 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
711 /* Check user has enabled this */
713 if (!lp_winbind_enum_groups()) {
717 /* Free old static data if it exists */
719 if (state->getgrent_state != NULL) {
720 free_getent_state(state->getgrent_state);
721 state->getgrent_state = NULL;
724 /* Create sam pipes for each domain we know about */
726 for (domain = domain_list(); domain != NULL; domain = domain->next) {
727 struct getent_state *domain_state;
729 /* Create a state record for this domain */
731 /* don't add our domaina if we are a PDC or if we
732 are a member of a Samba domain */
734 if ( lp_winbind_trusted_domains_only() && domain->primary )
740 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
741 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
745 ZERO_STRUCTP(domain_state);
747 fstrcpy(domain_state->domain_name, domain->name);
749 /* Add to list of open domains */
751 DLIST_ADD(state->getgrent_state, domain_state);
754 state->getgrent_initialized = True;
758 void winbindd_setgrent(struct winbindd_cli_state *state)
760 if (winbindd_setgrent_internal(state)) {
763 request_error(state);
767 /* Close file pointer to ntdom group database */
769 void winbindd_endgrent(struct winbindd_cli_state *state)
771 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
773 free_getent_state(state->getgrent_state);
774 state->getgrent_initialized = False;
775 state->getgrent_state = NULL;
779 /* Get the list of domain groups and domain aliases for a domain. We fill in
780 the sam_entries and num_sam_entries fields with domain group information.
781 The dispinfo_ndx field is incremented to the index of the next group to
782 fetch. Return True if some groups were returned, False otherwise. */
784 static BOOL get_sam_group_entries(struct getent_state *ent)
788 struct acct_info *name_list = NULL;
791 struct acct_info *sam_grp_entries = NULL;
792 struct winbindd_domain *domain;
794 if (ent->got_sam_entries)
797 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
798 ent->domain_name))) {
799 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
803 /* Free any existing group info */
805 SAFE_FREE(ent->sam_entries);
806 ent->num_sam_entries = 0;
807 ent->got_sam_entries = True;
809 /* Enumerate domain groups */
813 if (!(domain = find_domain_from_name(ent->domain_name))) {
814 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
818 /* always get the domain global groups */
820 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
822 if (!NT_STATUS_IS_OK(status)) {
823 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
828 /* Copy entries into return buffer */
831 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
832 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
837 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
840 ent->num_sam_entries = num_entries;
842 /* get the domain local groups if we are a member of a native win2k domain
843 and are not using LDAP to get the groups */
845 if ( ( lp_security() != SEC_ADS && domain->native_mode
846 && domain->primary) || domain->internal )
848 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
849 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
851 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
853 if ( !NT_STATUS_IS_OK(status) ) {
854 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
858 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
860 /* Copy entries into return buffer */
863 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
865 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
871 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
872 num_entries * sizeof(struct acct_info) );
875 ent->num_sam_entries += num_entries;
879 /* Fill in remaining fields */
881 ent->sam_entries = name_list;
882 ent->sam_entry_index = 0;
884 result = (ent->num_sam_entries > 0);
887 talloc_destroy(mem_ctx);
892 /* Fetch next group entry from ntdom database */
894 #define MAX_GETGRENT_GROUPS 500
896 void winbindd_getgrent(struct winbindd_cli_state *state)
898 struct getent_state *ent;
899 struct winbindd_gr *group_list = NULL;
900 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
901 char *gr_mem_list = NULL;
903 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
905 /* Check user has enabled this */
907 if (!lp_winbind_enum_groups()) {
908 request_error(state);
912 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
914 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
915 request_error(state);
919 memset(state->response.extra_data.data, '\0',
920 num_groups * sizeof(struct winbindd_gr) );
922 state->response.data.num_entries = 0;
924 group_list = (struct winbindd_gr *)state->response.extra_data.data;
926 if (!state->getgrent_initialized)
927 winbindd_setgrent_internal(state);
929 if (!(ent = state->getgrent_state)) {
930 request_error(state);
934 /* Start sending back groups */
936 for (i = 0; i < num_groups; i++) {
937 struct acct_info *name_list = NULL;
938 fstring domain_group_name;
944 struct winbindd_domain *domain;
946 /* Do we need to fetch another chunk of groups? */
950 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
951 ent->sam_entry_index, ent->num_sam_entries));
953 if (ent->num_sam_entries == ent->sam_entry_index) {
955 while(ent && !get_sam_group_entries(ent)) {
956 struct getent_state *next_ent;
958 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
960 /* Free state information for this domain */
962 SAFE_FREE(ent->sam_entries);
964 next_ent = ent->next;
965 DLIST_REMOVE(state->getgrent_state, ent);
971 /* No more domains */
977 name_list = (struct acct_info *)ent->sam_entries;
980 find_domain_from_name(ent->domain_name))) {
981 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
986 /* Lookup group info */
988 sid_copy(&group_sid, &domain->sid);
989 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
991 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
993 enum lsa_SidType type;
995 DEBUG(10, ("SID %s not in idmap\n",
996 sid_string_static(&group_sid)));
998 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
999 DEBUG(1, ("could not look up gid for group "
1001 name_list[ent->sam_entry_index].acct_name));
1002 ent->sam_entry_index++;
1006 if ((type != SID_NAME_DOM_GRP) &&
1007 (type != SID_NAME_ALIAS) &&
1008 (type != SID_NAME_WKN_GRP)) {
1009 DEBUG(1, ("Group %s is a %s, not a group\n",
1010 sid_type_lookup(type),
1011 name_list[ent->sam_entry_index].acct_name));
1012 ent->sam_entry_index++;
1018 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1019 (unsigned long)name_list[ent->sam_entry_index].rid));
1021 /* Fill in group entry */
1023 fill_domain_username(domain_group_name, ent->domain_name,
1024 name_list[ent->sam_entry_index].acct_name, True);
1026 result = fill_grent(&group_list[group_list_ndx],
1028 name_list[ent->sam_entry_index].acct_name,
1031 /* Fill in group membership entry */
1034 size_t num_gr_mem = 0;
1036 group_list[group_list_ndx].num_gr_mem = 0;
1040 /* Get group membership */
1041 if (state->request.cmd == WINBINDD_GETGRLST) {
1044 sid_copy(&member_sid, &domain->sid);
1045 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1046 result = fill_grent_mem(
1052 &gr_mem, &gr_mem_len);
1054 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1059 /* Append to group membership list */
1060 gr_mem_list = (char *)SMB_REALLOC(
1061 gr_mem_list, gr_mem_list_len + gr_mem_len);
1063 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
1064 DEBUG(0, ("out of memory\n"));
1065 gr_mem_list_len = 0;
1069 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1070 gr_mem_list_len, (unsigned int)gr_mem_len));
1072 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1077 group_list[group_list_ndx].gr_mem_ofs =
1080 gr_mem_list_len += gr_mem_len;
1083 ent->sam_entry_index++;
1085 /* Add group to return list */
1089 DEBUG(10, ("adding group num_entries = %d\n",
1090 state->response.data.num_entries));
1093 state->response.data.num_entries++;
1095 state->response.length +=
1096 sizeof(struct winbindd_gr);
1099 DEBUG(0, ("could not lookup domain group %s\n",
1100 domain_group_name));
1104 /* Copy the list of group memberships to the end of the extra data */
1106 if (group_list_ndx == 0)
1109 state->response.extra_data.data = SMB_REALLOC(
1110 state->response.extra_data.data,
1111 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1113 if (!state->response.extra_data.data) {
1114 DEBUG(0, ("out of memory\n"));
1116 SAFE_FREE(gr_mem_list);
1117 request_error(state);
1121 memcpy(&((char *)state->response.extra_data.data)
1122 [group_list_ndx * sizeof(struct winbindd_gr)],
1123 gr_mem_list, gr_mem_list_len);
1125 state->response.length += gr_mem_list_len;
1127 DEBUG(10, ("returning %d groups, length = %d\n",
1128 group_list_ndx, gr_mem_list_len));
1130 /* Out of domains */
1134 SAFE_FREE(gr_mem_list);
1136 if (group_list_ndx > 0)
1139 request_error(state);
1142 /* List domain groups without mapping to unix ids */
1144 void winbindd_list_groups(struct winbindd_cli_state *state)
1146 uint32 total_entries = 0;
1147 struct winbindd_domain *domain;
1148 const char *which_domain;
1149 char *extra_data = NULL;
1150 unsigned int extra_data_len = 0, i;
1152 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1154 /* Ensure null termination */
1155 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1156 which_domain = state->request.domain_name;
1158 /* Enumerate over trusted domains */
1160 for (domain = domain_list(); domain; domain = domain->next) {
1161 struct getent_state groups;
1163 /* if we have a domain name restricting the request and this
1164 one in the list doesn't match, then just bypass the remainder
1167 if ( *which_domain && !strequal(which_domain, domain->name) )
1170 ZERO_STRUCT(groups);
1172 /* Get list of sam groups */
1174 fstrcpy(groups.domain_name, domain->name);
1176 get_sam_group_entries(&groups);
1178 if (groups.num_sam_entries == 0) {
1179 /* this domain is empty or in an error state */
1183 /* keep track the of the total number of groups seen so
1184 far over all domains */
1185 total_entries += groups.num_sam_entries;
1187 /* Allocate some memory for extra data. Note that we limit
1188 account names to sizeof(fstring) = 128 characters. */
1189 extra_data = (char *)SMB_REALLOC(
1190 extra_data, sizeof(fstring) * total_entries);
1193 DEBUG(0,("failed to enlarge buffer!\n"));
1194 request_error(state);
1198 /* Pack group list into extra data fields */
1199 for (i = 0; i < groups.num_sam_entries; i++) {
1200 char *group_name = ((struct acct_info *)
1201 groups.sam_entries)[i].acct_name;
1204 fill_domain_username(name, domain->name, group_name, True);
1205 /* Append to extra data */
1206 memcpy(&extra_data[extra_data_len], name,
1208 extra_data_len += strlen(name);
1209 extra_data[extra_data_len++] = ',';
1212 SAFE_FREE(groups.sam_entries);
1215 /* Assign extra_data fields in response structure */
1217 extra_data[extra_data_len - 1] = '\0';
1218 state->response.extra_data.data = extra_data;
1219 state->response.length += extra_data_len;
1222 /* No domains may have responded but that's still OK so don't
1228 /* Get user supplementary groups. This is much quicker than trying to
1229 invert the groups database. We merge the groups from the gids and
1230 other_sids info3 fields as trusted domain, universal group
1231 memberships, and nested groups (win2k native mode only) are not
1232 returned by the getgroups RPC call but are present in the info3. */
1234 struct getgroups_state {
1235 struct winbindd_cli_state *state;
1236 struct winbindd_domain *domain;
1241 const DOM_SID *token_sids;
1242 size_t i, num_token_sids;
1245 size_t num_token_gids;
1248 static void getgroups_usersid_recv(void *private_data, BOOL success,
1249 const DOM_SID *sid, enum lsa_SidType type);
1250 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1251 DOM_SID *token_sids, size_t num_token_sids);
1252 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
1254 void winbindd_getgroups(struct winbindd_cli_state *state)
1256 struct getgroups_state *s;
1258 /* Ensure null termination */
1259 state->request.data.username
1260 [sizeof(state->request.data.username)-1]='\0';
1262 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1263 state->request.data.username));
1265 /* Parse domain and username */
1267 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1269 DEBUG(0, ("talloc failed\n"));
1270 request_error(state);
1276 if (!parse_domain_user_talloc(state->mem_ctx,
1277 state->request.data.username,
1278 &s->domname, &s->username)) {
1279 DEBUG(5, ("Could not parse domain user: %s\n",
1280 state->request.data.username));
1282 /* error out if we do not have nested group support */
1284 if ( !lp_winbind_nested_groups() ) {
1285 request_error(state);
1289 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1290 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1293 /* Get info for the domain */
1295 s->domain = find_domain_from_name_noinit(s->domname);
1297 if (s->domain == NULL) {
1298 DEBUG(7, ("could not find domain entry for domain %s\n",
1300 request_error(state);
1304 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1305 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1306 "getgroups() for %s\\%s.\n", s->domname,
1308 request_error(state);
1312 /* Get rid and name type from name. The following costs 1 packet */
1314 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1315 getgroups_usersid_recv, s);
1318 static void getgroups_usersid_recv(void *private_data, BOOL success,
1319 const DOM_SID *sid, enum lsa_SidType type)
1321 struct getgroups_state *s =
1322 (struct getgroups_state *)private_data;
1325 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1326 request_error(s->state);
1330 sid_copy(&s->user_sid, sid);
1332 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1333 getgroups_tokensids_recv, s);
1336 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1337 DOM_SID *token_sids, size_t num_token_sids)
1339 struct getgroups_state *s =
1340 (struct getgroups_state *)private_data;
1342 /* We need at least the user sid and the primary group in the token,
1343 * otherwise it's an error */
1345 if ((!success) || (num_token_sids < 2)) {
1346 request_error(s->state);
1350 s->token_sids = token_sids;
1351 s->num_token_sids = num_token_sids;
1354 s->token_gids = NULL;
1355 s->num_token_gids = 0;
1357 getgroups_sid2gid_recv(s, False, 0);
1360 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1362 struct getgroups_state *s =
1363 (struct getgroups_state *)private_data;
1366 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1368 &s->num_token_gids)) {
1373 if (s->i < s->num_token_sids) {
1374 const DOM_SID *sid = &s->token_sids[s->i];
1377 if (sid_equal(sid, &s->user_sid)) {
1378 getgroups_sid2gid_recv(s, False, 0);
1382 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1383 getgroups_sid2gid_recv, s);
1387 s->state->response.data.num_entries = s->num_token_gids;
1388 /* s->token_gids are talloced */
1389 s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
1390 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1391 request_ok(s->state);
1394 /* Get user supplementary sids. This is equivalent to the
1395 winbindd_getgroups() function but it involves a SID->SIDs mapping
1396 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1397 idmap. This call is designed to be used with applications that need
1398 to do ACL evaluation themselves. Note that the cached info3 data is
1401 this function assumes that the SID that comes in is a user SID. If
1402 you pass in another type of SID then you may get unpredictable
1406 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1409 void winbindd_getusersids(struct winbindd_cli_state *state)
1413 /* Ensure null termination */
1414 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1416 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1417 if (user_sid == NULL) {
1418 DEBUG(1, ("talloc failed\n"));
1419 request_error(state);
1423 if (!string_to_sid(user_sid, state->request.data.sid)) {
1424 DEBUG(1, ("Could not get convert sid %s from string\n",
1425 state->request.data.sid));
1426 request_error(state);
1430 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1434 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1437 struct winbindd_cli_state *state =
1438 (struct winbindd_cli_state *)private_data;
1440 unsigned ofs, ret_size = 0;
1444 request_error(state);
1448 /* work out the response size */
1449 for (i = 0; i < num_sids; i++) {
1450 const char *s = sid_string_static(&sids[i]);
1451 ret_size += strlen(s) + 1;
1454 /* build the reply */
1455 ret = (char *)SMB_MALLOC(ret_size);
1457 DEBUG(0, ("malloc failed\n"));
1458 request_error(state);
1462 for (i = 0; i < num_sids; i++) {
1463 const char *s = sid_string_static(&sids[i]);
1464 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1465 ofs += strlen(ret+ofs) + 1;
1468 /* Send data back to client */
1469 state->response.data.num_entries = num_sids;
1470 state->response.extra_data.data = ret;
1471 state->response.length += ret_size;
1475 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1478 struct winbindd_domain *domain;
1480 /* Ensure null termination */
1481 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1483 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1484 DEBUG(1, ("Could not get convert sid %s from string\n",
1485 state->request.data.sid));
1486 request_error(state);
1490 /* Get info for the domain */
1491 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1492 DEBUG(0,("could not find domain entry for sid %s\n",
1493 sid_string_static(&user_sid)));
1494 request_error(state);
1498 sendto_domain(state, domain);
1501 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1502 struct winbindd_cli_state *state)
1512 /* Ensure null termination */
1513 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1515 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1516 DEBUG(1, ("Could not get convert sid %s from string\n",
1517 state->request.data.sid));
1518 return WINBINDD_ERROR;
1521 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1522 &user_sid, &num_groups,
1524 if (!NT_STATUS_IS_OK(status))
1525 return WINBINDD_ERROR;
1527 if (num_groups == 0) {
1528 state->response.data.num_entries = 0;
1529 state->response.extra_data.data = NULL;
1533 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1534 DEBUG(0, ("talloc failed\n"));
1535 return WINBINDD_ERROR;
1538 state->response.extra_data.data = SMB_STRDUP(sidstring);
1539 if (!state->response.extra_data.data) {
1540 return WINBINDD_ERROR;
1542 state->response.length += len+1;
1543 state->response.data.num_entries = num_groups;