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,
61 enum lsa_SidType group_name_type,
62 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
64 DOM_SID *sid_mem = NULL;
66 uint32 *name_types = NULL;
67 unsigned int buf_len, buf_ndx, i;
68 char **names = NULL, *buf;
74 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
77 /* Initialise group membership information */
79 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
83 /* HACK ALERT!! This whole routine does not cope with group members
84 * from more than one domain, ie aliases. Thus we have to work it out
85 * ourselves in a special routine. */
88 return fill_passdb_alias_grmem(domain, group_sid,
92 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
93 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
95 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
96 sid_to_string(sid_string, group_sid), domain->name,
101 /* Lookup group members */
102 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
103 &sid_mem, &names, &name_types);
104 if (!NT_STATUS_IS_OK(status)) {
105 DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n",
106 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
111 DEBUG(10, ("looked up %d names\n", num_names));
113 if (DEBUGLEVEL >= 10) {
114 for (i = 0; i < num_names; i++)
115 DEBUG(10, ("\t%20s %s %d\n", names[i],
116 sid_string_static(&sid_mem[i]),
120 /* Add members to list */
123 buf_len = buf_ndx = 0;
127 for (i = 0; i < num_names; i++) {
134 DEBUG(10, ("processing name %s\n", the_name));
136 /* FIXME: need to cope with groups within groups. These
137 occur in Universal groups on a Windows 2000 native mode
140 /* make sure to allow machine accounts */
142 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
143 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
147 /* Append domain name */
149 fill_domain_username(name, domain->name, the_name, True);
153 /* Add to list or calculate buffer length */
156 buf_len += len + 1; /* List is comma separated */
158 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
160 DEBUG(10, ("appending %s at ndx %d\n", name, len));
161 safe_strcpy(&buf[buf_ndx], name, len);
168 /* Allocate buffer */
170 if (!buf && buf_len != 0) {
171 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
172 DEBUG(1, ("out of memory\n"));
176 memset(buf, 0, buf_len);
180 if (buf && buf_ndx > 0) {
181 buf[buf_ndx - 1] = '\0';
185 *gr_mem_len = buf_len;
187 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
188 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
193 talloc_destroy(mem_ctx);
195 DEBUG(10, ("fill_grent_mem returning %d\n", result));
200 /* Return a group structure from a group name */
202 void winbindd_getgrnam(struct winbindd_cli_state *state)
204 DOM_SID group_sid, tmp_sid;
206 struct winbindd_domain *domain;
207 enum lsa_SidType name_type;
208 fstring name_domain, name_group;
216 /* Ensure null termination */
217 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
219 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
220 state->request.data.groupname));
222 /* Parse domain and groupname */
224 memset(name_group, 0, sizeof(fstring));
226 tmp = state->request.data.groupname;
228 parse_domain_user(tmp, name_domain, name_group);
230 /* if no domain or our local domain and no local tdb group, default to
231 * our local domain for aliases */
233 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
234 fstrcpy(name_domain, get_global_sam_name());
237 /* Get info for the domain */
239 if ((domain = find_domain_from_name(name_domain)) == NULL) {
240 DEBUG(3, ("could not get domain sid for domain %s\n",
242 request_error(state);
245 /* should we deal with users for our domain? */
247 if ( lp_winbind_trusted_domains_only() && domain->primary) {
248 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
249 "getgrnam() for %s\\%s.\n", name_domain, name_group));
250 request_error(state);
254 /* Get rid and name type from name */
256 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
257 name_group, &group_sid, &name_type)) {
258 DEBUG(1, ("group %s in domain %s does not exist\n",
259 name_group, name_domain));
260 request_error(state);
264 if ( !((name_type==SID_NAME_DOM_GRP) ||
265 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
266 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
267 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
269 DEBUG(1, ("name '%s' is not a local, domain or builtin "
270 "group: %d\n", name_group, name_type));
271 request_error(state);
275 /* Make sure that the group SID is within the domain of the
278 sid_copy( &tmp_sid, &group_sid );
279 sid_split_rid( &tmp_sid, &grp_rid );
280 if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
281 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
282 state->request.data.groupname, sid_string_static(&group_sid)));
283 request_error(state);
289 /* Try to get the GID */
291 status = idmap_sid_to_gid(&group_sid, &gid, 0);
293 if (NT_STATUS_IS_OK(status)) {
297 /* Maybe it's one of our aliases in passdb */
299 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
300 ((name_type == SID_NAME_ALIAS) ||
301 (name_type == SID_NAME_WKN_GRP))) {
306 DEBUG(1, ("error converting unix gid to sid\n"));
307 request_error(state);
312 if (!fill_grent(&state->response.data.gr, name_domain,
314 !fill_grent_mem(domain, &group_sid, name_type,
316 &gr_mem, &gr_mem_len)) {
317 request_error(state);
321 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
323 /* Group membership lives at start of extra data */
325 state->response.data.gr.gr_mem_ofs = 0;
327 state->response.length += gr_mem_len;
328 state->response.extra_data.data = gr_mem;
332 static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
334 struct winbindd_domain *domain;
335 enum lsa_SidType name_type;
342 /* Get name from sid */
344 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
345 group_name, &name_type)) {
346 DEBUG(1, ("could not lookup sid\n"));
347 request_error(state);
351 /* Fill in group structure */
353 domain = find_domain_from_sid_noinit(&group_sid);
356 DEBUG(1,("Can't find domain from sid\n"));
357 request_error(state);
361 if ( !((name_type==SID_NAME_DOM_GRP) ||
362 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
363 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
365 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
366 group_name, name_type));
367 request_error(state);
371 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
372 state->request.data.gid) ||
373 !fill_grent_mem(domain, &group_sid, name_type,
375 &gr_mem, &gr_mem_len)) {
376 request_error(state);
380 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
382 /* Group membership lives at start of extra data */
384 state->response.data.gr.gr_mem_ofs = 0;
386 state->response.length += gr_mem_len;
387 state->response.extra_data.data = gr_mem;
392 static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
394 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
395 enum lsa_SidType name_type;
399 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
400 (unsigned long)(state->request.data.gid), sid));
402 string_to_sid(&group_sid, sid);
403 getgrgid_got_sid(state, group_sid);
407 /* Ok, this might be "ours", i.e. an alias */
408 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
409 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
410 (name_type == SID_NAME_ALIAS)) {
411 /* Hey, got an alias */
412 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
413 (unsigned long)(state->request.data.gid), sid));
414 getgrgid_got_sid(state, group_sid);
418 DEBUG(1, ("could not convert gid %lu to sid\n",
419 (unsigned long)state->request.data.gid));
420 request_error(state);
423 /* Return a group structure from a gid number */
424 void winbindd_getgrgid(struct winbindd_cli_state *state)
429 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
430 (unsigned long)state->request.data.gid));
432 /* Bug out if the gid isn't in the winbind range */
434 if ((state->request.data.gid < server_state.gid_low) ||
435 (state->request.data.gid > server_state.gid_high)) {
436 request_error(state);
440 /* Get sid from gid */
442 status = idmap_gid_to_sid(&group_sid, state->request.data.gid, IDMAP_FLAG_NONE);
443 if (NT_STATUS_IS_OK(status)) {
444 /* This is a remote one */
445 getgrgid_got_sid(state, group_sid);
449 DEBUG(10,("winbindd_getgrgid: gid %lu not found in cache, try with the async interface\n",
450 (unsigned long)state->request.data.gid));
452 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
456 * set/get/endgrent functions
459 /* "Rewind" file pointer for group database enumeration */
461 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
463 struct winbindd_domain *domain;
465 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
467 /* Check user has enabled this */
469 if (!lp_winbind_enum_groups()) {
473 /* Free old static data if it exists */
475 if (state->getgrent_state != NULL) {
476 free_getent_state(state->getgrent_state);
477 state->getgrent_state = NULL;
480 /* Create sam pipes for each domain we know about */
482 for (domain = domain_list(); domain != NULL; domain = domain->next) {
483 struct getent_state *domain_state;
485 /* Create a state record for this domain */
487 /* don't add our domaina if we are a PDC or if we
488 are a member of a Samba domain */
490 if ( lp_winbind_trusted_domains_only() && domain->primary )
496 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
497 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
501 ZERO_STRUCTP(domain_state);
503 fstrcpy(domain_state->domain_name, domain->name);
505 /* Add to list of open domains */
507 DLIST_ADD(state->getgrent_state, domain_state);
510 state->getgrent_initialized = True;
514 void winbindd_setgrent(struct winbindd_cli_state *state)
516 if (winbindd_setgrent_internal(state)) {
519 request_error(state);
523 /* Close file pointer to ntdom group database */
525 void winbindd_endgrent(struct winbindd_cli_state *state)
527 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
529 free_getent_state(state->getgrent_state);
530 state->getgrent_initialized = False;
531 state->getgrent_state = NULL;
535 /* Get the list of domain groups and domain aliases for a domain. We fill in
536 the sam_entries and num_sam_entries fields with domain group information.
537 The dispinfo_ndx field is incremented to the index of the next group to
538 fetch. Return True if some groups were returned, False otherwise. */
540 static BOOL get_sam_group_entries(struct getent_state *ent)
544 struct acct_info *name_list = NULL;
547 struct acct_info *sam_grp_entries = NULL;
548 struct winbindd_domain *domain;
550 if (ent->got_sam_entries)
553 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
554 ent->domain_name))) {
555 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
559 /* Free any existing group info */
561 SAFE_FREE(ent->sam_entries);
562 ent->num_sam_entries = 0;
563 ent->got_sam_entries = True;
565 /* Enumerate domain groups */
569 if (!(domain = find_domain_from_name(ent->domain_name))) {
570 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
574 /* always get the domain global groups */
576 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
578 if (!NT_STATUS_IS_OK(status)) {
579 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
584 /* Copy entries into return buffer */
587 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
588 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
593 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
596 ent->num_sam_entries = num_entries;
598 /* get the domain local groups if we are a member of a native win2k domain
599 and are not using LDAP to get the groups */
601 if ( ( lp_security() != SEC_ADS && domain->native_mode
602 && domain->primary) || domain->internal )
604 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
605 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
607 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
609 if ( !NT_STATUS_IS_OK(status) ) {
610 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
614 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
616 /* Copy entries into return buffer */
619 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
621 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
627 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
628 num_entries * sizeof(struct acct_info) );
631 ent->num_sam_entries += num_entries;
635 /* Fill in remaining fields */
637 ent->sam_entries = name_list;
638 ent->sam_entry_index = 0;
640 result = (ent->num_sam_entries > 0);
643 talloc_destroy(mem_ctx);
648 /* Fetch next group entry from ntdom database */
650 #define MAX_GETGRENT_GROUPS 500
652 void winbindd_getgrent(struct winbindd_cli_state *state)
654 struct getent_state *ent;
655 struct winbindd_gr *group_list = NULL;
656 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
657 char *gr_mem_list = NULL;
659 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
661 /* Check user has enabled this */
663 if (!lp_winbind_enum_groups()) {
664 request_error(state);
668 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
670 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
671 request_error(state);
675 memset(state->response.extra_data.data, '\0',
676 num_groups * sizeof(struct winbindd_gr) );
678 state->response.data.num_entries = 0;
680 group_list = (struct winbindd_gr *)state->response.extra_data.data;
682 if (!state->getgrent_initialized)
683 winbindd_setgrent_internal(state);
685 if (!(ent = state->getgrent_state)) {
686 request_error(state);
690 /* Start sending back groups */
692 for (i = 0; i < num_groups; i++) {
693 struct acct_info *name_list = NULL;
694 fstring domain_group_name;
700 struct winbindd_domain *domain;
702 /* Do we need to fetch another chunk of groups? */
706 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
707 ent->sam_entry_index, ent->num_sam_entries));
709 if (ent->num_sam_entries == ent->sam_entry_index) {
711 while(ent && !get_sam_group_entries(ent)) {
712 struct getent_state *next_ent;
714 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
716 /* Free state information for this domain */
718 SAFE_FREE(ent->sam_entries);
720 next_ent = ent->next;
721 DLIST_REMOVE(state->getgrent_state, ent);
727 /* No more domains */
733 name_list = (struct acct_info *)ent->sam_entries;
736 find_domain_from_name(ent->domain_name))) {
737 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
742 /* Lookup group info */
744 sid_copy(&group_sid, &domain->sid);
745 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
747 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid,
750 enum lsa_SidType type;
752 DEBUG(10, ("SID %s not in idmap\n",
753 sid_string_static(&group_sid)));
755 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
756 DEBUG(1, ("could not look up gid for group "
758 name_list[ent->sam_entry_index].acct_name));
759 ent->sam_entry_index++;
763 if ((type != SID_NAME_DOM_GRP) &&
764 (type != SID_NAME_ALIAS) &&
765 (type != SID_NAME_WKN_GRP)) {
766 DEBUG(1, ("Group %s is a %s, not a group\n",
767 sid_type_lookup(type),
768 name_list[ent->sam_entry_index].acct_name));
769 ent->sam_entry_index++;
775 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
776 (unsigned long)name_list[ent->sam_entry_index].rid));
778 /* Fill in group entry */
780 fill_domain_username(domain_group_name, ent->domain_name,
781 name_list[ent->sam_entry_index].acct_name, True);
783 result = fill_grent(&group_list[group_list_ndx],
785 name_list[ent->sam_entry_index].acct_name,
788 /* Fill in group membership entry */
791 size_t num_gr_mem = 0;
793 group_list[group_list_ndx].num_gr_mem = 0;
797 /* Get group membership */
798 if (state->request.cmd == WINBINDD_GETGRLST) {
801 sid_copy(&member_sid, &domain->sid);
802 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
803 result = fill_grent_mem(
808 &gr_mem, &gr_mem_len);
810 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
815 /* Append to group membership list */
816 gr_mem_list = (char *)SMB_REALLOC(
817 gr_mem_list, gr_mem_list_len + gr_mem_len);
819 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
820 DEBUG(0, ("out of memory\n"));
825 DEBUG(10, ("list_len = %d, mem_len = %u\n",
826 gr_mem_list_len, (unsigned int)gr_mem_len));
828 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
833 group_list[group_list_ndx].gr_mem_ofs =
836 gr_mem_list_len += gr_mem_len;
839 ent->sam_entry_index++;
841 /* Add group to return list */
845 DEBUG(10, ("adding group num_entries = %d\n",
846 state->response.data.num_entries));
849 state->response.data.num_entries++;
851 state->response.length +=
852 sizeof(struct winbindd_gr);
855 DEBUG(0, ("could not lookup domain group %s\n",
860 /* Copy the list of group memberships to the end of the extra data */
862 if (group_list_ndx == 0)
865 state->response.extra_data.data = SMB_REALLOC(
866 state->response.extra_data.data,
867 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
869 if (!state->response.extra_data.data) {
870 DEBUG(0, ("out of memory\n"));
872 SAFE_FREE(gr_mem_list);
873 request_error(state);
877 memcpy(&((char *)state->response.extra_data.data)
878 [group_list_ndx * sizeof(struct winbindd_gr)],
879 gr_mem_list, gr_mem_list_len);
881 state->response.length += gr_mem_list_len;
883 DEBUG(10, ("returning %d groups, length = %d\n",
884 group_list_ndx, gr_mem_list_len));
890 SAFE_FREE(gr_mem_list);
892 if (group_list_ndx > 0)
895 request_error(state);
898 /* List domain groups without mapping to unix ids */
900 void winbindd_list_groups(struct winbindd_cli_state *state)
902 uint32 total_entries = 0;
903 struct winbindd_domain *domain;
904 const char *which_domain;
905 char *extra_data = NULL;
906 unsigned int extra_data_len = 0, i;
908 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
910 /* Ensure null termination */
911 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
912 which_domain = state->request.domain_name;
914 /* Enumerate over trusted domains */
916 for (domain = domain_list(); domain; domain = domain->next) {
917 struct getent_state groups;
919 /* if we have a domain name restricting the request and this
920 one in the list doesn't match, then just bypass the remainder
923 if ( *which_domain && !strequal(which_domain, domain->name) )
928 /* Get list of sam groups */
930 fstrcpy(groups.domain_name, domain->name);
932 get_sam_group_entries(&groups);
934 if (groups.num_sam_entries == 0) {
935 /* this domain is empty or in an error state */
939 /* keep track the of the total number of groups seen so
940 far over all domains */
941 total_entries += groups.num_sam_entries;
943 /* Allocate some memory for extra data. Note that we limit
944 account names to sizeof(fstring) = 128 characters. */
945 extra_data = (char *)SMB_REALLOC(
946 extra_data, sizeof(fstring) * total_entries);
949 DEBUG(0,("failed to enlarge buffer!\n"));
950 request_error(state);
954 /* Pack group list into extra data fields */
955 for (i = 0; i < groups.num_sam_entries; i++) {
956 char *group_name = ((struct acct_info *)
957 groups.sam_entries)[i].acct_name;
960 fill_domain_username(name, domain->name, group_name, True);
961 /* Append to extra data */
962 memcpy(&extra_data[extra_data_len], name,
964 extra_data_len += strlen(name);
965 extra_data[extra_data_len++] = ',';
968 SAFE_FREE(groups.sam_entries);
971 /* Assign extra_data fields in response structure */
973 extra_data[extra_data_len - 1] = '\0';
974 state->response.extra_data.data = extra_data;
975 state->response.length += extra_data_len;
978 /* No domains may have responded but that's still OK so don't
984 /* Get user supplementary groups. This is much quicker than trying to
985 invert the groups database. We merge the groups from the gids and
986 other_sids info3 fields as trusted domain, universal group
987 memberships, and nested groups (win2k native mode only) are not
988 returned by the getgroups RPC call but are present in the info3. */
990 struct getgroups_state {
991 struct winbindd_cli_state *state;
992 struct winbindd_domain *domain;
997 const DOM_SID *token_sids;
998 size_t i, num_token_sids;
1001 size_t num_token_gids;
1004 static void getgroups_usersid_recv(void *private_data, BOOL success,
1005 const DOM_SID *sid, enum lsa_SidType type);
1006 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1007 DOM_SID *token_sids, size_t num_token_sids);
1008 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
1010 void winbindd_getgroups(struct winbindd_cli_state *state)
1012 struct getgroups_state *s;
1014 /* Ensure null termination */
1015 state->request.data.username
1016 [sizeof(state->request.data.username)-1]='\0';
1018 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1019 state->request.data.username));
1021 /* Parse domain and username */
1023 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1025 DEBUG(0, ("talloc failed\n"));
1026 request_error(state);
1032 if (!parse_domain_user_talloc(state->mem_ctx,
1033 state->request.data.username,
1034 &s->domname, &s->username)) {
1035 DEBUG(5, ("Could not parse domain user: %s\n",
1036 state->request.data.username));
1038 /* error out if we do not have nested group support */
1040 if ( !lp_winbind_nested_groups() ) {
1041 request_error(state);
1045 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1046 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1049 /* Get info for the domain */
1051 s->domain = find_domain_from_name_noinit(s->domname);
1053 if (s->domain == NULL) {
1054 DEBUG(7, ("could not find domain entry for domain %s\n",
1056 request_error(state);
1060 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1061 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
1062 "getgroups() for %s\\%s.\n", s->domname,
1064 request_error(state);
1068 /* Get rid and name type from name. The following costs 1 packet */
1070 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1071 getgroups_usersid_recv, s);
1074 static void getgroups_usersid_recv(void *private_data, BOOL success,
1075 const DOM_SID *sid, enum lsa_SidType type)
1077 struct getgroups_state *s =
1078 (struct getgroups_state *)private_data;
1081 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1082 request_error(s->state);
1086 sid_copy(&s->user_sid, sid);
1088 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1089 getgroups_tokensids_recv, s);
1092 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1093 DOM_SID *token_sids, size_t num_token_sids)
1095 struct getgroups_state *s =
1096 (struct getgroups_state *)private_data;
1098 /* We need at least the user sid and the primary group in the token,
1099 * otherwise it's an error */
1101 if ((!success) || (num_token_sids < 2)) {
1102 request_error(s->state);
1106 s->token_sids = token_sids;
1107 s->num_token_sids = num_token_sids;
1110 s->token_gids = NULL;
1111 s->num_token_gids = 0;
1113 getgroups_sid2gid_recv(s, False, 0);
1116 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1118 struct getgroups_state *s =
1119 (struct getgroups_state *)private_data;
1122 add_gid_to_array_unique(NULL, gid,
1124 &s->num_token_gids);
1126 if (s->i < s->num_token_sids) {
1127 const DOM_SID *sid = &s->token_sids[s->i];
1130 if (sid_equal(sid, &s->user_sid)) {
1131 getgroups_sid2gid_recv(s, False, 0);
1135 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1136 getgroups_sid2gid_recv, s);
1140 s->state->response.data.num_entries = s->num_token_gids;
1141 s->state->response.extra_data.data = s->token_gids;
1142 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1143 request_ok(s->state);
1146 /* Get user supplementary sids. This is equivalent to the
1147 winbindd_getgroups() function but it involves a SID->SIDs mapping
1148 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1149 idmap. This call is designed to be used with applications that need
1150 to do ACL evaluation themselves. Note that the cached info3 data is
1153 this function assumes that the SID that comes in is a user SID. If
1154 you pass in another type of SID then you may get unpredictable
1158 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1161 void winbindd_getusersids(struct winbindd_cli_state *state)
1165 /* Ensure null termination */
1166 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1168 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1169 if (user_sid == NULL) {
1170 DEBUG(1, ("talloc failed\n"));
1171 request_error(state);
1175 if (!string_to_sid(user_sid, state->request.data.sid)) {
1176 DEBUG(1, ("Could not get convert sid %s from string\n",
1177 state->request.data.sid));
1178 request_error(state);
1182 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1186 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1189 struct winbindd_cli_state *state =
1190 (struct winbindd_cli_state *)private_data;
1192 unsigned ofs, ret_size = 0;
1196 request_error(state);
1200 /* work out the response size */
1201 for (i = 0; i < num_sids; i++) {
1202 const char *s = sid_string_static(&sids[i]);
1203 ret_size += strlen(s) + 1;
1206 /* build the reply */
1207 ret = (char *)SMB_MALLOC(ret_size);
1209 DEBUG(0, ("malloc failed\n"));
1210 request_error(state);
1214 for (i = 0; i < num_sids; i++) {
1215 const char *s = sid_string_static(&sids[i]);
1216 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1217 ofs += strlen(ret+ofs) + 1;
1220 /* Send data back to client */
1221 state->response.data.num_entries = num_sids;
1222 state->response.extra_data.data = ret;
1223 state->response.length += ret_size;
1227 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1230 struct winbindd_domain *domain;
1232 /* Ensure null termination */
1233 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1235 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1236 DEBUG(1, ("Could not get convert sid %s from string\n",
1237 state->request.data.sid));
1238 request_error(state);
1242 /* Get info for the domain */
1243 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1244 DEBUG(0,("could not find domain entry for sid %s\n",
1245 sid_string_static(&user_sid)));
1246 request_error(state);
1250 sendto_domain(state, domain);
1253 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1254 struct winbindd_cli_state *state)
1264 /* Ensure null termination */
1265 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1267 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1268 DEBUG(1, ("Could not get convert sid %s from string\n",
1269 state->request.data.sid));
1270 return WINBINDD_ERROR;
1273 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1274 &user_sid, &num_groups,
1276 if (!NT_STATUS_IS_OK(status))
1277 return WINBINDD_ERROR;
1279 if (num_groups == 0) {
1280 state->response.data.num_entries = 0;
1281 state->response.extra_data.data = NULL;
1285 if (!print_sidlist(NULL, groups, num_groups, &sidstring, &len)) {
1286 DEBUG(0, ("malloc failed\n"));
1287 return WINBINDD_ERROR;
1290 state->response.extra_data.data = sidstring;
1291 state->response.length += len+1;
1292 state->response.data.num_entries = num_groups;