2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
8 Copyright (C) Gerald (Jerry) Carter 2003.
9 Copyright (C) Volker Lendecke 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 extern BOOL opt_nocache
;
32 #define DBGC_CLASS DBGC_WINBIND
34 static void add_member(const char *domain
, const char *user
,
35 char **pp_members
, size_t *p_num_members
)
39 fill_domain_username(name
, domain
, user
, True
);
40 safe_strcat(name
, ",", sizeof(name
)-1);
41 string_append(pp_members
, name
);
45 /**********************************************************************
46 Add member users resulting from sid. Expand if it is a domain group.
47 **********************************************************************/
49 static void add_expanded_sid(const DOM_SID
*sid
, char **pp_members
, size_t *p_num_members
)
53 struct winbindd_domain
*domain
;
56 char *domain_name
= NULL
;
58 enum lsa_SidType type
;
67 TALLOC_CTX
*mem_ctx
= talloc_init("add_expanded_sid");
69 if (mem_ctx
== NULL
) {
70 DEBUG(1, ("talloc_init failed\n"));
74 sid_copy(&dom_sid
, sid
);
75 sid_split_rid(&dom_sid
, &rid
);
77 domain
= find_lookup_domain_from_sid(sid
);
80 DEBUG(3, ("Could not find domain for sid %s\n",
81 sid_string_static(sid
)));
85 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
,
86 &domain_name
, &name
, &type
);
88 if (!NT_STATUS_IS_OK(result
)) {
89 DEBUG(3, ("sid_to_name failed for sid %s\n",
90 sid_string_static(sid
)));
94 DEBUG(10, ("Found name %s, type %d\n", name
, type
));
96 if (type
== SID_NAME_USER
) {
97 add_member(domain_name
, name
, pp_members
, p_num_members
);
101 if (type
!= SID_NAME_DOM_GRP
) {
102 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
107 /* Expand the domain group, this must be done via the target domain */
109 domain
= find_domain_from_sid(sid
);
111 if (domain
== NULL
) {
112 DEBUG(3, ("Could not find domain from SID %s\n",
113 sid_string_static(sid
)));
117 result
= domain
->methods
->lookup_groupmem(domain
, mem_ctx
,
122 if (!NT_STATUS_IS_OK(result
)) {
123 DEBUG(10, ("Could not lookup group members for %s: %s\n",
124 name
, nt_errstr(result
)));
128 for (i
=0; i
<num_names
; i
++) {
129 DEBUG(10, ("Adding group member SID %s\n",
130 sid_string_static(&sid_mem
[i
])));
132 if (types
[i
] != SID_NAME_USER
) {
133 DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
134 "Ignoring.\n", names
[i
], name
));
138 add_member(domain
->name
, names
[i
], pp_members
, p_num_members
);
142 talloc_destroy(mem_ctx
);
146 static BOOL
fill_passdb_alias_grmem(struct winbindd_domain
*domain
,
148 size_t *num_gr_mem
, char **gr_mem
, size_t *gr_mem_len
)
151 size_t i
, num_members
;
157 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid
, &members
,
161 for (i
=0; i
<num_members
; i
++) {
162 add_expanded_sid(&members
[i
], gr_mem
, num_gr_mem
);
165 TALLOC_FREE(members
);
167 if (*gr_mem
!= NULL
) {
170 /* We have at least one member, strip off the last "," */
171 len
= strlen(*gr_mem
);
172 (*gr_mem
)[len
-1] = '\0';
179 /* Fill a grent structure from various other information */
181 static BOOL
fill_grent(struct winbindd_gr
*gr
, const char *dom_name
,
182 const char *gr_name
, gid_t unix_gid
)
184 fstring full_group_name
;
186 fill_domain_username( full_group_name
, dom_name
, gr_name
, True
);
188 gr
->gr_gid
= unix_gid
;
190 /* Group name and password */
192 safe_strcpy(gr
->gr_name
, full_group_name
, sizeof(gr
->gr_name
) - 1);
193 safe_strcpy(gr
->gr_passwd
, "x", sizeof(gr
->gr_passwd
) - 1);
198 /* Fill in the group membership field of a NT group given by group_sid */
200 static BOOL
fill_grent_mem(struct winbindd_domain
*domain
,
201 struct winbindd_cli_state
*state
,
203 enum lsa_SidType group_name_type
,
204 size_t *num_gr_mem
, char **gr_mem
, size_t *gr_mem_len
)
206 DOM_SID
*sid_mem
= NULL
;
207 uint32 num_names
= 0;
208 uint32
*name_types
= NULL
;
209 unsigned int buf_len
= 0, buf_ndx
= 0, i
;
210 char **names
= NULL
, *buf
= NULL
;
217 if (!(mem_ctx
= talloc_init("fill_grent_mem(%s)", domain
->name
)))
220 /* Initialise group membership information */
222 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string
, group_sid
)));
224 /* Initialize with no members */
227 /* HACK ALERT!! This whole routine does not cope with group members
228 * from more than one domain, ie aliases. Thus we have to work it out
229 * ourselves in a special routine. */
231 if (domain
->internal
) {
232 result
= fill_passdb_alias_grmem(domain
, group_sid
,
238 if ( !((group_name_type
==SID_NAME_DOM_GRP
) ||
239 ((group_name_type
==SID_NAME_ALIAS
) && domain
->primary
)) )
241 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
242 sid_to_string(sid_string
, group_sid
), domain
->name
,
247 /* OPTIMIZATION / HACK. */
248 /* If "enum users" is set to false, and the group being looked
249 up is the Domain Users SID: S-1-5-domain-513, then for the
250 list of members check if the querying user is in that group,
251 and if so only return that user as the gr_mem array.
252 We can change this to a different parameter than "enum users"
253 if neccessaey, or parameterize the group list we do this for. */
255 sid_peek_rid( group_sid
, &group_rid
);
256 if (!lp_winbind_enum_users() && group_rid
== DOMAIN_GROUP_RID_USERS
) {
257 DOM_SID querying_user_sid
;
258 DOM_SID
*pquerying_user_sid
= NULL
;
259 uint32 num_groups
= 0;
260 DOM_SID
*user_sids
= NULL
;
261 BOOL u_in_group
= False
;
263 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
264 sid_to_string(sid_string
, group_sid
), domain
->name
));
267 uid_t ret_uid
= (uid_t
)-1;
268 if (sys_getpeereid(state
->sock
, &ret_uid
)==0) {
269 /* We know who's asking - look up their SID if
270 it's one we've mapped before. */
271 status
= idmap_uid_to_sid(&querying_user_sid
, ret_uid
);
272 if (NT_STATUS_IS_OK(status
)) {
273 pquerying_user_sid
= &querying_user_sid
;
274 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
275 (unsigned int)ret_uid
,
276 sid_to_string(sid_string
, pquerying_user_sid
) ));
281 /* Only look up if it was a winbindd user in this domain. */
282 if (pquerying_user_sid
&&
283 (sid_compare_domain(pquerying_user_sid
, &domain
->sid
) == 0)) {
285 DEBUG(10,("fill_grent_mem: querying user = %s\n",
286 sid_to_string(sid_string
, pquerying_user_sid
) ));
288 status
= domain
->methods
->lookup_usergroups(domain
,
293 if (!NT_STATUS_IS_OK(status
)) {
294 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
295 "for sid %s in domain %s (error: %s)\n",
296 sid_to_string(sid_string
, pquerying_user_sid
),
302 for (i
= 0; i
< num_groups
; i
++) {
303 if (sid_equal(group_sid
, &user_sids
[i
])) {
304 /* User is in Domain Users, add their name
305 as the only group member. */
314 char *domainname
= NULL
;
315 char *username
= NULL
;
317 enum lsa_SidType type
;
319 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
320 sid_to_string(sid_string
, pquerying_user_sid
), domain
->name
));
322 status
= domain
->methods
->sid_to_name(domain
, mem_ctx
,
327 if (!NT_STATUS_IS_OK(status
)) {
328 DEBUG(1, ("could not lookup username for user "
329 "sid %s in domain %s (error: %s)\n",
330 sid_to_string(sid_string
, pquerying_user_sid
),
335 fill_domain_username(name
, domain
->name
, username
, True
);
338 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
339 DEBUG(1, ("out of memory\n"));
342 memcpy(buf
, name
, buf_len
);
344 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
345 name
, domain
->name
));
347 /* user is the only member */
352 *gr_mem_len
= buf_len
;
354 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem
,
355 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
360 /* Lookup group members */
361 status
= domain
->methods
->lookup_groupmem(domain
, mem_ctx
, group_sid
, &num_names
,
362 &sid_mem
, &names
, &name_types
);
363 if (!NT_STATUS_IS_OK(status
)) {
364 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
365 sid_to_string(sid_string
, group_sid
), domain
->name
, nt_errstr(status
)));
369 DEBUG(10, ("looked up %d names\n", num_names
));
371 if (DEBUGLEVEL
>= 10) {
372 for (i
= 0; i
< num_names
; i
++)
373 DEBUG(10, ("\t%20s %s %d\n", names
[i
],
374 sid_string_static(&sid_mem
[i
]),
378 /* Add members to list */
382 for (i
= 0; i
< num_names
; i
++) {
389 DEBUG(10, ("processing name %s\n", the_name
));
391 /* FIXME: need to cope with groups within groups. These
392 occur in Universal groups on a Windows 2000 native mode
395 /* make sure to allow machine accounts */
397 if (name_types
[i
] != SID_NAME_USER
&& name_types
[i
] != SID_NAME_COMPUTER
) {
398 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name
, sid_type_lookup(name_types
[i
])));
402 /* Append domain name */
404 fill_domain_username(name
, domain
->name
, the_name
, True
);
408 /* Add to list or calculate buffer length */
411 buf_len
+= len
+ 1; /* List is comma separated */
413 DEBUG(10, ("buf_len + %d = %d\n", len
+ 1, buf_len
));
415 DEBUG(10, ("appending %s at ndx %d\n", name
, buf_ndx
));
416 safe_strcpy(&buf
[buf_ndx
], name
, len
);
423 /* Allocate buffer */
425 if (!buf
&& buf_len
!= 0) {
426 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
427 DEBUG(1, ("out of memory\n"));
431 memset(buf
, 0, buf_len
);
435 if (buf
&& buf_ndx
> 0) {
436 buf
[buf_ndx
- 1] = '\0';
440 *gr_mem_len
= buf_len
;
442 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem
,
443 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
448 talloc_destroy(mem_ctx
);
450 DEBUG(10, ("fill_grent_mem returning %d\n", result
));
455 /* Return a group structure from a group name */
457 void winbindd_getgrnam(struct winbindd_cli_state
*state
)
459 DOM_SID group_sid
, tmp_sid
;
461 struct winbindd_domain
*domain
;
462 enum lsa_SidType name_type
;
463 fstring name_domain
, name_group
;
471 /* Ensure null termination */
472 state
->request
.data
.groupname
[sizeof(state
->request
.data
.groupname
)-1]='\0';
474 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state
->pid
,
475 state
->request
.data
.groupname
));
477 /* Parse domain and groupname */
479 memset(name_group
, 0, sizeof(fstring
));
481 tmp
= state
->request
.data
.groupname
;
483 name_domain
[0] = '\0';
484 name_group
[0] = '\0';
486 parse_domain_user(tmp
, name_domain
, name_group
);
488 /* if no domain or our local domain and no local tdb group, default to
489 * our local domain for aliases */
491 if ( !*name_domain
|| strequal(name_domain
, get_global_sam_name()) ) {
492 fstrcpy(name_domain
, get_global_sam_name());
495 /* Get info for the domain */
497 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
498 DEBUG(3, ("could not get domain sid for domain %s\n",
500 request_error(state
);
503 /* should we deal with users for our domain? */
505 if ( lp_winbind_trusted_domains_only() && domain
->primary
) {
506 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
507 "getgrnam() for %s\\%s.\n", name_domain
, name_group
));
508 request_error(state
);
512 /* Get rid and name type from name */
514 ws_name_replace( name_group
, WB_REPLACE_CHAR
);
516 if (!winbindd_lookup_sid_by_name(state
->mem_ctx
, domain
, domain
->name
,
517 name_group
, &group_sid
, &name_type
)) {
518 DEBUG(1, ("group %s in domain %s does not exist\n",
519 name_group
, name_domain
));
520 request_error(state
);
524 if ( !((name_type
==SID_NAME_DOM_GRP
) ||
525 ((name_type
==SID_NAME_ALIAS
) && domain
->primary
) ||
526 ((name_type
==SID_NAME_ALIAS
) && domain
->internal
) ||
527 ((name_type
==SID_NAME_WKN_GRP
) && domain
->internal
)) )
529 DEBUG(1, ("name '%s' is not a local, domain or builtin "
530 "group: %d\n", name_group
, name_type
));
531 request_error(state
);
535 /* Make sure that the group SID is within the domain of the
538 sid_copy( &tmp_sid
, &group_sid
);
539 sid_split_rid( &tmp_sid
, &grp_rid
);
540 if ( !sid_equal( &tmp_sid
, &domain
->sid
) ) {
541 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
542 state
->request
.data
.groupname
, sid_string_static(&group_sid
)));
543 request_error(state
);
549 /* Try to get the GID */
551 status
= idmap_sid_to_gid(&group_sid
, &gid
);
553 if (NT_STATUS_IS_OK(status
)) {
557 /* Maybe it's one of our aliases in passdb */
559 if (pdb_sid_to_id(&group_sid
, &id
, &name_type
) &&
560 ((name_type
== SID_NAME_ALIAS
) ||
561 (name_type
== SID_NAME_WKN_GRP
))) {
566 DEBUG(1, ("error converting unix gid to sid\n"));
567 request_error(state
);
572 if (!fill_grent(&state
->response
.data
.gr
, name_domain
,
574 !fill_grent_mem(domain
, state
, &group_sid
, name_type
,
576 &gr_mem
, &gr_mem_len
)) {
577 request_error(state
);
581 state
->response
.data
.gr
.num_gr_mem
= (uint32
)num_gr_mem
;
583 /* Group membership lives at start of extra data */
585 state
->response
.data
.gr
.gr_mem_ofs
= 0;
587 state
->response
.length
+= gr_mem_len
;
588 state
->response
.extra_data
.data
= gr_mem
;
592 static void getgrgid_got_sid(struct winbindd_cli_state
*state
, DOM_SID group_sid
)
594 struct winbindd_domain
*domain
;
595 enum lsa_SidType name_type
;
602 /* Get name from sid */
604 if (!winbindd_lookup_name_by_sid(state
->mem_ctx
, &group_sid
, &dom_name
,
605 &group_name
, &name_type
)) {
606 DEBUG(1, ("could not lookup sid\n"));
607 request_error(state
);
608 TALLOC_FREE(group_name
);
609 TALLOC_FREE(dom_name
);
613 /* Fill in group structure */
615 domain
= find_domain_from_sid_noinit(&group_sid
);
618 DEBUG(1,("Can't find domain from sid\n"));
619 request_error(state
);
620 TALLOC_FREE(group_name
);
621 TALLOC_FREE(dom_name
);
625 if ( !((name_type
==SID_NAME_DOM_GRP
) ||
626 ((name_type
==SID_NAME_ALIAS
) && domain
->primary
) ||
627 ((name_type
==SID_NAME_ALIAS
) && domain
->internal
)) )
629 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
630 group_name
, name_type
));
631 request_error(state
);
632 TALLOC_FREE(group_name
);
633 TALLOC_FREE(dom_name
);
637 if (!fill_grent(&state
->response
.data
.gr
, dom_name
, group_name
,
638 state
->request
.data
.gid
) ||
639 !fill_grent_mem(domain
, state
, &group_sid
, name_type
,
641 &gr_mem
, &gr_mem_len
)) {
642 request_error(state
);
643 TALLOC_FREE(group_name
);
644 TALLOC_FREE(dom_name
);
648 state
->response
.data
.gr
.num_gr_mem
= (uint32
)num_gr_mem
;
650 /* Group membership lives at start of extra data */
652 state
->response
.data
.gr
.gr_mem_ofs
= 0;
654 state
->response
.length
+= gr_mem_len
;
655 state
->response
.extra_data
.data
= gr_mem
;
657 TALLOC_FREE(group_name
);
658 TALLOC_FREE(dom_name
);
663 static void getgrgid_recv(void *private_data
, BOOL success
, const char *sid
)
665 struct winbindd_cli_state
*state
= talloc_get_type_abort(private_data
, struct winbindd_cli_state
);
666 enum lsa_SidType name_type
;
670 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
671 (unsigned long)(state
->request
.data
.gid
), sid
));
673 string_to_sid(&group_sid
, sid
);
674 getgrgid_got_sid(state
, group_sid
);
678 /* Ok, this might be "ours", i.e. an alias */
679 if (pdb_gid_to_sid(state
->request
.data
.gid
, &group_sid
) &&
680 lookup_sid(state
->mem_ctx
, &group_sid
, NULL
, NULL
, &name_type
) &&
681 (name_type
== SID_NAME_ALIAS
)) {
682 /* Hey, got an alias */
683 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
684 (unsigned long)(state
->request
.data
.gid
), sid
));
685 getgrgid_got_sid(state
, group_sid
);
689 DEBUG(1, ("could not convert gid %lu to sid\n",
690 (unsigned long)state
->request
.data
.gid
));
691 request_error(state
);
694 /* Return a group structure from a gid number */
695 void winbindd_getgrgid(struct winbindd_cli_state
*state
)
697 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state
->pid
,
698 (unsigned long)state
->request
.data
.gid
));
700 /* always use the async interface */
701 winbindd_gid2sid_async(state
->mem_ctx
, state
->request
.data
.gid
, getgrgid_recv
, state
);
705 * set/get/endgrent functions
708 /* "Rewind" file pointer for group database enumeration */
710 static BOOL
winbindd_setgrent_internal(struct winbindd_cli_state
*state
)
712 struct winbindd_domain
*domain
;
714 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state
->pid
));
716 /* Check user has enabled this */
718 if (!lp_winbind_enum_groups()) {
722 /* Free old static data if it exists */
724 if (state
->getgrent_state
!= NULL
) {
725 free_getent_state(state
->getgrent_state
);
726 state
->getgrent_state
= NULL
;
729 /* Create sam pipes for each domain we know about */
731 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
732 struct getent_state
*domain_state
;
734 /* Create a state record for this domain */
736 /* don't add our domaina if we are a PDC or if we
737 are a member of a Samba domain */
739 if ( lp_winbind_trusted_domains_only() && domain
->primary
)
745 if ((domain_state
= SMB_MALLOC_P(struct getent_state
)) == NULL
) {
746 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
750 ZERO_STRUCTP(domain_state
);
752 fstrcpy(domain_state
->domain_name
, domain
->name
);
754 /* Add to list of open domains */
756 DLIST_ADD(state
->getgrent_state
, domain_state
);
759 state
->getgrent_initialized
= True
;
763 void winbindd_setgrent(struct winbindd_cli_state
*state
)
765 if (winbindd_setgrent_internal(state
)) {
768 request_error(state
);
772 /* Close file pointer to ntdom group database */
774 void winbindd_endgrent(struct winbindd_cli_state
*state
)
776 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state
->pid
));
778 free_getent_state(state
->getgrent_state
);
779 state
->getgrent_initialized
= False
;
780 state
->getgrent_state
= NULL
;
784 /* Get the list of domain groups and domain aliases for a domain. We fill in
785 the sam_entries and num_sam_entries fields with domain group information.
786 The dispinfo_ndx field is incremented to the index of the next group to
787 fetch. Return True if some groups were returned, False otherwise. */
789 static BOOL
get_sam_group_entries(struct getent_state
*ent
)
793 struct acct_info
*name_list
= NULL
;
796 struct acct_info
*sam_grp_entries
= NULL
;
797 struct winbindd_domain
*domain
;
799 if (ent
->got_sam_entries
)
802 if (!(mem_ctx
= talloc_init("get_sam_group_entries(%s)",
803 ent
->domain_name
))) {
804 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
808 /* Free any existing group info */
810 SAFE_FREE(ent
->sam_entries
);
811 ent
->num_sam_entries
= 0;
812 ent
->got_sam_entries
= True
;
814 /* Enumerate domain groups */
818 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
819 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent
->domain_name
));
823 /* always get the domain global groups */
825 status
= domain
->methods
->enum_dom_groups(domain
, mem_ctx
, &num_entries
, &sam_grp_entries
);
827 if (!NT_STATUS_IS_OK(status
)) {
828 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status
)));
833 /* Copy entries into return buffer */
836 if ( !(name_list
= SMB_MALLOC_ARRAY(struct acct_info
, num_entries
)) ) {
837 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
842 memcpy( name_list
, sam_grp_entries
, num_entries
* sizeof(struct acct_info
) );
845 ent
->num_sam_entries
= num_entries
;
847 /* get the domain local groups if we are a member of a native win2k domain
848 and are not using LDAP to get the groups */
850 if ( ( lp_security() != SEC_ADS
&& domain
->native_mode
851 && domain
->primary
) || domain
->internal
)
853 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
854 domain
->native_mode
? "Native Mode 2k":"BUILTIN or local"));
856 status
= domain
->methods
->enum_local_groups(domain
, mem_ctx
, &num_entries
, &sam_grp_entries
);
858 if ( !NT_STATUS_IS_OK(status
) ) {
859 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
863 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries
));
865 /* Copy entries into return buffer */
868 if ( !(name_list
= SMB_REALLOC_ARRAY( name_list
, struct acct_info
, ent
->num_sam_entries
+num_entries
)) )
870 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
876 memcpy( &name_list
[ent
->num_sam_entries
], sam_grp_entries
,
877 num_entries
* sizeof(struct acct_info
) );
880 ent
->num_sam_entries
+= num_entries
;
884 /* Fill in remaining fields */
886 ent
->sam_entries
= name_list
;
887 ent
->sam_entry_index
= 0;
889 result
= (ent
->num_sam_entries
> 0);
892 talloc_destroy(mem_ctx
);
897 /* Fetch next group entry from ntdom database */
899 #define MAX_GETGRENT_GROUPS 500
901 void winbindd_getgrent(struct winbindd_cli_state
*state
)
903 struct getent_state
*ent
;
904 struct winbindd_gr
*group_list
= NULL
;
905 int num_groups
, group_list_ndx
, gr_mem_list_len
= 0;
906 char *gr_mem_list
= NULL
;
908 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state
->pid
));
910 /* Check user has enabled this */
912 if (!lp_winbind_enum_groups()) {
913 request_error(state
);
917 num_groups
= MIN(MAX_GETGRENT_GROUPS
, state
->request
.data
.num_entries
);
919 if (num_groups
== 0) {
920 request_error(state
);
924 if ((state
->response
.extra_data
.data
= SMB_MALLOC_ARRAY(struct winbindd_gr
, num_groups
)) == NULL
) {
925 request_error(state
);
929 memset(state
->response
.extra_data
.data
, '\0',
930 num_groups
* sizeof(struct winbindd_gr
) );
932 state
->response
.data
.num_entries
= 0;
934 group_list
= (struct winbindd_gr
*)state
->response
.extra_data
.data
;
936 if (!state
->getgrent_initialized
)
937 winbindd_setgrent_internal(state
);
939 if (!(ent
= state
->getgrent_state
)) {
940 request_error(state
);
944 /* Start sending back groups */
946 for (group_list_ndx
= 0; group_list_ndx
< num_groups
; ) {
947 struct acct_info
*name_list
= NULL
;
948 fstring domain_group_name
;
954 struct winbindd_domain
*domain
;
956 /* Do we need to fetch another chunk of groups? */
960 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
961 ent
->sam_entry_index
, ent
->num_sam_entries
));
963 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
965 while(ent
&& !get_sam_group_entries(ent
)) {
966 struct getent_state
*next_ent
;
968 DEBUG(10, ("freeing state info for domain %s\n", ent
->domain_name
));
970 /* Free state information for this domain */
972 SAFE_FREE(ent
->sam_entries
);
974 next_ent
= ent
->next
;
975 DLIST_REMOVE(state
->getgrent_state
, ent
);
981 /* No more domains */
987 name_list
= (struct acct_info
*)ent
->sam_entries
;
990 find_domain_from_name(ent
->domain_name
))) {
991 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent
->domain_name
));
996 /* Lookup group info */
998 sid_copy(&group_sid
, &domain
->sid
);
999 sid_append_rid(&group_sid
, name_list
[ent
->sam_entry_index
].rid
);
1001 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid
, &group_gid
))) {
1003 enum lsa_SidType type
;
1005 DEBUG(10, ("SID %s not in idmap\n",
1006 sid_string_static(&group_sid
)));
1008 if (!pdb_sid_to_id(&group_sid
, &id
, &type
)) {
1009 DEBUG(1, ("could not look up gid for group "
1011 name_list
[ent
->sam_entry_index
].acct_name
));
1012 ent
->sam_entry_index
++;
1016 if ((type
!= SID_NAME_DOM_GRP
) &&
1017 (type
!= SID_NAME_ALIAS
) &&
1018 (type
!= SID_NAME_WKN_GRP
)) {
1019 DEBUG(1, ("Group %s is a %s, not a group\n",
1020 sid_type_lookup(type
),
1021 name_list
[ent
->sam_entry_index
].acct_name
));
1022 ent
->sam_entry_index
++;
1028 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid
,
1029 (unsigned long)name_list
[ent
->sam_entry_index
].rid
));
1031 /* Fill in group entry */
1033 fill_domain_username(domain_group_name
, ent
->domain_name
,
1034 name_list
[ent
->sam_entry_index
].acct_name
, True
);
1036 result
= fill_grent(&group_list
[group_list_ndx
],
1038 name_list
[ent
->sam_entry_index
].acct_name
,
1041 /* Fill in group membership entry */
1044 size_t num_gr_mem
= 0;
1046 group_list
[group_list_ndx
].num_gr_mem
= 0;
1050 /* Get group membership */
1051 if (state
->request
.cmd
== WINBINDD_GETGRLST
) {
1054 sid_copy(&member_sid
, &domain
->sid
);
1055 sid_append_rid(&member_sid
, name_list
[ent
->sam_entry_index
].rid
);
1056 result
= fill_grent_mem(
1062 &gr_mem
, &gr_mem_len
);
1064 group_list
[group_list_ndx
].num_gr_mem
= (uint32
)num_gr_mem
;
1069 /* Append to group membership list */
1070 gr_mem_list
= (char *)SMB_REALLOC(
1071 gr_mem_list
, gr_mem_list_len
+ gr_mem_len
);
1073 if (!gr_mem_list
&& (group_list
[group_list_ndx
].num_gr_mem
!= 0)) {
1074 DEBUG(0, ("out of memory\n"));
1075 gr_mem_list_len
= 0;
1079 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1080 gr_mem_list_len
, (unsigned int)gr_mem_len
));
1082 memcpy(&gr_mem_list
[gr_mem_list_len
], gr_mem
,
1087 group_list
[group_list_ndx
].gr_mem_ofs
=
1090 gr_mem_list_len
+= gr_mem_len
;
1093 ent
->sam_entry_index
++;
1095 /* Add group to return list */
1099 DEBUG(10, ("adding group num_entries = %d\n",
1100 state
->response
.data
.num_entries
));
1103 state
->response
.data
.num_entries
++;
1105 state
->response
.length
+=
1106 sizeof(struct winbindd_gr
);
1109 DEBUG(0, ("could not lookup domain group %s\n",
1110 domain_group_name
));
1114 /* Copy the list of group memberships to the end of the extra data */
1116 if (group_list_ndx
== 0)
1119 state
->response
.extra_data
.data
= SMB_REALLOC(
1120 state
->response
.extra_data
.data
,
1121 group_list_ndx
* sizeof(struct winbindd_gr
) + gr_mem_list_len
);
1123 if (!state
->response
.extra_data
.data
) {
1124 DEBUG(0, ("out of memory\n"));
1126 SAFE_FREE(gr_mem_list
);
1127 request_error(state
);
1131 memcpy(&((char *)state
->response
.extra_data
.data
)
1132 [group_list_ndx
* sizeof(struct winbindd_gr
)],
1133 gr_mem_list
, gr_mem_list_len
);
1135 state
->response
.length
+= gr_mem_list_len
;
1137 DEBUG(10, ("returning %d groups, length = %d\n",
1138 group_list_ndx
, gr_mem_list_len
));
1140 /* Out of domains */
1144 SAFE_FREE(gr_mem_list
);
1146 if (group_list_ndx
> 0)
1149 request_error(state
);
1152 /* List domain groups without mapping to unix ids */
1154 void winbindd_list_groups(struct winbindd_cli_state
*state
)
1156 uint32 total_entries
= 0;
1157 struct winbindd_domain
*domain
;
1158 const char *which_domain
;
1159 char *extra_data
= NULL
;
1160 unsigned int extra_data_len
= 0, i
;
1162 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state
->pid
));
1164 /* Ensure null termination */
1165 state
->request
.domain_name
[sizeof(state
->request
.domain_name
)-1]='\0';
1166 which_domain
= state
->request
.domain_name
;
1168 /* Enumerate over trusted domains */
1170 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
1171 struct getent_state groups
;
1173 /* if we have a domain name restricting the request and this
1174 one in the list doesn't match, then just bypass the remainder
1177 if ( *which_domain
&& !strequal(which_domain
, domain
->name
) )
1180 ZERO_STRUCT(groups
);
1182 /* Get list of sam groups */
1184 fstrcpy(groups
.domain_name
, domain
->name
);
1186 get_sam_group_entries(&groups
);
1188 if (groups
.num_sam_entries
== 0) {
1189 /* this domain is empty or in an error state */
1193 /* keep track the of the total number of groups seen so
1194 far over all domains */
1195 total_entries
+= groups
.num_sam_entries
;
1197 /* Allocate some memory for extra data. Note that we limit
1198 account names to sizeof(fstring) = 128 characters. */
1199 extra_data
= (char *)SMB_REALLOC(
1200 extra_data
, sizeof(fstring
) * total_entries
);
1203 DEBUG(0,("failed to enlarge buffer!\n"));
1204 request_error(state
);
1208 /* Pack group list into extra data fields */
1209 for (i
= 0; i
< groups
.num_sam_entries
; i
++) {
1210 char *group_name
= ((struct acct_info
*)
1211 groups
.sam_entries
)[i
].acct_name
;
1214 fill_domain_username(name
, domain
->name
, group_name
, True
);
1215 /* Append to extra data */
1216 memcpy(&extra_data
[extra_data_len
], name
,
1218 extra_data_len
+= strlen(name
);
1219 extra_data
[extra_data_len
++] = ',';
1222 SAFE_FREE(groups
.sam_entries
);
1225 /* Assign extra_data fields in response structure */
1227 extra_data
[extra_data_len
- 1] = '\0';
1228 state
->response
.extra_data
.data
= extra_data
;
1229 state
->response
.length
+= extra_data_len
;
1232 /* No domains may have responded but that's still OK so don't
1238 /* Get user supplementary groups. This is much quicker than trying to
1239 invert the groups database. We merge the groups from the gids and
1240 other_sids info3 fields as trusted domain, universal group
1241 memberships, and nested groups (win2k native mode only) are not
1242 returned by the getgroups RPC call but are present in the info3. */
1244 struct getgroups_state
{
1245 struct winbindd_cli_state
*state
;
1246 struct winbindd_domain
*domain
;
1251 const DOM_SID
*token_sids
;
1252 size_t i
, num_token_sids
;
1255 size_t num_token_gids
;
1258 static void getgroups_usersid_recv(void *private_data
, BOOL success
,
1259 const DOM_SID
*sid
, enum lsa_SidType type
);
1260 static void getgroups_tokensids_recv(void *private_data
, BOOL success
,
1261 DOM_SID
*token_sids
, size_t num_token_sids
);
1262 static void getgroups_sid2gid_recv(void *private_data
, BOOL success
, gid_t gid
);
1264 void winbindd_getgroups(struct winbindd_cli_state
*state
)
1266 struct getgroups_state
*s
;
1268 /* Ensure null termination */
1269 state
->request
.data
.username
1270 [sizeof(state
->request
.data
.username
)-1]='\0';
1272 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state
->pid
,
1273 state
->request
.data
.username
));
1275 /* Parse domain and username */
1277 s
= TALLOC_P(state
->mem_ctx
, struct getgroups_state
);
1279 DEBUG(0, ("talloc failed\n"));
1280 request_error(state
);
1286 ws_name_return( state
->request
.data
.username
, WB_REPLACE_CHAR
);
1288 if (!parse_domain_user_talloc(state
->mem_ctx
,
1289 state
->request
.data
.username
,
1290 &s
->domname
, &s
->username
)) {
1291 DEBUG(5, ("Could not parse domain user: %s\n",
1292 state
->request
.data
.username
));
1294 /* error out if we do not have nested group support */
1296 if ( !lp_winbind_nested_groups() ) {
1297 request_error(state
);
1301 s
->domname
= talloc_strdup( state
->mem_ctx
, get_global_sam_name() );
1302 s
->username
= talloc_strdup( state
->mem_ctx
, state
->request
.data
.username
);
1305 /* Get info for the domain */
1307 s
->domain
= find_domain_from_name_noinit(s
->domname
);
1309 if (s
->domain
== NULL
) {
1310 DEBUG(7, ("could not find domain entry for domain %s\n",
1312 request_error(state
);
1316 if ( s
->domain
->primary
&& lp_winbind_trusted_domains_only()) {
1317 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1318 "getgroups() for %s\\%s.\n", s
->domname
,
1320 request_error(state
);
1324 /* Get rid and name type from name. The following costs 1 packet */
1326 winbindd_lookupname_async(state
->mem_ctx
, s
->domname
, s
->username
,
1327 getgroups_usersid_recv
, s
);
1330 static void getgroups_usersid_recv(void *private_data
, BOOL success
,
1331 const DOM_SID
*sid
, enum lsa_SidType type
)
1333 struct getgroups_state
*s
=
1334 (struct getgroups_state
*)private_data
;
1337 ((type
!= SID_NAME_USER
) && (type
!= SID_NAME_COMPUTER
))) {
1338 request_error(s
->state
);
1342 sid_copy(&s
->user_sid
, sid
);
1344 winbindd_gettoken_async(s
->state
->mem_ctx
, &s
->user_sid
,
1345 getgroups_tokensids_recv
, s
);
1348 static void getgroups_tokensids_recv(void *private_data
, BOOL success
,
1349 DOM_SID
*token_sids
, size_t num_token_sids
)
1351 struct getgroups_state
*s
=
1352 (struct getgroups_state
*)private_data
;
1354 /* We need at least the user sid and the primary group in the token,
1355 * otherwise it's an error */
1357 if ((!success
) || (num_token_sids
< 2)) {
1358 request_error(s
->state
);
1362 s
->token_sids
= token_sids
;
1363 s
->num_token_sids
= num_token_sids
;
1366 s
->token_gids
= NULL
;
1367 s
->num_token_gids
= 0;
1369 getgroups_sid2gid_recv(s
, False
, 0);
1372 static void getgroups_sid2gid_recv(void *private_data
, BOOL success
, gid_t gid
)
1374 struct getgroups_state
*s
=
1375 (struct getgroups_state
*)private_data
;
1378 if (!add_gid_to_array_unique(s
->state
->mem_ctx
, gid
,
1380 &s
->num_token_gids
)) {
1385 if (s
->i
< s
->num_token_sids
) {
1386 const DOM_SID
*sid
= &s
->token_sids
[s
->i
];
1389 if (sid_equal(sid
, &s
->user_sid
)) {
1390 getgroups_sid2gid_recv(s
, False
, 0);
1394 winbindd_sid2gid_async(s
->state
->mem_ctx
, sid
,
1395 getgroups_sid2gid_recv
, s
);
1399 s
->state
->response
.data
.num_entries
= s
->num_token_gids
;
1400 /* s->token_gids are talloced */
1401 s
->state
->response
.extra_data
.data
= smb_xmemdup(s
->token_gids
, s
->num_token_gids
* sizeof(gid_t
));
1402 s
->state
->response
.length
+= s
->num_token_gids
* sizeof(gid_t
);
1403 request_ok(s
->state
);
1406 /* Get user supplementary sids. This is equivalent to the
1407 winbindd_getgroups() function but it involves a SID->SIDs mapping
1408 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1409 idmap. This call is designed to be used with applications that need
1410 to do ACL evaluation themselves. Note that the cached info3 data is
1413 this function assumes that the SID that comes in is a user SID. If
1414 you pass in another type of SID then you may get unpredictable
1418 static void getusersids_recv(void *private_data
, BOOL success
, DOM_SID
*sids
,
1421 void winbindd_getusersids(struct winbindd_cli_state
*state
)
1425 /* Ensure null termination */
1426 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1428 user_sid
= TALLOC_P(state
->mem_ctx
, DOM_SID
);
1429 if (user_sid
== NULL
) {
1430 DEBUG(1, ("talloc failed\n"));
1431 request_error(state
);
1435 if (!string_to_sid(user_sid
, state
->request
.data
.sid
)) {
1436 DEBUG(1, ("Could not get convert sid %s from string\n",
1437 state
->request
.data
.sid
));
1438 request_error(state
);
1442 winbindd_gettoken_async(state
->mem_ctx
, user_sid
, getusersids_recv
,
1446 static void getusersids_recv(void *private_data
, BOOL success
, DOM_SID
*sids
,
1449 struct winbindd_cli_state
*state
=
1450 (struct winbindd_cli_state
*)private_data
;
1452 unsigned ofs
, ret_size
= 0;
1456 request_error(state
);
1460 /* work out the response size */
1461 for (i
= 0; i
< num_sids
; i
++) {
1462 const char *s
= sid_string_static(&sids
[i
]);
1463 ret_size
+= strlen(s
) + 1;
1466 /* build the reply */
1467 ret
= (char *)SMB_MALLOC(ret_size
);
1469 DEBUG(0, ("malloc failed\n"));
1470 request_error(state
);
1474 for (i
= 0; i
< num_sids
; i
++) {
1475 const char *s
= sid_string_static(&sids
[i
]);
1476 safe_strcpy(ret
+ ofs
, s
, ret_size
- ofs
- 1);
1477 ofs
+= strlen(ret
+ofs
) + 1;
1480 /* Send data back to client */
1481 state
->response
.data
.num_entries
= num_sids
;
1482 state
->response
.extra_data
.data
= ret
;
1483 state
->response
.length
+= ret_size
;
1487 void winbindd_getuserdomgroups(struct winbindd_cli_state
*state
)
1490 struct winbindd_domain
*domain
;
1492 /* Ensure null termination */
1493 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1495 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1496 DEBUG(1, ("Could not get convert sid %s from string\n",
1497 state
->request
.data
.sid
));
1498 request_error(state
);
1502 /* Get info for the domain */
1503 if ((domain
= find_domain_from_sid_noinit(&user_sid
)) == NULL
) {
1504 DEBUG(0,("could not find domain entry for sid %s\n",
1505 sid_string_static(&user_sid
)));
1506 request_error(state
);
1510 sendto_domain(state
, domain
);
1513 enum winbindd_result
winbindd_dual_getuserdomgroups(struct winbindd_domain
*domain
,
1514 struct winbindd_cli_state
*state
)
1524 /* Ensure null termination */
1525 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1527 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1528 DEBUG(1, ("Could not get convert sid %s from string\n",
1529 state
->request
.data
.sid
));
1530 return WINBINDD_ERROR
;
1533 status
= domain
->methods
->lookup_usergroups(domain
, state
->mem_ctx
,
1534 &user_sid
, &num_groups
,
1536 if (!NT_STATUS_IS_OK(status
))
1537 return WINBINDD_ERROR
;
1539 if (num_groups
== 0) {
1540 state
->response
.data
.num_entries
= 0;
1541 state
->response
.extra_data
.data
= NULL
;
1545 if (!print_sidlist(state
->mem_ctx
, groups
, num_groups
, &sidstring
, &len
)) {
1546 DEBUG(0, ("talloc failed\n"));
1547 return WINBINDD_ERROR
;
1550 state
->response
.extra_data
.data
= SMB_STRDUP(sidstring
);
1551 if (!state
->response
.extra_data
.data
) {
1552 return WINBINDD_ERROR
;
1554 state
->response
.length
+= len
+1;
1555 state
->response
.data
.num_entries
= num_groups
;