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);
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 SID_NAME_USE 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);
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 = 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 = %d, len = %d, mem = %s\n", *num_gr_mem,
188 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)
205 struct winbindd_domain *domain;
206 enum SID_NAME_USE name_type;
207 fstring name_domain, name_group;
214 /* Ensure null termination */
215 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
217 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
218 state->request.data.groupname));
220 /* Parse domain and groupname */
222 memset(name_group, 0, sizeof(fstring));
224 tmp = state->request.data.groupname;
226 parse_domain_user(tmp, name_domain, name_group);
228 /* if no domain or our local domain and no local tdb group, default to
229 * our local domain for aliases */
231 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
232 fstrcpy(name_domain, get_global_sam_name());
235 /* Get info for the domain */
237 if ((domain = find_domain_from_name(name_domain)) == NULL) {
238 DEBUG(3, ("could not get domain sid for domain %s\n",
240 request_error(state);
243 /* should we deal with users for our domain? */
245 if ( lp_winbind_trusted_domains_only() && domain->primary) {
246 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
247 "getgrnam() for %s\\%s.\n", name_domain, name_group));
248 request_error(state);
252 /* Get rid and name type from name */
254 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
255 name_group, &group_sid, &name_type)) {
256 DEBUG(1, ("group %s in domain %s does not exist\n",
257 name_group, name_domain));
258 request_error(state);
262 if ( !((name_type==SID_NAME_DOM_GRP) ||
263 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
264 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
265 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
267 DEBUG(1, ("name '%s' is not a local, domain or builtin "
268 "group: %d\n", name_group, name_type));
269 request_error(state);
273 /* Try to get the GID */
275 status = idmap_sid_to_gid(&group_sid, &gid, 0);
277 if (NT_STATUS_IS_OK(status)) {
281 /* Maybe it's one of our aliases in passdb */
283 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
284 ((name_type == SID_NAME_ALIAS) ||
285 (name_type == SID_NAME_WKN_GRP))) {
290 DEBUG(1, ("error converting unix gid to sid\n"));
291 request_error(state);
296 if (!fill_grent(&state->response.data.gr, name_domain,
298 !fill_grent_mem(domain, &group_sid, name_type,
299 &state->response.data.gr.num_gr_mem,
300 &gr_mem, &gr_mem_len)) {
301 request_error(state);
305 /* Group membership lives at start of extra data */
307 state->response.data.gr.gr_mem_ofs = 0;
309 state->response.length += gr_mem_len;
310 state->response.extra_data = gr_mem;
314 /* Return a group structure from a gid number */
316 void winbindd_getgrgid(struct winbindd_cli_state *state)
318 struct winbindd_domain *domain;
320 enum SID_NAME_USE name_type;
327 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
328 (unsigned long)state->request.data.gid));
330 /* Bug out if the gid isn't in the winbind range */
332 if ((state->request.data.gid < server_state.gid_low) ||
333 (state->request.data.gid > server_state.gid_high)) {
334 request_error(state);
338 /* Get sid from gid */
340 status = idmap_gid_to_sid(&group_sid, state->request.data.gid, 0);
341 if (NT_STATUS_IS_OK(status)) {
342 /* This is a remote one */
346 /* Ok, this might be "ours", i.e. an alias */
348 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
349 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
350 (name_type == SID_NAME_ALIAS)) {
351 /* Hey, got an alias */
355 DEBUG(1, ("could not convert gid %lu to sid\n",
356 (unsigned long)state->request.data.gid));
357 request_error(state);
361 /* Get name from sid */
363 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
364 group_name, &name_type)) {
365 DEBUG(1, ("could not lookup sid\n"));
366 request_error(state);
370 /* Fill in group structure */
372 domain = find_domain_from_sid_noinit(&group_sid);
375 DEBUG(1,("Can't find domain from sid\n"));
376 request_error(state);
380 if ( !((name_type==SID_NAME_DOM_GRP) ||
381 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
382 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
384 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
385 group_name, name_type));
386 request_error(state);
390 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
391 state->request.data.gid) ||
392 !fill_grent_mem(domain, &group_sid, name_type,
393 &state->response.data.gr.num_gr_mem,
394 &gr_mem, &gr_mem_len)) {
395 request_error(state);
399 /* Group membership lives at start of extra data */
401 state->response.data.gr.gr_mem_ofs = 0;
403 state->response.length += gr_mem_len;
404 state->response.extra_data = gr_mem;
409 * set/get/endgrent functions
412 /* "Rewind" file pointer for group database enumeration */
414 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
416 struct winbindd_domain *domain;
418 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
420 /* Check user has enabled this */
422 if (!lp_winbind_enum_groups()) {
426 /* Free old static data if it exists */
428 if (state->getgrent_state != NULL) {
429 free_getent_state(state->getgrent_state);
430 state->getgrent_state = NULL;
433 /* Create sam pipes for each domain we know about */
435 for (domain = domain_list(); domain != NULL; domain = domain->next) {
436 struct getent_state *domain_state;
438 /* Create a state record for this domain */
440 /* don't add our domaina if we are a PDC or if we
441 are a member of a Samba domain */
443 if ( lp_winbind_trusted_domains_only() && domain->primary )
449 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
450 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
454 ZERO_STRUCTP(domain_state);
456 fstrcpy(domain_state->domain_name, domain->name);
458 /* Add to list of open domains */
460 DLIST_ADD(state->getgrent_state, domain_state);
463 state->getgrent_initialized = True;
467 void winbindd_setgrent(struct winbindd_cli_state *state)
469 if (winbindd_setgrent_internal(state)) {
472 request_error(state);
476 /* Close file pointer to ntdom group database */
478 void winbindd_endgrent(struct winbindd_cli_state *state)
480 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
482 free_getent_state(state->getgrent_state);
483 state->getgrent_initialized = False;
484 state->getgrent_state = NULL;
488 /* Get the list of domain groups and domain aliases for a domain. We fill in
489 the sam_entries and num_sam_entries fields with domain group information.
490 The dispinfo_ndx field is incremented to the index of the next group to
491 fetch. Return True if some groups were returned, False otherwise. */
493 static BOOL get_sam_group_entries(struct getent_state *ent)
497 struct acct_info *name_list = NULL;
500 struct acct_info *sam_grp_entries = NULL;
501 struct winbindd_domain *domain;
503 if (ent->got_sam_entries)
506 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
507 ent->domain_name))) {
508 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
512 /* Free any existing group info */
514 SAFE_FREE(ent->sam_entries);
515 ent->num_sam_entries = 0;
516 ent->got_sam_entries = True;
518 /* Enumerate domain groups */
522 if (!(domain = find_domain_from_name(ent->domain_name))) {
523 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
527 /* always get the domain global groups */
529 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
531 if (!NT_STATUS_IS_OK(status)) {
532 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
537 /* Copy entries into return buffer */
540 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
541 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
546 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
549 ent->num_sam_entries = num_entries;
551 /* get the domain local groups if we are a member of a native win2k domain
552 and are not using LDAP to get the groups */
554 if ( ( lp_security() != SEC_ADS && domain->native_mode
555 && domain->primary) || domain->internal )
557 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
558 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
560 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
562 if ( !NT_STATUS_IS_OK(status) ) {
563 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
567 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
569 /* Copy entries into return buffer */
572 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
574 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
580 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
581 num_entries * sizeof(struct acct_info) );
584 ent->num_sam_entries += num_entries;
588 /* Fill in remaining fields */
590 ent->sam_entries = name_list;
591 ent->sam_entry_index = 0;
593 result = (ent->num_sam_entries > 0);
596 talloc_destroy(mem_ctx);
601 /* Fetch next group entry from ntdom database */
603 #define MAX_GETGRENT_GROUPS 500
605 void winbindd_getgrent(struct winbindd_cli_state *state)
607 struct getent_state *ent;
608 struct winbindd_gr *group_list = NULL;
609 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
610 char *gr_mem_list = NULL;
612 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
614 /* Check user has enabled this */
616 if (!lp_winbind_enum_groups()) {
617 request_error(state);
621 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
623 if ((state->response.extra_data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
624 request_error(state);
628 memset(state->response.extra_data, '\0',
629 num_groups * sizeof(struct winbindd_gr) );
631 state->response.data.num_entries = 0;
633 group_list = (struct winbindd_gr *)state->response.extra_data;
635 if (!state->getgrent_initialized)
636 winbindd_setgrent_internal(state);
638 if (!(ent = state->getgrent_state)) {
639 request_error(state);
643 /* Start sending back groups */
645 for (i = 0; i < num_groups; i++) {
646 struct acct_info *name_list = NULL;
647 fstring domain_group_name;
653 struct winbindd_domain *domain;
655 /* Do we need to fetch another chunk of groups? */
659 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
660 ent->sam_entry_index, ent->num_sam_entries));
662 if (ent->num_sam_entries == ent->sam_entry_index) {
664 while(ent && !get_sam_group_entries(ent)) {
665 struct getent_state *next_ent;
667 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
669 /* Free state information for this domain */
671 SAFE_FREE(ent->sam_entries);
673 next_ent = ent->next;
674 DLIST_REMOVE(state->getgrent_state, ent);
680 /* No more domains */
686 name_list = ent->sam_entries;
689 find_domain_from_name(ent->domain_name))) {
690 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
695 /* Lookup group info */
697 sid_copy(&group_sid, &domain->sid);
698 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
700 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid,
703 enum SID_NAME_USE type;
705 DEBUG(10, ("SID %s not in idmap\n",
706 sid_string_static(&group_sid)));
708 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
709 DEBUG(1, ("could not look up gid for group "
711 name_list[ent->sam_entry_index].acct_name));
712 ent->sam_entry_index++;
716 if ((type != SID_NAME_DOM_GRP) &&
717 (type != SID_NAME_ALIAS) &&
718 (type != SID_NAME_WKN_GRP)) {
719 DEBUG(1, ("Group %s is a %s, not a group\n",
720 sid_type_lookup(type),
721 name_list[ent->sam_entry_index].acct_name));
722 ent->sam_entry_index++;
728 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
729 (unsigned long)name_list[ent->sam_entry_index].rid));
731 /* Fill in group entry */
733 fill_domain_username(domain_group_name, ent->domain_name,
734 name_list[ent->sam_entry_index].acct_name);
736 result = fill_grent(&group_list[group_list_ndx],
738 name_list[ent->sam_entry_index].acct_name,
741 /* Fill in group membership entry */
745 group_list[group_list_ndx].num_gr_mem = 0;
749 /* Get group membership */
750 if (state->request.cmd == WINBINDD_GETGRLST) {
753 sid_copy(&member_sid, &domain->sid);
754 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
755 result = fill_grent_mem(
759 &group_list[group_list_ndx].num_gr_mem,
760 &gr_mem, &gr_mem_len);
765 /* Append to group membership list */
766 gr_mem_list = SMB_REALLOC( gr_mem_list, gr_mem_list_len + gr_mem_len);
769 DEBUG(0, ("out of memory\n"));
774 DEBUG(10, ("list_len = %d, mem_len = %d\n",
775 gr_mem_list_len, gr_mem_len));
777 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
782 group_list[group_list_ndx].gr_mem_ofs =
785 gr_mem_list_len += gr_mem_len;
788 ent->sam_entry_index++;
790 /* Add group to return list */
794 DEBUG(10, ("adding group num_entries = %d\n",
795 state->response.data.num_entries));
798 state->response.data.num_entries++;
800 state->response.length +=
801 sizeof(struct winbindd_gr);
804 DEBUG(0, ("could not lookup domain group %s\n",
809 /* Copy the list of group memberships to the end of the extra data */
811 if (group_list_ndx == 0)
814 state->response.extra_data = SMB_REALLOC(
815 state->response.extra_data,
816 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
818 if (!state->response.extra_data) {
819 DEBUG(0, ("out of memory\n"));
821 SAFE_FREE(gr_mem_list);
822 request_error(state);
826 memcpy(&((char *)state->response.extra_data)
827 [group_list_ndx * sizeof(struct winbindd_gr)],
828 gr_mem_list, gr_mem_list_len);
830 state->response.length += gr_mem_list_len;
832 DEBUG(10, ("returning %d groups, length = %d\n",
833 group_list_ndx, gr_mem_list_len));
839 SAFE_FREE(gr_mem_list);
841 if (group_list_ndx > 0)
844 request_error(state);
847 /* List domain groups without mapping to unix ids */
849 void winbindd_list_groups(struct winbindd_cli_state *state)
851 uint32 total_entries = 0;
852 struct winbindd_domain *domain;
853 const char *which_domain;
854 char *extra_data = NULL;
855 unsigned int extra_data_len = 0, i;
857 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
859 /* Ensure null termination */
860 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
861 which_domain = state->request.domain_name;
863 /* Enumerate over trusted domains */
865 for (domain = domain_list(); domain; domain = domain->next) {
866 struct getent_state groups;
868 /* if we have a domain name restricting the request and this
869 one in the list doesn't match, then just bypass the remainder
872 if ( *which_domain && !strequal(which_domain, domain->name) )
877 /* Get list of sam groups */
879 fstrcpy(groups.domain_name, domain->name);
881 get_sam_group_entries(&groups);
883 if (groups.num_sam_entries == 0) {
884 /* this domain is empty or in an error state */
888 /* keep track the of the total number of groups seen so
889 far over all domains */
890 total_entries += groups.num_sam_entries;
892 /* Allocate some memory for extra data. Note that we limit
893 account names to sizeof(fstring) = 128 characters. */
894 extra_data = SMB_REALLOC(extra_data, sizeof(fstring) * total_entries);
897 DEBUG(0,("failed to enlarge buffer!\n"));
898 request_error(state);
902 /* Pack group list into extra data fields */
903 for (i = 0; i < groups.num_sam_entries; i++) {
904 char *group_name = ((struct acct_info *)
905 groups.sam_entries)[i].acct_name;
908 fill_domain_username(name, domain->name, group_name);
909 /* Append to extra data */
910 memcpy(&extra_data[extra_data_len], name,
912 extra_data_len += strlen(name);
913 extra_data[extra_data_len++] = ',';
916 SAFE_FREE(groups.sam_entries);
919 /* Assign extra_data fields in response structure */
921 extra_data[extra_data_len - 1] = '\0';
922 state->response.extra_data = extra_data;
923 state->response.length += extra_data_len;
926 /* No domains may have responded but that's still OK so don't
932 /* Get user supplementary groups. This is much quicker than trying to
933 invert the groups database. We merge the groups from the gids and
934 other_sids info3 fields as trusted domain, universal group
935 memberships, and nested groups (win2k native mode only) are not
936 returned by the getgroups RPC call but are present in the info3. */
938 struct getgroups_state {
939 struct winbindd_cli_state *state;
940 struct winbindd_domain *domain;
945 const DOM_SID *token_sids;
946 size_t i, num_token_sids;
949 size_t num_token_gids;
952 static void getgroups_usersid_recv(void *private_data, BOOL success,
953 const DOM_SID *sid, enum SID_NAME_USE type);
954 static void getgroups_tokensids_recv(void *private_data, BOOL success,
955 DOM_SID *token_sids, size_t num_token_sids);
956 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
958 void winbindd_getgroups(struct winbindd_cli_state *state)
960 struct getgroups_state *s;
962 /* Ensure null termination */
963 state->request.data.username
964 [sizeof(state->request.data.username)-1]='\0';
966 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
967 state->request.data.username));
969 /* Parse domain and username */
971 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
973 DEBUG(0, ("talloc failed\n"));
974 request_error(state);
980 if (!parse_domain_user_talloc(state->mem_ctx,
981 state->request.data.username,
982 &s->domname, &s->username)) {
983 DEBUG(5, ("Could not parse domain user: %s\n",
984 state->request.data.username));
985 request_error(state);
989 /* Get info for the domain */
991 s->domain = find_domain_from_name_noinit(s->domname);
993 if (s->domain == NULL) {
994 DEBUG(7, ("could not find domain entry for domain %s\n",
996 request_error(state);
1000 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1001 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
1002 "getgroups() for %s\\%s.\n", s->domname,
1004 request_error(state);
1008 /* Get rid and name type from name. The following costs 1 packet */
1010 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1011 getgroups_usersid_recv, s);
1014 static void getgroups_usersid_recv(void *private_data, BOOL success,
1015 const DOM_SID *sid, enum SID_NAME_USE type)
1017 struct getgroups_state *s = private_data;
1020 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1021 request_error(s->state);
1025 sid_copy(&s->user_sid, sid);
1027 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1028 getgroups_tokensids_recv, s);
1031 static void getgroups_tokensids_recv(void *private_data, BOOL success,
1032 DOM_SID *token_sids, size_t num_token_sids)
1034 struct getgroups_state *s = private_data;
1036 /* We need at least the user sid and the primary group in the token,
1037 * otherwise it's an error */
1039 if ((!success) || (num_token_sids < 2)) {
1040 request_error(s->state);
1044 s->token_sids = token_sids;
1045 s->num_token_sids = num_token_sids;
1048 s->token_gids = NULL;
1049 s->num_token_gids = 0;
1051 getgroups_sid2gid_recv(s, False, 0);
1054 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1056 struct getgroups_state *s = private_data;
1059 add_gid_to_array_unique(NULL, gid,
1061 &s->num_token_gids);
1063 if (s->i < s->num_token_sids) {
1064 const DOM_SID *sid = &s->token_sids[s->i];
1067 if (sid_equal(sid, &s->user_sid)) {
1068 getgroups_sid2gid_recv(s, False, 0);
1072 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1073 getgroups_sid2gid_recv, s);
1077 s->state->response.data.num_entries = s->num_token_gids;
1078 s->state->response.extra_data = s->token_gids;
1079 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1080 request_ok(s->state);
1083 /* Get user supplementary sids. This is equivalent to the
1084 winbindd_getgroups() function but it involves a SID->SIDs mapping
1085 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1086 idmap. This call is designed to be used with applications that need
1087 to do ACL evaluation themselves. Note that the cached info3 data is
1090 this function assumes that the SID that comes in is a user SID. If
1091 you pass in another type of SID then you may get unpredictable
1095 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1098 void winbindd_getusersids(struct winbindd_cli_state *state)
1102 /* Ensure null termination */
1103 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1105 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1106 if (user_sid == NULL) {
1107 DEBUG(1, ("talloc failed\n"));
1108 request_error(state);
1112 if (!string_to_sid(user_sid, state->request.data.sid)) {
1113 DEBUG(1, ("Could not get convert sid %s from string\n",
1114 state->request.data.sid));
1115 request_error(state);
1119 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1123 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1126 struct winbindd_cli_state *state = private_data;
1128 unsigned ofs, ret_size = 0;
1132 request_error(state);
1136 /* work out the response size */
1137 for (i = 0; i < num_sids; i++) {
1138 const char *s = sid_string_static(&sids[i]);
1139 ret_size += strlen(s) + 1;
1142 /* build the reply */
1143 ret = SMB_MALLOC(ret_size);
1145 DEBUG(0, ("malloc failed\n"));
1146 request_error(state);
1150 for (i = 0; i < num_sids; i++) {
1151 const char *s = sid_string_static(&sids[i]);
1152 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1153 ofs += strlen(ret+ofs) + 1;
1156 /* Send data back to client */
1157 state->response.data.num_entries = num_sids;
1158 state->response.extra_data = ret;
1159 state->response.length += ret_size;
1163 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1166 struct winbindd_domain *domain;
1168 /* Ensure null termination */
1169 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1171 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1172 DEBUG(1, ("Could not get convert sid %s from string\n",
1173 state->request.data.sid));
1174 request_error(state);
1178 /* Get info for the domain */
1179 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1180 DEBUG(0,("could not find domain entry for sid %s\n",
1181 sid_string_static(&user_sid)));
1182 request_error(state);
1186 sendto_domain(state, domain);
1189 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1190 struct winbindd_cli_state *state)
1200 /* Ensure null termination */
1201 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1203 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1204 DEBUG(1, ("Could not get convert sid %s from string\n",
1205 state->request.data.sid));
1206 return WINBINDD_ERROR;
1209 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1210 &user_sid, &num_groups,
1212 if (!NT_STATUS_IS_OK(status))
1213 return WINBINDD_ERROR;
1215 if (num_groups == 0) {
1216 state->response.data.num_entries = 0;
1217 state->response.extra_data = NULL;
1221 if (!print_sidlist(NULL, groups, num_groups, &sidstring, &len)) {
1222 DEBUG(0, ("malloc failed\n"));
1223 return WINBINDD_ERROR;
1226 state->response.extra_data = sidstring;
1227 state->response.length += len+1;
1228 state->response.data.num_entries = num_groups;