2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
8 Copyright (C) Gerald (Jerry) Carter 2003.
9 Copyright (C) Volker Lendecke 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 extern BOOL opt_nocache;
32 #define DBGC_CLASS DBGC_WINBIND
34 /***************************************************************
35 Empty static struct for negative caching.
36 ****************************************************************/
38 /* Fill a grent structure from various other information */
40 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
41 const char *gr_name, gid_t unix_gid)
43 fstring full_group_name;
45 fill_domain_username( full_group_name, dom_name, gr_name, True );
47 gr->gr_gid = unix_gid;
49 /* Group name and password */
51 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
52 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
57 /* Fill in the group membership field of a NT group given by group_sid */
59 static BOOL fill_grent_mem(struct winbindd_domain *domain,
60 struct winbindd_cli_state *state,
62 enum lsa_SidType group_name_type,
63 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
65 DOM_SID *sid_mem = NULL;
67 uint32 *name_types = NULL;
68 unsigned int buf_len = 0, buf_ndx = 0, i;
69 char **names = NULL, *buf = NULL;
76 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
79 /* Initialise group membership information */
81 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
85 /* HACK ALERT!! This whole routine does not cope with group members
86 * from more than one domain, ie aliases. Thus we have to work it out
87 * ourselves in a special routine. */
90 return fill_passdb_alias_grmem(domain, group_sid,
94 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
95 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
97 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
98 sid_to_string(sid_string, group_sid), domain->name,
103 /* OPTIMIZATION / HACK. */
104 /* If "enum users" is set to false, and the group being looked
105 up is the Domain Users SID: S-1-5-domain-513, then for the
106 list of members check if the querying user is in that group,
107 and if so only return that user as the gr_mem array.
108 We can change this to a different parameter than "enum users"
109 if neccessaey, or parameterize the group list we do this for. */
111 sid_peek_rid( group_sid, &group_rid );
112 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
113 DOM_SID querying_user_sid;
114 DOM_SID *pquerying_user_sid = NULL;
115 uint32 num_groups = 0;
116 DOM_SID *user_sids = NULL;
117 BOOL u_in_group = False;
119 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
120 sid_to_string(sid_string, group_sid), domain->name ));
123 uid_t ret_uid = (uid_t)-1;
124 if (sys_getpeereid(state->sock, &ret_uid)==0) {
125 /* We know who's asking - look up their SID if
126 it's one we've mapped before. */
127 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
128 if (NT_STATUS_IS_OK(status)) {
129 pquerying_user_sid = &querying_user_sid;
130 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
131 (unsigned int)ret_uid,
132 sid_to_string(sid_string, pquerying_user_sid) ));
137 /* Only look up if it was a winbindd user in this domain. */
138 if (pquerying_user_sid &&
139 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
141 DEBUG(10,("fill_grent_mem: querying user = %s\n",
142 sid_to_string(sid_string, pquerying_user_sid) ));
144 status = domain->methods->lookup_usergroups(domain,
149 if (!NT_STATUS_IS_OK(status)) {
150 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
151 "for sid %s in domain %s (error: %s)\n",
152 sid_to_string(sid_string, pquerying_user_sid),
158 for (i = 0; i < num_groups; i++) {
159 if (sid_equal(group_sid, &user_sids[i])) {
160 /* User is in Domain Users, add their name
161 as the only group member. */
170 char *domainname = NULL;
171 char *username = NULL;
173 enum lsa_SidType type;
175 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
176 sid_to_string(sid_string, pquerying_user_sid), domain->name ));
178 status = domain->methods->sid_to_name(domain, mem_ctx,
183 if (!NT_STATUS_IS_OK(status)) {
184 DEBUG(1, ("could not lookup username for user "
185 "sid %s in domain %s (error: %s)\n",
186 sid_to_string(sid_string, pquerying_user_sid),
191 fill_domain_username(name, domain->name, username, True);
194 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
195 DEBUG(1, ("out of memory\n"));
198 memcpy(buf, name, buf_len);
200 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
201 name, domain->name ));
205 *gr_mem_len = buf_len;
208 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
209 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
214 /* Lookup group members */
215 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
216 &sid_mem, &names, &name_types);
217 if (!NT_STATUS_IS_OK(status)) {
218 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
219 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
223 DEBUG(10, ("looked up %d names\n", num_names));
225 if (DEBUGLEVEL >= 10) {
226 for (i = 0; i < num_names; i++)
227 DEBUG(10, ("\t%20s %s %d\n", names[i],
228 sid_string_static(&sid_mem[i]),
232 /* Add members to list */
236 for (i = 0; i < num_names; i++) {
243 DEBUG(10, ("processing name %s\n", the_name));
245 /* FIXME: need to cope with groups within groups. These
246 occur in Universal groups on a Windows 2000 native mode
249 /* make sure to allow machine accounts */
251 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
252 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
256 /* Append domain name */
258 fill_domain_username(name, domain->name, the_name, True);
262 /* Add to list or calculate buffer length */
265 buf_len += len + 1; /* List is comma separated */
267 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
269 DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
270 safe_strcpy(&buf[buf_ndx], name, len);
277 /* Allocate buffer */
279 if (!buf && buf_len != 0) {
280 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
281 DEBUG(1, ("out of memory\n"));
285 memset(buf, 0, buf_len);
289 if (buf && buf_ndx > 0) {
290 buf[buf_ndx - 1] = '\0';
294 *gr_mem_len = buf_len;
296 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
297 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
302 talloc_destroy(mem_ctx);
304 DEBUG(10, ("fill_grent_mem returning %d\n", result));
309 /* Return a group structure from a group name */
311 void winbindd_getgrnam(struct winbindd_cli_state *state)
313 DOM_SID group_sid, tmp_sid;
315 struct winbindd_domain *domain;
316 enum lsa_SidType name_type;
317 fstring name_domain, name_group;
325 /* Ensure null termination */
326 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
328 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
329 state->request.data.groupname));
331 /* Parse domain and groupname */
333 memset(name_group, 0, sizeof(fstring));
335 tmp = state->request.data.groupname;
337 parse_domain_user(tmp, name_domain, name_group);
339 /* if no domain or our local domain and no local tdb group, default to
340 * our local domain for aliases */
342 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
343 fstrcpy(name_domain, get_global_sam_name());
346 /* Get info for the domain */
348 if ((domain = find_domain_from_name(name_domain)) == NULL) {
349 DEBUG(3, ("could not get domain sid for domain %s\n",
351 request_error(state);
354 /* should we deal with users for our domain? */
356 if ( lp_winbind_trusted_domains_only() && domain->primary) {
357 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
358 "getgrnam() for %s\\%s.\n", name_domain, name_group));
359 request_error(state);
363 /* Get rid and name type from name */
365 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
366 name_group, &group_sid, &name_type)) {
367 DEBUG(1, ("group %s in domain %s does not exist\n",
368 name_group, name_domain));
369 request_error(state);
373 if ( !((name_type==SID_NAME_DOM_GRP) ||
374 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
375 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
376 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
378 DEBUG(1, ("name '%s' is not a local, domain or builtin "
379 "group: %d\n", name_group, name_type));
380 request_error(state);
384 /* Make sure that the group SID is within the domain of the
387 sid_copy( &tmp_sid, &group_sid );
388 sid_split_rid( &tmp_sid, &grp_rid );
389 if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
390 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
391 state->request.data.groupname, sid_string_static(&group_sid)));
392 request_error(state);
398 /* Try to get the GID */
400 status = idmap_sid_to_gid(&group_sid, &gid);
402 if (NT_STATUS_IS_OK(status)) {
406 /* Maybe it's one of our aliases in passdb */
408 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
409 ((name_type == SID_NAME_ALIAS) ||
410 (name_type == SID_NAME_WKN_GRP))) {
415 DEBUG(1, ("error converting unix gid to sid\n"));
416 request_error(state);
421 if (!fill_grent(&state->response.data.gr, name_domain,
423 !fill_grent_mem(domain, state, &group_sid, name_type,
425 &gr_mem, &gr_mem_len)) {
426 request_error(state);
430 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
432 /* Group membership lives at start of extra data */
434 state->response.data.gr.gr_mem_ofs = 0;
436 state->response.length += gr_mem_len;
437 state->response.extra_data.data = gr_mem;
441 static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
443 struct winbindd_domain *domain;
444 enum lsa_SidType name_type;
445 char *dom_name = NULL;
446 char *group_name = NULL;
451 /* Get name from sid */
453 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, &dom_name,
454 &group_name, &name_type)) {
455 DEBUG(1, ("could not lookup sid\n"));
456 request_error(state);
457 TALLOC_FREE(group_name);
458 TALLOC_FREE(dom_name);
462 /* Fill in group structure */
464 domain = find_domain_from_sid_noinit(&group_sid);
467 DEBUG(1,("Can't find domain from sid\n"));
468 request_error(state);
469 TALLOC_FREE(group_name);
470 TALLOC_FREE(dom_name);
474 if ( !((name_type==SID_NAME_DOM_GRP) ||
475 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
476 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
478 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
479 group_name, name_type));
480 request_error(state);
481 TALLOC_FREE(group_name);
482 TALLOC_FREE(dom_name);
486 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
487 state->request.data.gid) ||
488 !fill_grent_mem(domain, state, &group_sid, name_type,
490 &gr_mem, &gr_mem_len)) {
491 request_error(state);
492 TALLOC_FREE(group_name);
493 TALLOC_FREE(dom_name);
497 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
499 /* Group membership lives at start of extra data */
501 state->response.data.gr.gr_mem_ofs = 0;
503 state->response.length += gr_mem_len;
504 state->response.extra_data.data = gr_mem;
506 TALLOC_FREE(group_name);
507 TALLOC_FREE(dom_name);
512 static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
514 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
515 enum lsa_SidType name_type;
519 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
520 (unsigned long)(state->request.data.gid), sid));
522 string_to_sid(&group_sid, sid);
523 getgrgid_got_sid(state, group_sid);
527 /* Ok, this might be "ours", i.e. an alias */
528 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
529 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
530 (name_type == SID_NAME_ALIAS)) {
531 /* Hey, got an alias */
532 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
533 (unsigned long)(state->request.data.gid), sid));
534 getgrgid_got_sid(state, group_sid);
538 DEBUG(1, ("could not convert gid %lu to sid\n",
539 (unsigned long)state->request.data.gid));
540 request_error(state);
543 /* Return a group structure from a gid number */
544 void winbindd_getgrgid(struct winbindd_cli_state *state)
546 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
547 (unsigned long)state->request.data.gid));
549 /* always use the async interface */
550 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
554 * set/get/endgrent functions
557 /* "Rewind" file pointer for group database enumeration */
559 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
561 struct winbindd_domain *domain;
563 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
565 /* Check user has enabled this */
567 if (!lp_winbind_enum_groups()) {
571 /* Free old static data if it exists */
573 if (state->getgrent_state != NULL) {
574 free_getent_state(state->getgrent_state);
575 state->getgrent_state = NULL;
578 /* Create sam pipes for each domain we know about */
580 for (domain = domain_list(); domain != NULL; domain = domain->next) {
581 struct getent_state *domain_state;
583 /* Create a state record for this domain */
585 /* don't add our domaina if we are a PDC or if we
586 are a member of a Samba domain */
588 if ( lp_winbind_trusted_domains_only() && domain->primary )
594 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
595 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
599 ZERO_STRUCTP(domain_state);
601 fstrcpy(domain_state->domain_name, domain->name);
603 /* Add to list of open domains */
605 DLIST_ADD(state->getgrent_state, domain_state);
608 state->getgrent_initialized = True;
612 void winbindd_setgrent(struct winbindd_cli_state *state)
614 if (winbindd_setgrent_internal(state)) {
617 request_error(state);
621 /* Close file pointer to ntdom group database */
623 void winbindd_endgrent(struct winbindd_cli_state *state)
625 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
627 free_getent_state(state->getgrent_state);
628 state->getgrent_initialized = False;
629 state->getgrent_state = NULL;
633 /* Get the list of domain groups and domain aliases for a domain. We fill in
634 the sam_entries and num_sam_entries fields with domain group information.
635 The dispinfo_ndx field is incremented to the index of the next group to
636 fetch. Return True if some groups were returned, False otherwise. */
638 static BOOL get_sam_group_entries(struct getent_state *ent)
642 struct acct_info *name_list = NULL;
645 struct acct_info *sam_grp_entries = NULL;
646 struct winbindd_domain *domain;
648 if (ent->got_sam_entries)
651 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
652 ent->domain_name))) {
653 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
657 /* Free any existing group info */
659 SAFE_FREE(ent->sam_entries);
660 ent->num_sam_entries = 0;
661 ent->got_sam_entries = True;
663 /* Enumerate domain groups */
667 if (!(domain = find_domain_from_name(ent->domain_name))) {
668 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
672 /* always get the domain global groups */
674 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
676 if (!NT_STATUS_IS_OK(status)) {
677 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
682 /* Copy entries into return buffer */
685 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
686 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
691 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
694 ent->num_sam_entries = num_entries;
696 /* get the domain local groups if we are a member of a native win2k domain
697 and are not using LDAP to get the groups */
699 if ( ( lp_security() != SEC_ADS && domain->native_mode
700 && domain->primary) || domain->internal )
702 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
703 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
705 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
707 if ( !NT_STATUS_IS_OK(status) ) {
708 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
712 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
714 /* Copy entries into return buffer */
717 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
719 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
725 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
726 num_entries * sizeof(struct acct_info) );
729 ent->num_sam_entries += num_entries;
733 /* Fill in remaining fields */
735 ent->sam_entries = name_list;
736 ent->sam_entry_index = 0;
738 result = (ent->num_sam_entries > 0);
741 talloc_destroy(mem_ctx);
746 /* Fetch next group entry from ntdom database */
748 #define MAX_GETGRENT_GROUPS 500
750 void winbindd_getgrent(struct winbindd_cli_state *state)
752 struct getent_state *ent;
753 struct winbindd_gr *group_list = NULL;
754 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
755 char *gr_mem_list = NULL;
757 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
759 /* Check user has enabled this */
761 if (!lp_winbind_enum_groups()) {
762 request_error(state);
766 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
768 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
769 request_error(state);
773 memset(state->response.extra_data.data, '\0',
774 num_groups * sizeof(struct winbindd_gr) );
776 state->response.data.num_entries = 0;
778 group_list = (struct winbindd_gr *)state->response.extra_data.data;
780 if (!state->getgrent_initialized)
781 winbindd_setgrent_internal(state);
783 if (!(ent = state->getgrent_state)) {
784 request_error(state);
788 /* Start sending back groups */
790 for (i = 0; i < num_groups; i++) {
791 struct acct_info *name_list = NULL;
792 fstring domain_group_name;
798 struct winbindd_domain *domain;
800 /* Do we need to fetch another chunk of groups? */
804 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
805 ent->sam_entry_index, ent->num_sam_entries));
807 if (ent->num_sam_entries == ent->sam_entry_index) {
809 while(ent && !get_sam_group_entries(ent)) {
810 struct getent_state *next_ent;
812 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
814 /* Free state information for this domain */
816 SAFE_FREE(ent->sam_entries);
818 next_ent = ent->next;
819 DLIST_REMOVE(state->getgrent_state, ent);
825 /* No more domains */
831 name_list = (struct acct_info *)ent->sam_entries;
834 find_domain_from_name(ent->domain_name))) {
835 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
840 /* Lookup group info */
842 sid_copy(&group_sid, &domain->sid);
843 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
845 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
847 enum lsa_SidType type;
849 DEBUG(10, ("SID %s not in idmap\n",
850 sid_string_static(&group_sid)));
852 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
853 DEBUG(1, ("could not look up gid for group "
855 name_list[ent->sam_entry_index].acct_name));
856 ent->sam_entry_index++;
860 if ((type != SID_NAME_DOM_GRP) &&
861 (type != SID_NAME_ALIAS) &&
862 (type != SID_NAME_WKN_GRP)) {
863 DEBUG(1, ("Group %s is a %s, not a group\n",
864 sid_type_lookup(type),
865 name_list[ent->sam_entry_index].acct_name));
866 ent->sam_entry_index++;
872 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
873 (unsigned long)name_list[ent->sam_entry_index].rid));
875 /* Fill in group entry */
877 fill_domain_username(domain_group_name, ent->domain_name,
878 name_list[ent->sam_entry_index].acct_name, True);
880 result = fill_grent(&group_list[group_list_ndx],
882 name_list[ent->sam_entry_index].acct_name,
885 /* Fill in group membership entry */
888 size_t num_gr_mem = 0;
890 group_list[group_list_ndx].num_gr_mem = 0;
894 /* Get group membership */
895 if (state->request.cmd == WINBINDD_GETGRLST) {
898 sid_copy(&member_sid, &domain->sid);
899 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
900 result = fill_grent_mem(
906 &gr_mem, &gr_mem_len);
908 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
913 /* Append to group membership list */
914 gr_mem_list = (char *)SMB_REALLOC(
915 gr_mem_list, gr_mem_list_len + gr_mem_len);
917 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
918 DEBUG(0, ("out of memory\n"));
923 DEBUG(10, ("list_len = %d, mem_len = %u\n",
924 gr_mem_list_len, (unsigned int)gr_mem_len));
926 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
931 group_list[group_list_ndx].gr_mem_ofs =
934 gr_mem_list_len += gr_mem_len;
937 ent->sam_entry_index++;
939 /* Add group to return list */
943 DEBUG(10, ("adding group num_entries = %d\n",
944 state->response.data.num_entries));
947 state->response.data.num_entries++;
949 state->response.length +=
950 sizeof(struct winbindd_gr);
953 DEBUG(0, ("could not lookup domain group %s\n",
958 /* Copy the list of group memberships to the end of the extra data */
960 if (group_list_ndx == 0)
963 state->response.extra_data.data = SMB_REALLOC(
964 state->response.extra_data.data,
965 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
967 if (!state->response.extra_data.data) {
968 DEBUG(0, ("out of memory\n"));
970 SAFE_FREE(gr_mem_list);
971 request_error(state);
975 memcpy(&((char *)state->response.extra_data.data)
976 [group_list_ndx * sizeof(struct winbindd_gr)],
977 gr_mem_list, gr_mem_list_len);
979 state->response.length += gr_mem_list_len;
981 DEBUG(10, ("returning %d groups, length = %d\n",
982 group_list_ndx, gr_mem_list_len));
988 SAFE_FREE(gr_mem_list);
990 if (group_list_ndx > 0)
993 request_error(state);
996 /* List domain groups without mapping to unix ids */
998 void winbindd_list_groups(struct winbindd_cli_state *state)
1000 uint32 total_entries = 0;
1001 struct winbindd_domain *domain;
1002 const char *which_domain;
1003 char *extra_data = NULL;
1004 unsigned int extra_data_len = 0, i;
1006 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1008 /* Ensure null termination */
1009 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1010 which_domain = state->request.domain_name;
1012 /* Enumerate over trusted domains */
1014 for (domain = domain_list(); domain; domain = domain->next) {
1015 struct getent_state groups;
1017 /* if we have a domain name restricting the request and this
1018 one in the list doesn't match, then just bypass the remainder
1021 if ( *which_domain && !strequal(which_domain, domain->name) )
1024 ZERO_STRUCT(groups);
1026 /* Get list of sam groups */
1028 fstrcpy(groups.domain_name, domain->name);
1030 get_sam_group_entries(&groups);
1032 if (groups.num_sam_entries == 0) {
1033 /* this domain is empty or in an error state */
1037 /* keep track the of the total number of groups seen so
1038 far over all domains */
1039 total_entries += groups.num_sam_entries;
1041 /* Allocate some memory for extra data. Note that we limit
1042 account names to sizeof(fstring) = 128 characters. */
1043 extra_data = (char *)SMB_REALLOC(
1044 extra_data, sizeof(fstring) * total_entries);
1047 DEBUG(0,("failed to enlarge buffer!\n"));
1048 request_error(state);
1052 /* Pack group list into extra data fields */
1053 for (i = 0; i < groups.num_sam_entries; i++) {
1054 char *group_name = ((struct acct_info *)
1055 groups.sam_entries)[i].acct_name;
1058 fill_domain_username(name, domain->name, group_name, True);
1059 /* Append to extra data */
1060 memcpy(&extra_data[extra_data_len], name,
1062 extra_data_len += strlen(name);
1063 extra_data[extra_data_len++] = ',';
1066 SAFE_FREE(groups.sam_entries);
1069 /* Assign extra_data fields in response structure */
1071 extra_data[extra_data_len - 1] = '\0';
1072 state->response.extra_data.data = extra_data;
1073 state->response.length += extra_data_len;
1076 /* No domains may have responded but that's still OK so don't
1082 /* Get user supplementary groups. This is much quicker than trying to
1083 invert the groups database. We merge the groups from the gids and
1084 other_sids info3 fields as trusted domain, universal group
1085 memberships, and nested groups (win2k native mode only) are not
1086 returned by the getgroups RPC call but are present in the info3. */
1088 struct getgroups_state {
1089 struct winbindd_cli_state *state;
1090 struct winbindd_domain *domain;
1095 const DOM_SID *token_sids;
1096 size_t i, num_token_sids;
1099 size_t num_token_gids;
1102 static void getgroups_usersid_recv(void *private_data, BOOL success,
1103 const DOM_SID *sid, enum lsa_SidType type);
1104 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1105 DOM_SID *token_sids, size_t num_token_sids);
1106 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
1108 void winbindd_getgroups(struct winbindd_cli_state *state)
1110 struct getgroups_state *s;
1112 /* Ensure null termination */
1113 state->request.data.username
1114 [sizeof(state->request.data.username)-1]='\0';
1116 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1117 state->request.data.username));
1119 /* Parse domain and username */
1121 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1123 DEBUG(0, ("talloc failed\n"));
1124 request_error(state);
1130 if (!parse_domain_user_talloc(state->mem_ctx,
1131 state->request.data.username,
1132 &s->domname, &s->username)) {
1133 DEBUG(5, ("Could not parse domain user: %s\n",
1134 state->request.data.username));
1136 /* error out if we do not have nested group support */
1138 if ( !lp_winbind_nested_groups() ) {
1139 request_error(state);
1143 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1144 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1147 /* Get info for the domain */
1149 s->domain = find_domain_from_name_noinit(s->domname);
1151 if (s->domain == NULL) {
1152 DEBUG(7, ("could not find domain entry for domain %s\n",
1154 request_error(state);
1158 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1159 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
1160 "getgroups() for %s\\%s.\n", s->domname,
1162 request_error(state);
1166 /* Get rid and name type from name. The following costs 1 packet */
1168 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1169 getgroups_usersid_recv, s);
1172 static void getgroups_usersid_recv(void *private_data, BOOL success,
1173 const DOM_SID *sid, enum lsa_SidType type)
1175 struct getgroups_state *s =
1176 (struct getgroups_state *)private_data;
1179 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1180 request_error(s->state);
1184 sid_copy(&s->user_sid, sid);
1186 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1187 getgroups_tokensids_recv, s);
1190 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1191 DOM_SID *token_sids, size_t num_token_sids)
1193 struct getgroups_state *s =
1194 (struct getgroups_state *)private_data;
1196 /* We need at least the user sid and the primary group in the token,
1197 * otherwise it's an error */
1199 if ((!success) || (num_token_sids < 2)) {
1200 request_error(s->state);
1204 s->token_sids = token_sids;
1205 s->num_token_sids = num_token_sids;
1208 s->token_gids = NULL;
1209 s->num_token_gids = 0;
1211 getgroups_sid2gid_recv(s, False, 0);
1214 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1216 struct getgroups_state *s =
1217 (struct getgroups_state *)private_data;
1220 if (!add_gid_to_array_unique(NULL, gid,
1222 &s->num_token_gids)) {
1227 if (s->i < s->num_token_sids) {
1228 const DOM_SID *sid = &s->token_sids[s->i];
1231 if (sid_equal(sid, &s->user_sid)) {
1232 getgroups_sid2gid_recv(s, False, 0);
1236 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1237 getgroups_sid2gid_recv, s);
1241 s->state->response.data.num_entries = s->num_token_gids;
1242 s->state->response.extra_data.data = s->token_gids;
1243 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1244 request_ok(s->state);
1247 /* Get user supplementary sids. This is equivalent to the
1248 winbindd_getgroups() function but it involves a SID->SIDs mapping
1249 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1250 idmap. This call is designed to be used with applications that need
1251 to do ACL evaluation themselves. Note that the cached info3 data is
1254 this function assumes that the SID that comes in is a user SID. If
1255 you pass in another type of SID then you may get unpredictable
1259 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1262 void winbindd_getusersids(struct winbindd_cli_state *state)
1266 /* Ensure null termination */
1267 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1269 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1270 if (user_sid == NULL) {
1271 DEBUG(1, ("talloc failed\n"));
1272 request_error(state);
1276 if (!string_to_sid(user_sid, state->request.data.sid)) {
1277 DEBUG(1, ("Could not get convert sid %s from string\n",
1278 state->request.data.sid));
1279 request_error(state);
1283 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1287 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1290 struct winbindd_cli_state *state =
1291 (struct winbindd_cli_state *)private_data;
1293 unsigned ofs, ret_size = 0;
1297 request_error(state);
1301 /* work out the response size */
1302 for (i = 0; i < num_sids; i++) {
1303 const char *s = sid_string_static(&sids[i]);
1304 ret_size += strlen(s) + 1;
1307 /* build the reply */
1308 ret = (char *)SMB_MALLOC(ret_size);
1310 DEBUG(0, ("malloc failed\n"));
1311 request_error(state);
1315 for (i = 0; i < num_sids; i++) {
1316 const char *s = sid_string_static(&sids[i]);
1317 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1318 ofs += strlen(ret+ofs) + 1;
1321 /* Send data back to client */
1322 state->response.data.num_entries = num_sids;
1323 state->response.extra_data.data = ret;
1324 state->response.length += ret_size;
1328 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1331 struct winbindd_domain *domain;
1333 /* Ensure null termination */
1334 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1336 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1337 DEBUG(1, ("Could not get convert sid %s from string\n",
1338 state->request.data.sid));
1339 request_error(state);
1343 /* Get info for the domain */
1344 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1345 DEBUG(0,("could not find domain entry for sid %s\n",
1346 sid_string_static(&user_sid)));
1347 request_error(state);
1351 sendto_domain(state, domain);
1354 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1355 struct winbindd_cli_state *state)
1365 /* Ensure null termination */
1366 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1368 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1369 DEBUG(1, ("Could not get convert sid %s from string\n",
1370 state->request.data.sid));
1371 return WINBINDD_ERROR;
1374 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1375 &user_sid, &num_groups,
1377 if (!NT_STATUS_IS_OK(status))
1378 return WINBINDD_ERROR;
1380 if (num_groups == 0) {
1381 state->response.data.num_entries = 0;
1382 state->response.extra_data.data = NULL;
1386 if (!print_sidlist(NULL, groups, num_groups, &sidstring, &len)) {
1387 DEBUG(0, ("malloc failed\n"));
1388 return WINBINDD_ERROR;
1391 state->response.extra_data.data = sidstring;
1392 state->response.length += len+1;
1393 state->response.data.num_entries = num_groups;