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
, False
);
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
, False
);
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
)
204 DOM_SID group_sid
, tmp_sid
;
206 struct winbindd_domain
*domain
;
207 enum SID_NAME_USE name_type
;
208 fstring name_domain
, name_group
;
215 /* Ensure null termination */
216 state
->request
.data
.groupname
[sizeof(state
->request
.data
.groupname
)-1]='\0';
218 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state
->pid
,
219 state
->request
.data
.groupname
));
221 /* Parse domain and groupname */
223 memset(name_group
, 0, sizeof(fstring
));
225 tmp
= state
->request
.data
.groupname
;
227 parse_domain_user(tmp
, name_domain
, name_group
);
229 /* if no domain or our local domain and no local tdb group, default to
230 * our local domain for aliases */
232 if ( !*name_domain
|| strequal(name_domain
, get_global_sam_name()) ) {
233 fstrcpy(name_domain
, get_global_sam_name());
236 /* Get info for the domain */
238 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
239 DEBUG(3, ("could not get domain sid for domain %s\n",
241 request_error(state
);
244 /* should we deal with users for our domain? */
246 if ( lp_winbind_trusted_domains_only() && domain
->primary
) {
247 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
248 "getgrnam() for %s\\%s.\n", name_domain
, name_group
));
249 request_error(state
);
253 /* Get rid and name type from name */
255 if (!winbindd_lookup_sid_by_name(state
->mem_ctx
, domain
, domain
->name
,
256 name_group
, &group_sid
, &name_type
)) {
257 DEBUG(1, ("group %s in domain %s does not exist\n",
258 name_group
, name_domain
));
259 request_error(state
);
263 if ( !((name_type
==SID_NAME_DOM_GRP
) ||
264 ((name_type
==SID_NAME_ALIAS
) && domain
->primary
) ||
265 ((name_type
==SID_NAME_ALIAS
) && domain
->internal
) ||
266 ((name_type
==SID_NAME_WKN_GRP
) && domain
->internal
)) )
268 DEBUG(1, ("name '%s' is not a local, domain or builtin "
269 "group: %d\n", name_group
, name_type
));
270 request_error(state
);
274 /* Make sure that the group SID is within the domain of the
277 sid_copy( &tmp_sid
, &group_sid
);
278 sid_split_rid( &tmp_sid
, &grp_rid
);
279 if ( !sid_equal( &tmp_sid
, &domain
->sid
) ) {
280 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
281 state
->request
.data
.groupname
, sid_string_static(&group_sid
)));
282 request_error(state
);
288 /* Try to get the GID */
290 status
= idmap_sid_to_gid(&group_sid
, &gid
, 0);
292 if (NT_STATUS_IS_OK(status
)) {
296 /* Maybe it's one of our aliases in passdb */
298 if (pdb_sid_to_id(&group_sid
, &id
, &name_type
) &&
299 ((name_type
== SID_NAME_ALIAS
) ||
300 (name_type
== SID_NAME_WKN_GRP
))) {
305 DEBUG(1, ("error converting unix gid to sid\n"));
306 request_error(state
);
311 if (!fill_grent(&state
->response
.data
.gr
, name_domain
,
313 !fill_grent_mem(domain
, &group_sid
, name_type
,
314 &state
->response
.data
.gr
.num_gr_mem
,
315 &gr_mem
, &gr_mem_len
)) {
316 request_error(state
);
320 /* Group membership lives at start of extra data */
322 state
->response
.data
.gr
.gr_mem_ofs
= 0;
324 state
->response
.length
+= gr_mem_len
;
325 state
->response
.extra_data
= gr_mem
;
329 /* Return a group structure from a gid number */
331 void winbindd_getgrgid(struct winbindd_cli_state
*state
)
333 struct winbindd_domain
*domain
;
335 enum SID_NAME_USE name_type
;
342 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state
->pid
,
343 (unsigned long)state
->request
.data
.gid
));
345 /* Bug out if the gid isn't in the winbind range */
347 if ((state
->request
.data
.gid
< server_state
.gid_low
) ||
348 (state
->request
.data
.gid
> server_state
.gid_high
)) {
349 request_error(state
);
353 /* Get sid from gid */
355 status
= idmap_gid_to_sid(&group_sid
, state
->request
.data
.gid
, 0);
356 if (NT_STATUS_IS_OK(status
)) {
357 /* This is a remote one */
361 /* Ok, this might be "ours", i.e. an alias */
363 if (pdb_gid_to_sid(state
->request
.data
.gid
, &group_sid
) &&
364 lookup_sid(state
->mem_ctx
, &group_sid
, NULL
, NULL
, &name_type
) &&
365 (name_type
== SID_NAME_ALIAS
)) {
366 /* Hey, got an alias */
370 DEBUG(1, ("could not convert gid %lu to sid\n",
371 (unsigned long)state
->request
.data
.gid
));
372 request_error(state
);
376 /* Get name from sid */
378 if (!winbindd_lookup_name_by_sid(state
->mem_ctx
, &group_sid
, dom_name
,
379 group_name
, &name_type
)) {
380 DEBUG(1, ("could not lookup sid\n"));
381 request_error(state
);
385 /* Fill in group structure */
387 domain
= find_domain_from_sid_noinit(&group_sid
);
390 DEBUG(1,("Can't find domain from sid\n"));
391 request_error(state
);
395 if ( !((name_type
==SID_NAME_DOM_GRP
) ||
396 ((name_type
==SID_NAME_ALIAS
) && domain
->primary
) ||
397 ((name_type
==SID_NAME_ALIAS
) && domain
->internal
)) )
399 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
400 group_name
, name_type
));
401 request_error(state
);
405 if (!fill_grent(&state
->response
.data
.gr
, dom_name
, group_name
,
406 state
->request
.data
.gid
) ||
407 !fill_grent_mem(domain
, &group_sid
, name_type
,
408 &state
->response
.data
.gr
.num_gr_mem
,
409 &gr_mem
, &gr_mem_len
)) {
410 request_error(state
);
414 /* Group membership lives at start of extra data */
416 state
->response
.data
.gr
.gr_mem_ofs
= 0;
418 state
->response
.length
+= gr_mem_len
;
419 state
->response
.extra_data
= gr_mem
;
424 * set/get/endgrent functions
427 /* "Rewind" file pointer for group database enumeration */
429 static BOOL
winbindd_setgrent_internal(struct winbindd_cli_state
*state
)
431 struct winbindd_domain
*domain
;
433 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state
->pid
));
435 /* Check user has enabled this */
437 if (!lp_winbind_enum_groups()) {
441 /* Free old static data if it exists */
443 if (state
->getgrent_state
!= NULL
) {
444 free_getent_state(state
->getgrent_state
);
445 state
->getgrent_state
= NULL
;
448 /* Create sam pipes for each domain we know about */
450 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
451 struct getent_state
*domain_state
;
453 /* Create a state record for this domain */
455 /* don't add our domaina if we are a PDC or if we
456 are a member of a Samba domain */
458 if ( lp_winbind_trusted_domains_only() && domain
->primary
)
464 if ((domain_state
= SMB_MALLOC_P(struct getent_state
)) == NULL
) {
465 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
469 ZERO_STRUCTP(domain_state
);
471 fstrcpy(domain_state
->domain_name
, domain
->name
);
473 /* Add to list of open domains */
475 DLIST_ADD(state
->getgrent_state
, domain_state
);
478 state
->getgrent_initialized
= True
;
482 void winbindd_setgrent(struct winbindd_cli_state
*state
)
484 if (winbindd_setgrent_internal(state
)) {
487 request_error(state
);
491 /* Close file pointer to ntdom group database */
493 void winbindd_endgrent(struct winbindd_cli_state
*state
)
495 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state
->pid
));
497 free_getent_state(state
->getgrent_state
);
498 state
->getgrent_initialized
= False
;
499 state
->getgrent_state
= NULL
;
503 /* Get the list of domain groups and domain aliases for a domain. We fill in
504 the sam_entries and num_sam_entries fields with domain group information.
505 The dispinfo_ndx field is incremented to the index of the next group to
506 fetch. Return True if some groups were returned, False otherwise. */
508 static BOOL
get_sam_group_entries(struct getent_state
*ent
)
512 struct acct_info
*name_list
= NULL
;
515 struct acct_info
*sam_grp_entries
= NULL
;
516 struct winbindd_domain
*domain
;
518 if (ent
->got_sam_entries
)
521 if (!(mem_ctx
= talloc_init("get_sam_group_entries(%s)",
522 ent
->domain_name
))) {
523 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
527 /* Free any existing group info */
529 SAFE_FREE(ent
->sam_entries
);
530 ent
->num_sam_entries
= 0;
531 ent
->got_sam_entries
= True
;
533 /* Enumerate domain groups */
537 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
538 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent
->domain_name
));
542 /* always get the domain global groups */
544 status
= domain
->methods
->enum_dom_groups(domain
, mem_ctx
, &num_entries
, &sam_grp_entries
);
546 if (!NT_STATUS_IS_OK(status
)) {
547 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status
)));
552 /* Copy entries into return buffer */
555 if ( !(name_list
= SMB_MALLOC_ARRAY(struct acct_info
, num_entries
)) ) {
556 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
561 memcpy( name_list
, sam_grp_entries
, num_entries
* sizeof(struct acct_info
) );
564 ent
->num_sam_entries
= num_entries
;
566 /* get the domain local groups if we are a member of a native win2k domain
567 and are not using LDAP to get the groups */
569 if ( ( lp_security() != SEC_ADS
&& domain
->native_mode
570 && domain
->primary
) || domain
->internal
)
572 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
573 domain
->native_mode
? "Native Mode 2k":"BUILTIN or local"));
575 status
= domain
->methods
->enum_local_groups(domain
, mem_ctx
, &num_entries
, &sam_grp_entries
);
577 if ( !NT_STATUS_IS_OK(status
) ) {
578 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
582 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries
));
584 /* Copy entries into return buffer */
587 if ( !(name_list
= SMB_REALLOC_ARRAY( name_list
, struct acct_info
, ent
->num_sam_entries
+num_entries
)) )
589 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
595 memcpy( &name_list
[ent
->num_sam_entries
], sam_grp_entries
,
596 num_entries
* sizeof(struct acct_info
) );
599 ent
->num_sam_entries
+= num_entries
;
603 /* Fill in remaining fields */
605 ent
->sam_entries
= name_list
;
606 ent
->sam_entry_index
= 0;
608 result
= (ent
->num_sam_entries
> 0);
611 talloc_destroy(mem_ctx
);
616 /* Fetch next group entry from ntdom database */
618 #define MAX_GETGRENT_GROUPS 500
620 void winbindd_getgrent(struct winbindd_cli_state
*state
)
622 struct getent_state
*ent
;
623 struct winbindd_gr
*group_list
= NULL
;
624 int num_groups
, group_list_ndx
= 0, i
, gr_mem_list_len
= 0;
625 char *gr_mem_list
= NULL
;
627 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state
->pid
));
629 /* Check user has enabled this */
631 if (!lp_winbind_enum_groups()) {
632 request_error(state
);
636 num_groups
= MIN(MAX_GETGRENT_GROUPS
, state
->request
.data
.num_entries
);
638 if ((state
->response
.extra_data
= SMB_MALLOC_ARRAY(struct winbindd_gr
, num_groups
)) == NULL
) {
639 request_error(state
);
643 memset(state
->response
.extra_data
, '\0',
644 num_groups
* sizeof(struct winbindd_gr
) );
646 state
->response
.data
.num_entries
= 0;
648 group_list
= (struct winbindd_gr
*)state
->response
.extra_data
;
650 if (!state
->getgrent_initialized
)
651 winbindd_setgrent_internal(state
);
653 if (!(ent
= state
->getgrent_state
)) {
654 request_error(state
);
658 /* Start sending back groups */
660 for (i
= 0; i
< num_groups
; i
++) {
661 struct acct_info
*name_list
= NULL
;
662 fstring domain_group_name
;
668 struct winbindd_domain
*domain
;
670 /* Do we need to fetch another chunk of groups? */
674 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
675 ent
->sam_entry_index
, ent
->num_sam_entries
));
677 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
679 while(ent
&& !get_sam_group_entries(ent
)) {
680 struct getent_state
*next_ent
;
682 DEBUG(10, ("freeing state info for domain %s\n", ent
->domain_name
));
684 /* Free state information for this domain */
686 SAFE_FREE(ent
->sam_entries
);
688 next_ent
= ent
->next
;
689 DLIST_REMOVE(state
->getgrent_state
, ent
);
695 /* No more domains */
701 name_list
= ent
->sam_entries
;
704 find_domain_from_name(ent
->domain_name
))) {
705 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent
->domain_name
));
710 /* Lookup group info */
712 sid_copy(&group_sid
, &domain
->sid
);
713 sid_append_rid(&group_sid
, name_list
[ent
->sam_entry_index
].rid
);
715 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid
,
718 enum SID_NAME_USE type
;
720 DEBUG(10, ("SID %s not in idmap\n",
721 sid_string_static(&group_sid
)));
723 if (!pdb_sid_to_id(&group_sid
, &id
, &type
)) {
724 DEBUG(1, ("could not look up gid for group "
726 name_list
[ent
->sam_entry_index
].acct_name
));
727 ent
->sam_entry_index
++;
731 if ((type
!= SID_NAME_DOM_GRP
) &&
732 (type
!= SID_NAME_ALIAS
) &&
733 (type
!= SID_NAME_WKN_GRP
)) {
734 DEBUG(1, ("Group %s is a %s, not a group\n",
735 sid_type_lookup(type
),
736 name_list
[ent
->sam_entry_index
].acct_name
));
737 ent
->sam_entry_index
++;
743 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid
,
744 (unsigned long)name_list
[ent
->sam_entry_index
].rid
));
746 /* Fill in group entry */
748 fill_domain_username(domain_group_name
, ent
->domain_name
,
749 name_list
[ent
->sam_entry_index
].acct_name
, False
);
751 result
= fill_grent(&group_list
[group_list_ndx
],
753 name_list
[ent
->sam_entry_index
].acct_name
,
756 /* Fill in group membership entry */
760 group_list
[group_list_ndx
].num_gr_mem
= 0;
764 /* Get group membership */
765 if (state
->request
.cmd
== WINBINDD_GETGRLST
) {
768 sid_copy(&member_sid
, &domain
->sid
);
769 sid_append_rid(&member_sid
, name_list
[ent
->sam_entry_index
].rid
);
770 result
= fill_grent_mem(
774 &group_list
[group_list_ndx
].num_gr_mem
,
775 &gr_mem
, &gr_mem_len
);
780 /* Append to group membership list */
781 gr_mem_list
= SMB_REALLOC( gr_mem_list
, gr_mem_list_len
+ gr_mem_len
);
784 DEBUG(0, ("out of memory\n"));
789 DEBUG(10, ("list_len = %d, mem_len = %d\n",
790 gr_mem_list_len
, gr_mem_len
));
792 memcpy(&gr_mem_list
[gr_mem_list_len
], gr_mem
,
797 group_list
[group_list_ndx
].gr_mem_ofs
=
800 gr_mem_list_len
+= gr_mem_len
;
803 ent
->sam_entry_index
++;
805 /* Add group to return list */
809 DEBUG(10, ("adding group num_entries = %d\n",
810 state
->response
.data
.num_entries
));
813 state
->response
.data
.num_entries
++;
815 state
->response
.length
+=
816 sizeof(struct winbindd_gr
);
819 DEBUG(0, ("could not lookup domain group %s\n",
824 /* Copy the list of group memberships to the end of the extra data */
826 if (group_list_ndx
== 0)
829 state
->response
.extra_data
= SMB_REALLOC(
830 state
->response
.extra_data
,
831 group_list_ndx
* sizeof(struct winbindd_gr
) + gr_mem_list_len
);
833 if (!state
->response
.extra_data
) {
834 DEBUG(0, ("out of memory\n"));
836 SAFE_FREE(gr_mem_list
);
837 request_error(state
);
841 memcpy(&((char *)state
->response
.extra_data
)
842 [group_list_ndx
* sizeof(struct winbindd_gr
)],
843 gr_mem_list
, gr_mem_list_len
);
845 state
->response
.length
+= gr_mem_list_len
;
847 DEBUG(10, ("returning %d groups, length = %d\n",
848 group_list_ndx
, gr_mem_list_len
));
854 SAFE_FREE(gr_mem_list
);
856 if (group_list_ndx
> 0)
859 request_error(state
);
862 /* List domain groups without mapping to unix ids */
864 void winbindd_list_groups(struct winbindd_cli_state
*state
)
866 uint32 total_entries
= 0;
867 struct winbindd_domain
*domain
;
868 const char *which_domain
;
869 char *extra_data
= NULL
;
870 unsigned int extra_data_len
= 0, i
;
872 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state
->pid
));
874 /* Ensure null termination */
875 state
->request
.domain_name
[sizeof(state
->request
.domain_name
)-1]='\0';
876 which_domain
= state
->request
.domain_name
;
878 /* Enumerate over trusted domains */
880 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
881 struct getent_state groups
;
883 /* if we have a domain name restricting the request and this
884 one in the list doesn't match, then just bypass the remainder
887 if ( *which_domain
&& !strequal(which_domain
, domain
->name
) )
892 /* Get list of sam groups */
894 fstrcpy(groups
.domain_name
, domain
->name
);
896 get_sam_group_entries(&groups
);
898 if (groups
.num_sam_entries
== 0) {
899 /* this domain is empty or in an error state */
903 /* keep track the of the total number of groups seen so
904 far over all domains */
905 total_entries
+= groups
.num_sam_entries
;
907 /* Allocate some memory for extra data. Note that we limit
908 account names to sizeof(fstring) = 128 characters. */
909 extra_data
= SMB_REALLOC(extra_data
, sizeof(fstring
) * total_entries
);
912 DEBUG(0,("failed to enlarge buffer!\n"));
913 request_error(state
);
917 /* Pack group list into extra data fields */
918 for (i
= 0; i
< groups
.num_sam_entries
; i
++) {
919 char *group_name
= ((struct acct_info
*)
920 groups
.sam_entries
)[i
].acct_name
;
923 fill_domain_username(name
, domain
->name
, group_name
, False
);
924 /* Append to extra data */
925 memcpy(&extra_data
[extra_data_len
], name
,
927 extra_data_len
+= strlen(name
);
928 extra_data
[extra_data_len
++] = ',';
931 SAFE_FREE(groups
.sam_entries
);
934 /* Assign extra_data fields in response structure */
936 extra_data
[extra_data_len
- 1] = '\0';
937 state
->response
.extra_data
= extra_data
;
938 state
->response
.length
+= extra_data_len
;
941 /* No domains may have responded but that's still OK so don't
947 /* Get user supplementary groups. This is much quicker than trying to
948 invert the groups database. We merge the groups from the gids and
949 other_sids info3 fields as trusted domain, universal group
950 memberships, and nested groups (win2k native mode only) are not
951 returned by the getgroups RPC call but are present in the info3. */
953 struct getgroups_state
{
954 struct winbindd_cli_state
*state
;
955 struct winbindd_domain
*domain
;
960 const DOM_SID
*token_sids
;
961 size_t i
, num_token_sids
;
964 size_t num_token_gids
;
967 static void getgroups_usersid_recv(void *private_data
, BOOL success
,
968 const DOM_SID
*sid
, enum SID_NAME_USE type
);
969 static void getgroups_tokensids_recv(void *private_data
, BOOL success
,
970 DOM_SID
*token_sids
, size_t num_token_sids
);
971 static void getgroups_sid2gid_recv(void *private_data
, BOOL success
, gid_t gid
);
973 void winbindd_getgroups(struct winbindd_cli_state
*state
)
975 struct getgroups_state
*s
;
977 /* Ensure null termination */
978 state
->request
.data
.username
979 [sizeof(state
->request
.data
.username
)-1]='\0';
981 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state
->pid
,
982 state
->request
.data
.username
));
984 /* Parse domain and username */
986 s
= TALLOC_P(state
->mem_ctx
, struct getgroups_state
);
988 DEBUG(0, ("talloc failed\n"));
989 request_error(state
);
995 if (!parse_domain_user_talloc(state
->mem_ctx
,
996 state
->request
.data
.username
,
997 &s
->domname
, &s
->username
)) {
998 DEBUG(5, ("Could not parse domain user: %s\n",
999 state
->request
.data
.username
));
1000 request_error(state
);
1004 /* Get info for the domain */
1006 s
->domain
= find_domain_from_name_noinit(s
->domname
);
1008 if (s
->domain
== NULL
) {
1009 DEBUG(7, ("could not find domain entry for domain %s\n",
1011 request_error(state
);
1015 if ( s
->domain
->primary
&& lp_winbind_trusted_domains_only()) {
1016 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
1017 "getgroups() for %s\\%s.\n", s
->domname
,
1019 request_error(state
);
1023 /* Get rid and name type from name. The following costs 1 packet */
1025 winbindd_lookupname_async(state
->mem_ctx
, s
->domname
, s
->username
,
1026 getgroups_usersid_recv
, s
);
1029 static void getgroups_usersid_recv(void *private_data
, BOOL success
,
1030 const DOM_SID
*sid
, enum SID_NAME_USE type
)
1032 struct getgroups_state
*s
= private_data
;
1035 ((type
!= SID_NAME_USER
) && (type
!= SID_NAME_COMPUTER
))) {
1036 request_error(s
->state
);
1040 sid_copy(&s
->user_sid
, sid
);
1042 winbindd_gettoken_async(s
->state
->mem_ctx
, &s
->user_sid
,
1043 getgroups_tokensids_recv
, s
);
1046 static void getgroups_tokensids_recv(void *private_data
, BOOL success
,
1047 DOM_SID
*token_sids
, size_t num_token_sids
)
1049 struct getgroups_state
*s
= private_data
;
1051 /* We need at least the user sid and the primary group in the token,
1052 * otherwise it's an error */
1054 if ((!success
) || (num_token_sids
< 2)) {
1055 request_error(s
->state
);
1059 s
->token_sids
= token_sids
;
1060 s
->num_token_sids
= num_token_sids
;
1063 s
->token_gids
= NULL
;
1064 s
->num_token_gids
= 0;
1066 getgroups_sid2gid_recv(s
, False
, 0);
1069 static void getgroups_sid2gid_recv(void *private_data
, BOOL success
, gid_t gid
)
1071 struct getgroups_state
*s
= private_data
;
1074 add_gid_to_array_unique(NULL
, gid
,
1076 &s
->num_token_gids
);
1078 if (s
->i
< s
->num_token_sids
) {
1079 const DOM_SID
*sid
= &s
->token_sids
[s
->i
];
1082 if (sid_equal(sid
, &s
->user_sid
)) {
1083 getgroups_sid2gid_recv(s
, False
, 0);
1087 winbindd_sid2gid_async(s
->state
->mem_ctx
, sid
,
1088 getgroups_sid2gid_recv
, s
);
1092 s
->state
->response
.data
.num_entries
= s
->num_token_gids
;
1093 s
->state
->response
.extra_data
= s
->token_gids
;
1094 s
->state
->response
.length
+= s
->num_token_gids
* sizeof(gid_t
);
1095 request_ok(s
->state
);
1098 /* Get user supplementary sids. This is equivalent to the
1099 winbindd_getgroups() function but it involves a SID->SIDs mapping
1100 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1101 idmap. This call is designed to be used with applications that need
1102 to do ACL evaluation themselves. Note that the cached info3 data is
1105 this function assumes that the SID that comes in is a user SID. If
1106 you pass in another type of SID then you may get unpredictable
1110 static void getusersids_recv(void *private_data
, BOOL success
, DOM_SID
*sids
,
1113 void winbindd_getusersids(struct winbindd_cli_state
*state
)
1117 /* Ensure null termination */
1118 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1120 user_sid
= TALLOC_P(state
->mem_ctx
, DOM_SID
);
1121 if (user_sid
== NULL
) {
1122 DEBUG(1, ("talloc failed\n"));
1123 request_error(state
);
1127 if (!string_to_sid(user_sid
, state
->request
.data
.sid
)) {
1128 DEBUG(1, ("Could not get convert sid %s from string\n",
1129 state
->request
.data
.sid
));
1130 request_error(state
);
1134 winbindd_gettoken_async(state
->mem_ctx
, user_sid
, getusersids_recv
,
1138 static void getusersids_recv(void *private_data
, BOOL success
, DOM_SID
*sids
,
1141 struct winbindd_cli_state
*state
= private_data
;
1143 unsigned ofs
, ret_size
= 0;
1147 request_error(state
);
1151 /* work out the response size */
1152 for (i
= 0; i
< num_sids
; i
++) {
1153 const char *s
= sid_string_static(&sids
[i
]);
1154 ret_size
+= strlen(s
) + 1;
1157 /* build the reply */
1158 ret
= SMB_MALLOC(ret_size
);
1160 DEBUG(0, ("malloc failed\n"));
1161 request_error(state
);
1165 for (i
= 0; i
< num_sids
; i
++) {
1166 const char *s
= sid_string_static(&sids
[i
]);
1167 safe_strcpy(ret
+ ofs
, s
, ret_size
- ofs
- 1);
1168 ofs
+= strlen(ret
+ofs
) + 1;
1171 /* Send data back to client */
1172 state
->response
.data
.num_entries
= num_sids
;
1173 state
->response
.extra_data
= ret
;
1174 state
->response
.length
+= ret_size
;
1178 void winbindd_getuserdomgroups(struct winbindd_cli_state
*state
)
1181 struct winbindd_domain
*domain
;
1183 /* Ensure null termination */
1184 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1186 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1187 DEBUG(1, ("Could not get convert sid %s from string\n",
1188 state
->request
.data
.sid
));
1189 request_error(state
);
1193 /* Get info for the domain */
1194 if ((domain
= find_domain_from_sid_noinit(&user_sid
)) == NULL
) {
1195 DEBUG(0,("could not find domain entry for sid %s\n",
1196 sid_string_static(&user_sid
)));
1197 request_error(state
);
1201 sendto_domain(state
, domain
);
1204 enum winbindd_result
winbindd_dual_getuserdomgroups(struct winbindd_domain
*domain
,
1205 struct winbindd_cli_state
*state
)
1215 /* Ensure null termination */
1216 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1218 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1219 DEBUG(1, ("Could not get convert sid %s from string\n",
1220 state
->request
.data
.sid
));
1221 return WINBINDD_ERROR
;
1224 status
= domain
->methods
->lookup_usergroups(domain
, state
->mem_ctx
,
1225 &user_sid
, &num_groups
,
1227 if (!NT_STATUS_IS_OK(status
))
1228 return WINBINDD_ERROR
;
1230 if (num_groups
== 0) {
1231 state
->response
.data
.num_entries
= 0;
1232 state
->response
.extra_data
= NULL
;
1236 if (!print_sidlist(NULL
, groups
, num_groups
, &sidstring
, &len
)) {
1237 DEBUG(0, ("malloc failed\n"));
1238 return WINBINDD_ERROR
;
1241 state
->response
.extra_data
= sidstring
;
1242 state
->response
.length
+= len
+1;
1243 state
->response
.data
.num_entries
= num_groups
;