2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
8 Copyright (C) Gerald (Jerry) Carter 2003.
9 Copyright (C) Volker Lendecke 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 extern BOOL opt_nocache
;
32 #define DBGC_CLASS DBGC_WINBIND
34 /***************************************************************
35 Empty static struct for negative caching.
36 ****************************************************************/
38 /* Fill a grent structure from various other information */
40 static BOOL
fill_grent(struct winbindd_gr
*gr
, const char *dom_name
,
41 const char *gr_name
, gid_t unix_gid
)
43 fstring full_group_name
;
45 fill_domain_username( full_group_name
, dom_name
, gr_name
, True
);
47 gr
->gr_gid
= unix_gid
;
49 /* Group name and password */
51 safe_strcpy(gr
->gr_name
, full_group_name
, sizeof(gr
->gr_name
) - 1);
52 safe_strcpy(gr
->gr_passwd
, "x", sizeof(gr
->gr_passwd
) - 1);
57 /* Fill in the group membership field of a NT group given by group_sid */
59 static BOOL
fill_grent_mem(struct winbindd_domain
*domain
,
60 struct winbindd_cli_state
*state
,
62 enum SID_NAME_USE group_name_type
,
63 size_t *num_gr_mem
, char **gr_mem
, size_t *gr_mem_len
)
65 DOM_SID
*sid_mem
= NULL
;
67 uint32
*name_types
= NULL
;
68 unsigned int buf_len
= 0, buf_ndx
= 0, i
;
69 char **names
= NULL
, *buf
= NULL
;
76 if (!(mem_ctx
= talloc_init("fill_grent_mem(%s)", domain
->name
)))
79 /* Initialise group membership information */
81 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string
, group_sid
)));
85 /* HACK ALERT!! This whole routine does not cope with group members
86 * from more than one domain, ie aliases. Thus we have to work it out
87 * ourselves in a special routine. */
90 return fill_passdb_alias_grmem(domain
, group_sid
,
94 if ( !((group_name_type
==SID_NAME_DOM_GRP
) ||
95 ((group_name_type
==SID_NAME_ALIAS
) && domain
->primary
)) )
97 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
98 sid_to_string(sid_string
, group_sid
), domain
->name
,
103 /* OPTIMIZATION / HACK. */
104 /* If "enum users" is set to false, and the group being looked
105 up is the Domain Users SID: S-1-5-domain-513, then for the
106 list of members check if the querying user is in that group,
107 and if so only return that user as the gr_mem array.
108 We can change this to a different parameter than "enum users"
109 if neccessaey, or parameterize the group list we do this for. */
111 sid_peek_rid( group_sid
, &group_rid
);
112 if (!lp_winbind_enum_users() && group_rid
== DOMAIN_GROUP_RID_USERS
) {
113 DOM_SID querying_user_sid
;
114 DOM_SID
*pquerying_user_sid
= NULL
;
115 uint32 num_groups
= 0;
116 DOM_SID
*user_sids
= NULL
;
117 BOOL u_in_group
= False
;
119 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
120 sid_to_string(sid_string
, group_sid
), domain
->name
));
123 uid_t ret_uid
= (uid_t
)-1;
124 if (sys_getpeereid(state
->sock
, &ret_uid
)==0) {
125 /* We know who's asking - look up their SID if
126 it's one we've mapped before. */
127 status
= idmap_uid_to_sid(&querying_user_sid
,
129 ID_QUERY_ONLY
|ID_CACHE_ONLY
);
130 if (NT_STATUS_IS_OK(status
)) {
131 pquerying_user_sid
= &querying_user_sid
;
132 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
133 (unsigned int)ret_uid
,
134 sid_to_string(sid_string
, pquerying_user_sid
) ));
139 /* Only look up if it was a winbindd user in this domain. */
140 if (pquerying_user_sid
&&
141 (sid_compare_domain(pquerying_user_sid
, &domain
->sid
) == 0)) {
143 DEBUG(10,("fill_grent_mem: querying user = %s\n",
144 sid_to_string(sid_string
, pquerying_user_sid
) ));
146 status
= domain
->methods
->lookup_usergroups(domain
,
151 if (!NT_STATUS_IS_OK(status
)) {
152 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
153 "for sid %s in domain %s (error: %s)\n",
154 sid_to_string(sid_string
, pquerying_user_sid
),
160 for (i
= 0; i
< num_groups
; i
++) {
161 if (sid_equal(group_sid
, &user_sids
[i
])) {
162 /* User is in Domain Users, add their name
163 as the only group member. */
172 char *domainname
= NULL
;
173 char *username
= NULL
;
175 enum SID_NAME_USE type
;
177 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
178 sid_to_string(sid_string
, pquerying_user_sid
), domain
->name
));
180 status
= domain
->methods
->sid_to_name(domain
, mem_ctx
,
185 if (!NT_STATUS_IS_OK(status
)) {
186 DEBUG(1, ("could not lookup username for user "
187 "sid %s in domain %s (error: %s)\n",
188 sid_to_string(sid_string
, pquerying_user_sid
),
193 fill_domain_username(name
, domain
->name
, username
, True
);
196 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
197 DEBUG(1, ("out of memory\n"));
200 memcpy(buf
, name
, buf_len
);
202 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
203 name
, domain
->name
));
207 *gr_mem_len
= buf_len
;
210 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem
,
211 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
216 /* Lookup group members */
217 status
= domain
->methods
->lookup_groupmem(domain
, mem_ctx
, group_sid
, &num_names
,
218 &sid_mem
, &names
, &name_types
);
219 if (!NT_STATUS_IS_OK(status
)) {
220 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
221 sid_to_string(sid_string
, group_sid
), domain
->name
, nt_errstr(status
)));
225 DEBUG(10, ("looked up %d names\n", num_names
));
227 if (DEBUGLEVEL
>= 10) {
228 for (i
= 0; i
< num_names
; i
++)
229 DEBUG(10, ("\t%20s %s %d\n", names
[i
],
230 sid_string_static(&sid_mem
[i
]),
234 /* Add members to list */
238 for (i
= 0; i
< num_names
; i
++) {
245 DEBUG(10, ("processing name %s\n", the_name
));
247 /* FIXME: need to cope with groups within groups. These
248 occur in Universal groups on a Windows 2000 native mode
251 /* make sure to allow machine accounts */
253 if (name_types
[i
] != SID_NAME_USER
&& name_types
[i
] != SID_NAME_COMPUTER
) {
254 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name
, sid_type_lookup(name_types
[i
])));
258 /* Append domain name */
260 fill_domain_username(name
, domain
->name
, the_name
, True
);
264 /* Add to list or calculate buffer length */
267 buf_len
+= len
+ 1; /* List is comma separated */
269 DEBUG(10, ("buf_len + %d = %d\n", len
+ 1, buf_len
));
271 DEBUG(10, ("appending %s at ndx %d\n", name
, buf_ndx
));
272 safe_strcpy(&buf
[buf_ndx
], name
, len
);
279 /* Allocate buffer */
281 if (!buf
&& buf_len
!= 0) {
282 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
283 DEBUG(1, ("out of memory\n"));
287 memset(buf
, 0, buf_len
);
291 if (buf
&& buf_ndx
> 0) {
292 buf
[buf_ndx
- 1] = '\0';
296 *gr_mem_len
= buf_len
;
298 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem
,
299 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
304 talloc_destroy(mem_ctx
);
306 DEBUG(10, ("fill_grent_mem returning %d\n", result
));
311 /* Return a group structure from a group name */
313 void winbindd_getgrnam(struct winbindd_cli_state
*state
)
315 DOM_SID group_sid
, tmp_sid
;
317 struct winbindd_domain
*domain
;
318 enum SID_NAME_USE name_type
;
319 fstring name_domain
, name_group
;
327 /* Ensure null termination */
328 state
->request
.data
.groupname
[sizeof(state
->request
.data
.groupname
)-1]='\0';
330 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state
->pid
,
331 state
->request
.data
.groupname
));
333 /* Parse domain and groupname */
335 memset(name_group
, 0, sizeof(fstring
));
337 tmp
= state
->request
.data
.groupname
;
339 parse_domain_user(tmp
, name_domain
, name_group
);
341 /* if no domain or our local domain and no local tdb group, default to
342 * our local domain for aliases */
344 if ( !*name_domain
|| strequal(name_domain
, get_global_sam_name()) ) {
345 fstrcpy(name_domain
, get_global_sam_name());
348 /* Get info for the domain */
350 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
351 DEBUG(3, ("could not get domain sid for domain %s\n",
353 request_error(state
);
356 /* should we deal with users for our domain? */
358 if ( lp_winbind_trusted_domains_only() && domain
->primary
) {
359 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
360 "getgrnam() for %s\\%s.\n", name_domain
, name_group
));
361 request_error(state
);
365 /* Get rid and name type from name */
367 if (!winbindd_lookup_sid_by_name(state
->mem_ctx
, domain
, domain
->name
,
368 name_group
, &group_sid
, &name_type
)) {
369 DEBUG(1, ("group %s in domain %s does not exist\n",
370 name_group
, name_domain
));
371 request_error(state
);
375 if ( !((name_type
==SID_NAME_DOM_GRP
) ||
376 ((name_type
==SID_NAME_ALIAS
) && domain
->primary
) ||
377 ((name_type
==SID_NAME_ALIAS
) && domain
->internal
) ||
378 ((name_type
==SID_NAME_WKN_GRP
) && domain
->internal
)) )
380 DEBUG(1, ("name '%s' is not a local, domain or builtin "
381 "group: %d\n", name_group
, name_type
));
382 request_error(state
);
386 /* Make sure that the group SID is within the domain of the
389 sid_copy( &tmp_sid
, &group_sid
);
390 sid_split_rid( &tmp_sid
, &grp_rid
);
391 if ( !sid_equal( &tmp_sid
, &domain
->sid
) ) {
392 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
393 state
->request
.data
.groupname
, sid_string_static(&group_sid
)));
394 request_error(state
);
400 /* Try to get the GID */
402 status
= idmap_sid_to_gid(&group_sid
, &gid
, 0);
404 if (NT_STATUS_IS_OK(status
)) {
408 /* Maybe it's one of our aliases in passdb */
410 if (pdb_sid_to_id(&group_sid
, &id
, &name_type
) &&
411 ((name_type
== SID_NAME_ALIAS
) ||
412 (name_type
== SID_NAME_WKN_GRP
))) {
417 DEBUG(1, ("error converting unix gid to sid\n"));
418 request_error(state
);
423 if (!fill_grent(&state
->response
.data
.gr
, name_domain
,
425 !fill_grent_mem(domain
, state
, &group_sid
, name_type
,
427 &gr_mem
, &gr_mem_len
)) {
428 request_error(state
);
432 state
->response
.data
.gr
.num_gr_mem
= (uint32
)num_gr_mem
;
434 /* Group membership lives at start of extra data */
436 state
->response
.data
.gr
.gr_mem_ofs
= 0;
438 state
->response
.length
+= gr_mem_len
;
439 state
->response
.extra_data
.data
= gr_mem
;
443 static void getgrgid_got_sid(struct winbindd_cli_state
*state
, DOM_SID group_sid
)
445 struct winbindd_domain
*domain
;
446 enum SID_NAME_USE name_type
;
453 /* Get name from sid */
455 if (!winbindd_lookup_name_by_sid(state
->mem_ctx
, &group_sid
, dom_name
,
456 group_name
, &name_type
)) {
457 DEBUG(1, ("could not lookup sid\n"));
458 request_error(state
);
462 /* Fill in group structure */
464 domain
= find_domain_from_sid_noinit(&group_sid
);
467 DEBUG(1,("Can't find domain from sid\n"));
468 request_error(state
);
472 if ( !((name_type
==SID_NAME_DOM_GRP
) ||
473 ((name_type
==SID_NAME_ALIAS
) && domain
->primary
) ||
474 ((name_type
==SID_NAME_ALIAS
) && domain
->internal
)) )
476 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
477 group_name
, name_type
));
478 request_error(state
);
482 if (!fill_grent(&state
->response
.data
.gr
, dom_name
, group_name
,
483 state
->request
.data
.gid
) ||
484 !fill_grent_mem(domain
, state
, &group_sid
, name_type
,
486 &gr_mem
, &gr_mem_len
)) {
487 request_error(state
);
491 state
->response
.data
.gr
.num_gr_mem
= (uint32
)num_gr_mem
;
493 /* Group membership lives at start of extra data */
495 state
->response
.data
.gr
.gr_mem_ofs
= 0;
497 state
->response
.length
+= gr_mem_len
;
498 state
->response
.extra_data
.data
= gr_mem
;
503 static void getgrgid_recv(void *private_data
, BOOL success
, const char *sid
)
505 struct winbindd_cli_state
*state
= talloc_get_type_abort(private_data
, struct winbindd_cli_state
);
506 enum SID_NAME_USE name_type
;
510 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
511 (unsigned long)(state
->request
.data
.gid
), sid
));
513 string_to_sid(&group_sid
, sid
);
514 getgrgid_got_sid(state
, group_sid
);
518 /* Ok, this might be "ours", i.e. an alias */
519 if (pdb_gid_to_sid(state
->request
.data
.gid
, &group_sid
) &&
520 lookup_sid(state
->mem_ctx
, &group_sid
, NULL
, NULL
, &name_type
) &&
521 (name_type
== SID_NAME_ALIAS
)) {
522 /* Hey, got an alias */
523 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
524 (unsigned long)(state
->request
.data
.gid
), sid
));
525 getgrgid_got_sid(state
, group_sid
);
529 DEBUG(1, ("could not convert gid %lu to sid\n",
530 (unsigned long)state
->request
.data
.gid
));
531 request_error(state
);
534 /* Return a group structure from a gid number */
535 void winbindd_getgrgid(struct winbindd_cli_state
*state
)
540 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state
->pid
,
541 (unsigned long)state
->request
.data
.gid
));
543 /* Bug out if the gid isn't in the winbind range */
545 if ((state
->request
.data
.gid
< server_state
.gid_low
) ||
546 (state
->request
.data
.gid
> server_state
.gid_high
)) {
547 request_error(state
);
551 /* Get sid from gid */
553 status
= idmap_gid_to_sid(&group_sid
, state
->request
.data
.gid
, 0);
554 if (NT_STATUS_IS_OK(status
)) {
555 /* This is a remote one */
556 getgrgid_got_sid(state
, group_sid
);
560 DEBUG(10,("winbindd_getgrgid: gid %lu not found in cache, try with the async interface\n",
561 (unsigned long)state
->request
.data
.gid
));
563 winbindd_gid2sid_async(state
->mem_ctx
, state
->request
.data
.gid
, getgrgid_recv
, state
);
567 * set/get/endgrent functions
570 /* "Rewind" file pointer for group database enumeration */
572 static BOOL
winbindd_setgrent_internal(struct winbindd_cli_state
*state
)
574 struct winbindd_domain
*domain
;
576 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state
->pid
));
578 /* Check user has enabled this */
580 if (!lp_winbind_enum_groups()) {
584 /* Free old static data if it exists */
586 if (state
->getgrent_state
!= NULL
) {
587 free_getent_state(state
->getgrent_state
);
588 state
->getgrent_state
= NULL
;
591 /* Create sam pipes for each domain we know about */
593 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
594 struct getent_state
*domain_state
;
596 /* Create a state record for this domain */
598 /* don't add our domaina if we are a PDC or if we
599 are a member of a Samba domain */
601 if ( lp_winbind_trusted_domains_only() && domain
->primary
)
607 if ((domain_state
= SMB_MALLOC_P(struct getent_state
)) == NULL
) {
608 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
612 ZERO_STRUCTP(domain_state
);
614 fstrcpy(domain_state
->domain_name
, domain
->name
);
616 /* Add to list of open domains */
618 DLIST_ADD(state
->getgrent_state
, domain_state
);
621 state
->getgrent_initialized
= True
;
625 void winbindd_setgrent(struct winbindd_cli_state
*state
)
627 if (winbindd_setgrent_internal(state
)) {
630 request_error(state
);
634 /* Close file pointer to ntdom group database */
636 void winbindd_endgrent(struct winbindd_cli_state
*state
)
638 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state
->pid
));
640 free_getent_state(state
->getgrent_state
);
641 state
->getgrent_initialized
= False
;
642 state
->getgrent_state
= NULL
;
646 /* Get the list of domain groups and domain aliases for a domain. We fill in
647 the sam_entries and num_sam_entries fields with domain group information.
648 The dispinfo_ndx field is incremented to the index of the next group to
649 fetch. Return True if some groups were returned, False otherwise. */
651 static BOOL
get_sam_group_entries(struct getent_state
*ent
)
655 struct acct_info
*name_list
= NULL
;
658 struct acct_info
*sam_grp_entries
= NULL
;
659 struct winbindd_domain
*domain
;
661 if (ent
->got_sam_entries
)
664 if (!(mem_ctx
= talloc_init("get_sam_group_entries(%s)",
665 ent
->domain_name
))) {
666 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
670 /* Free any existing group info */
672 SAFE_FREE(ent
->sam_entries
);
673 ent
->num_sam_entries
= 0;
674 ent
->got_sam_entries
= True
;
676 /* Enumerate domain groups */
680 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
681 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent
->domain_name
));
685 /* always get the domain global groups */
687 status
= domain
->methods
->enum_dom_groups(domain
, mem_ctx
, &num_entries
, &sam_grp_entries
);
689 if (!NT_STATUS_IS_OK(status
)) {
690 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status
)));
695 /* Copy entries into return buffer */
698 if ( !(name_list
= SMB_MALLOC_ARRAY(struct acct_info
, num_entries
)) ) {
699 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
704 memcpy( name_list
, sam_grp_entries
, num_entries
* sizeof(struct acct_info
) );
707 ent
->num_sam_entries
= num_entries
;
709 /* get the domain local groups if we are a member of a native win2k domain
710 and are not using LDAP to get the groups */
712 if ( ( lp_security() != SEC_ADS
&& domain
->native_mode
713 && domain
->primary
) || domain
->internal
)
715 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
716 domain
->native_mode
? "Native Mode 2k":"BUILTIN or local"));
718 status
= domain
->methods
->enum_local_groups(domain
, mem_ctx
, &num_entries
, &sam_grp_entries
);
720 if ( !NT_STATUS_IS_OK(status
) ) {
721 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
725 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries
));
727 /* Copy entries into return buffer */
730 if ( !(name_list
= SMB_REALLOC_ARRAY( name_list
, struct acct_info
, ent
->num_sam_entries
+num_entries
)) )
732 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
738 memcpy( &name_list
[ent
->num_sam_entries
], sam_grp_entries
,
739 num_entries
* sizeof(struct acct_info
) );
742 ent
->num_sam_entries
+= num_entries
;
746 /* Fill in remaining fields */
748 ent
->sam_entries
= name_list
;
749 ent
->sam_entry_index
= 0;
751 result
= (ent
->num_sam_entries
> 0);
754 talloc_destroy(mem_ctx
);
759 /* Fetch next group entry from ntdom database */
761 #define MAX_GETGRENT_GROUPS 500
763 void winbindd_getgrent(struct winbindd_cli_state
*state
)
765 struct getent_state
*ent
;
766 struct winbindd_gr
*group_list
= NULL
;
767 int num_groups
, group_list_ndx
= 0, i
, gr_mem_list_len
= 0;
768 char *gr_mem_list
= NULL
;
770 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state
->pid
));
772 /* Check user has enabled this */
774 if (!lp_winbind_enum_groups()) {
775 request_error(state
);
779 num_groups
= MIN(MAX_GETGRENT_GROUPS
, state
->request
.data
.num_entries
);
781 if ((state
->response
.extra_data
.data
= SMB_MALLOC_ARRAY(struct winbindd_gr
, num_groups
)) == NULL
) {
782 request_error(state
);
786 memset(state
->response
.extra_data
.data
, '\0',
787 num_groups
* sizeof(struct winbindd_gr
) );
789 state
->response
.data
.num_entries
= 0;
791 group_list
= (struct winbindd_gr
*)state
->response
.extra_data
.data
;
793 if (!state
->getgrent_initialized
)
794 winbindd_setgrent_internal(state
);
796 if (!(ent
= state
->getgrent_state
)) {
797 request_error(state
);
801 /* Start sending back groups */
803 for (i
= 0; i
< num_groups
; i
++) {
804 struct acct_info
*name_list
= NULL
;
805 fstring domain_group_name
;
811 struct winbindd_domain
*domain
;
813 /* Do we need to fetch another chunk of groups? */
817 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
818 ent
->sam_entry_index
, ent
->num_sam_entries
));
820 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
822 while(ent
&& !get_sam_group_entries(ent
)) {
823 struct getent_state
*next_ent
;
825 DEBUG(10, ("freeing state info for domain %s\n", ent
->domain_name
));
827 /* Free state information for this domain */
829 SAFE_FREE(ent
->sam_entries
);
831 next_ent
= ent
->next
;
832 DLIST_REMOVE(state
->getgrent_state
, ent
);
838 /* No more domains */
844 name_list
= (struct acct_info
*)ent
->sam_entries
;
847 find_domain_from_name(ent
->domain_name
))) {
848 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent
->domain_name
));
853 /* Lookup group info */
855 sid_copy(&group_sid
, &domain
->sid
);
856 sid_append_rid(&group_sid
, name_list
[ent
->sam_entry_index
].rid
);
858 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid
,
861 enum SID_NAME_USE type
;
863 DEBUG(10, ("SID %s not in idmap\n",
864 sid_string_static(&group_sid
)));
866 if (!pdb_sid_to_id(&group_sid
, &id
, &type
)) {
867 DEBUG(1, ("could not look up gid for group "
869 name_list
[ent
->sam_entry_index
].acct_name
));
870 ent
->sam_entry_index
++;
874 if ((type
!= SID_NAME_DOM_GRP
) &&
875 (type
!= SID_NAME_ALIAS
) &&
876 (type
!= SID_NAME_WKN_GRP
)) {
877 DEBUG(1, ("Group %s is a %s, not a group\n",
878 sid_type_lookup(type
),
879 name_list
[ent
->sam_entry_index
].acct_name
));
880 ent
->sam_entry_index
++;
886 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid
,
887 (unsigned long)name_list
[ent
->sam_entry_index
].rid
));
889 /* Fill in group entry */
891 fill_domain_username(domain_group_name
, ent
->domain_name
,
892 name_list
[ent
->sam_entry_index
].acct_name
, True
);
894 result
= fill_grent(&group_list
[group_list_ndx
],
896 name_list
[ent
->sam_entry_index
].acct_name
,
899 /* Fill in group membership entry */
902 size_t num_gr_mem
= 0;
904 group_list
[group_list_ndx
].num_gr_mem
= 0;
908 /* Get group membership */
909 if (state
->request
.cmd
== WINBINDD_GETGRLST
) {
912 sid_copy(&member_sid
, &domain
->sid
);
913 sid_append_rid(&member_sid
, name_list
[ent
->sam_entry_index
].rid
);
914 result
= fill_grent_mem(
920 &gr_mem
, &gr_mem_len
);
922 group_list
[group_list_ndx
].num_gr_mem
= (uint32
)num_gr_mem
;
927 /* Append to group membership list */
928 gr_mem_list
= (char *)SMB_REALLOC(
929 gr_mem_list
, gr_mem_list_len
+ gr_mem_len
);
931 if (!gr_mem_list
&& (group_list
[group_list_ndx
].num_gr_mem
!= 0)) {
932 DEBUG(0, ("out of memory\n"));
937 DEBUG(10, ("list_len = %d, mem_len = %u\n",
938 gr_mem_list_len
, (unsigned int)gr_mem_len
));
940 memcpy(&gr_mem_list
[gr_mem_list_len
], gr_mem
,
945 group_list
[group_list_ndx
].gr_mem_ofs
=
948 gr_mem_list_len
+= gr_mem_len
;
951 ent
->sam_entry_index
++;
953 /* Add group to return list */
957 DEBUG(10, ("adding group num_entries = %d\n",
958 state
->response
.data
.num_entries
));
961 state
->response
.data
.num_entries
++;
963 state
->response
.length
+=
964 sizeof(struct winbindd_gr
);
967 DEBUG(0, ("could not lookup domain group %s\n",
972 /* Copy the list of group memberships to the end of the extra data */
974 if (group_list_ndx
== 0)
977 state
->response
.extra_data
.data
= SMB_REALLOC(
978 state
->response
.extra_data
.data
,
979 group_list_ndx
* sizeof(struct winbindd_gr
) + gr_mem_list_len
);
981 if (!state
->response
.extra_data
.data
) {
982 DEBUG(0, ("out of memory\n"));
984 SAFE_FREE(gr_mem_list
);
985 request_error(state
);
989 memcpy(&((char *)state
->response
.extra_data
.data
)
990 [group_list_ndx
* sizeof(struct winbindd_gr
)],
991 gr_mem_list
, gr_mem_list_len
);
993 state
->response
.length
+= gr_mem_list_len
;
995 DEBUG(10, ("returning %d groups, length = %d\n",
996 group_list_ndx
, gr_mem_list_len
));
1002 SAFE_FREE(gr_mem_list
);
1004 if (group_list_ndx
> 0)
1007 request_error(state
);
1010 /* List domain groups without mapping to unix ids */
1012 void winbindd_list_groups(struct winbindd_cli_state
*state
)
1014 uint32 total_entries
= 0;
1015 struct winbindd_domain
*domain
;
1016 const char *which_domain
;
1017 char *extra_data
= NULL
;
1018 unsigned int extra_data_len
= 0, i
;
1020 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state
->pid
));
1022 /* Ensure null termination */
1023 state
->request
.domain_name
[sizeof(state
->request
.domain_name
)-1]='\0';
1024 which_domain
= state
->request
.domain_name
;
1026 /* Enumerate over trusted domains */
1028 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
1029 struct getent_state groups
;
1031 /* if we have a domain name restricting the request and this
1032 one in the list doesn't match, then just bypass the remainder
1035 if ( *which_domain
&& !strequal(which_domain
, domain
->name
) )
1038 ZERO_STRUCT(groups
);
1040 /* Get list of sam groups */
1042 fstrcpy(groups
.domain_name
, domain
->name
);
1044 get_sam_group_entries(&groups
);
1046 if (groups
.num_sam_entries
== 0) {
1047 /* this domain is empty or in an error state */
1051 /* keep track the of the total number of groups seen so
1052 far over all domains */
1053 total_entries
+= groups
.num_sam_entries
;
1055 /* Allocate some memory for extra data. Note that we limit
1056 account names to sizeof(fstring) = 128 characters. */
1057 extra_data
= (char *)SMB_REALLOC(
1058 extra_data
, sizeof(fstring
) * total_entries
);
1061 DEBUG(0,("failed to enlarge buffer!\n"));
1062 request_error(state
);
1066 /* Pack group list into extra data fields */
1067 for (i
= 0; i
< groups
.num_sam_entries
; i
++) {
1068 char *group_name
= ((struct acct_info
*)
1069 groups
.sam_entries
)[i
].acct_name
;
1072 fill_domain_username(name
, domain
->name
, group_name
, True
);
1073 /* Append to extra data */
1074 memcpy(&extra_data
[extra_data_len
], name
,
1076 extra_data_len
+= strlen(name
);
1077 extra_data
[extra_data_len
++] = ',';
1080 SAFE_FREE(groups
.sam_entries
);
1083 /* Assign extra_data fields in response structure */
1085 extra_data
[extra_data_len
- 1] = '\0';
1086 state
->response
.extra_data
.data
= extra_data
;
1087 state
->response
.length
+= extra_data_len
;
1090 /* No domains may have responded but that's still OK so don't
1096 /* Get user supplementary groups. This is much quicker than trying to
1097 invert the groups database. We merge the groups from the gids and
1098 other_sids info3 fields as trusted domain, universal group
1099 memberships, and nested groups (win2k native mode only) are not
1100 returned by the getgroups RPC call but are present in the info3. */
1102 struct getgroups_state
{
1103 struct winbindd_cli_state
*state
;
1104 struct winbindd_domain
*domain
;
1109 const DOM_SID
*token_sids
;
1110 size_t i
, num_token_sids
;
1113 size_t num_token_gids
;
1116 static void getgroups_usersid_recv(void *private_data
, BOOL success
,
1117 const DOM_SID
*sid
, enum SID_NAME_USE type
);
1118 static void getgroups_tokensids_recv(void *private_data
, BOOL success
,
1119 DOM_SID
*token_sids
, size_t num_token_sids
);
1120 static void getgroups_sid2gid_recv(void *private_data
, BOOL success
, gid_t gid
);
1122 void winbindd_getgroups(struct winbindd_cli_state
*state
)
1124 struct getgroups_state
*s
;
1126 /* Ensure null termination */
1127 state
->request
.data
.username
1128 [sizeof(state
->request
.data
.username
)-1]='\0';
1130 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state
->pid
,
1131 state
->request
.data
.username
));
1133 /* Parse domain and username */
1135 s
= TALLOC_P(state
->mem_ctx
, struct getgroups_state
);
1137 DEBUG(0, ("talloc failed\n"));
1138 request_error(state
);
1144 if (!parse_domain_user_talloc(state
->mem_ctx
,
1145 state
->request
.data
.username
,
1146 &s
->domname
, &s
->username
)) {
1147 DEBUG(5, ("Could not parse domain user: %s\n",
1148 state
->request
.data
.username
));
1150 /* error out if we do not have nested group support */
1152 if ( !lp_winbind_nested_groups() ) {
1153 request_error(state
);
1157 s
->domname
= talloc_strdup( state
->mem_ctx
, get_global_sam_name() );
1158 s
->username
= talloc_strdup( state
->mem_ctx
, state
->request
.data
.username
);
1161 /* Get info for the domain */
1163 s
->domain
= find_domain_from_name_noinit(s
->domname
);
1165 if (s
->domain
== NULL
) {
1166 DEBUG(7, ("could not find domain entry for domain %s\n",
1168 request_error(state
);
1172 if ( s
->domain
->primary
&& lp_winbind_trusted_domains_only()) {
1173 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
1174 "getgroups() for %s\\%s.\n", s
->domname
,
1176 request_error(state
);
1180 /* Get rid and name type from name. The following costs 1 packet */
1182 winbindd_lookupname_async(state
->mem_ctx
, s
->domname
, s
->username
,
1183 getgroups_usersid_recv
, s
);
1186 static void getgroups_usersid_recv(void *private_data
, BOOL success
,
1187 const DOM_SID
*sid
, enum SID_NAME_USE type
)
1189 struct getgroups_state
*s
=
1190 (struct getgroups_state
*)private_data
;
1193 ((type
!= SID_NAME_USER
) && (type
!= SID_NAME_COMPUTER
))) {
1194 request_error(s
->state
);
1198 sid_copy(&s
->user_sid
, sid
);
1200 winbindd_gettoken_async(s
->state
->mem_ctx
, &s
->user_sid
,
1201 getgroups_tokensids_recv
, s
);
1204 static void getgroups_tokensids_recv(void *private_data
, BOOL success
,
1205 DOM_SID
*token_sids
, size_t num_token_sids
)
1207 struct getgroups_state
*s
=
1208 (struct getgroups_state
*)private_data
;
1210 /* We need at least the user sid and the primary group in the token,
1211 * otherwise it's an error */
1213 if ((!success
) || (num_token_sids
< 2)) {
1214 request_error(s
->state
);
1218 s
->token_sids
= token_sids
;
1219 s
->num_token_sids
= num_token_sids
;
1222 s
->token_gids
= NULL
;
1223 s
->num_token_gids
= 0;
1225 getgroups_sid2gid_recv(s
, False
, 0);
1228 static void getgroups_sid2gid_recv(void *private_data
, BOOL success
, gid_t gid
)
1230 struct getgroups_state
*s
=
1231 (struct getgroups_state
*)private_data
;
1234 add_gid_to_array_unique(NULL
, gid
,
1236 &s
->num_token_gids
);
1238 if (s
->i
< s
->num_token_sids
) {
1239 const DOM_SID
*sid
= &s
->token_sids
[s
->i
];
1242 if (sid_equal(sid
, &s
->user_sid
)) {
1243 getgroups_sid2gid_recv(s
, False
, 0);
1247 winbindd_sid2gid_async(s
->state
->mem_ctx
, sid
,
1248 getgroups_sid2gid_recv
, s
);
1252 s
->state
->response
.data
.num_entries
= s
->num_token_gids
;
1253 s
->state
->response
.extra_data
.data
= s
->token_gids
;
1254 s
->state
->response
.length
+= s
->num_token_gids
* sizeof(gid_t
);
1255 request_ok(s
->state
);
1258 /* Get user supplementary sids. This is equivalent to the
1259 winbindd_getgroups() function but it involves a SID->SIDs mapping
1260 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1261 idmap. This call is designed to be used with applications that need
1262 to do ACL evaluation themselves. Note that the cached info3 data is
1265 this function assumes that the SID that comes in is a user SID. If
1266 you pass in another type of SID then you may get unpredictable
1270 static void getusersids_recv(void *private_data
, BOOL success
, DOM_SID
*sids
,
1273 void winbindd_getusersids(struct winbindd_cli_state
*state
)
1277 /* Ensure null termination */
1278 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1280 user_sid
= TALLOC_P(state
->mem_ctx
, DOM_SID
);
1281 if (user_sid
== NULL
) {
1282 DEBUG(1, ("talloc failed\n"));
1283 request_error(state
);
1287 if (!string_to_sid(user_sid
, state
->request
.data
.sid
)) {
1288 DEBUG(1, ("Could not get convert sid %s from string\n",
1289 state
->request
.data
.sid
));
1290 request_error(state
);
1294 winbindd_gettoken_async(state
->mem_ctx
, user_sid
, getusersids_recv
,
1298 static void getusersids_recv(void *private_data
, BOOL success
, DOM_SID
*sids
,
1301 struct winbindd_cli_state
*state
=
1302 (struct winbindd_cli_state
*)private_data
;
1304 unsigned ofs
, ret_size
= 0;
1308 request_error(state
);
1312 /* work out the response size */
1313 for (i
= 0; i
< num_sids
; i
++) {
1314 const char *s
= sid_string_static(&sids
[i
]);
1315 ret_size
+= strlen(s
) + 1;
1318 /* build the reply */
1319 ret
= (char *)SMB_MALLOC(ret_size
);
1321 DEBUG(0, ("malloc failed\n"));
1322 request_error(state
);
1326 for (i
= 0; i
< num_sids
; i
++) {
1327 const char *s
= sid_string_static(&sids
[i
]);
1328 safe_strcpy(ret
+ ofs
, s
, ret_size
- ofs
- 1);
1329 ofs
+= strlen(ret
+ofs
) + 1;
1332 /* Send data back to client */
1333 state
->response
.data
.num_entries
= num_sids
;
1334 state
->response
.extra_data
.data
= ret
;
1335 state
->response
.length
+= ret_size
;
1339 void winbindd_getuserdomgroups(struct winbindd_cli_state
*state
)
1342 struct winbindd_domain
*domain
;
1344 /* Ensure null termination */
1345 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1347 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1348 DEBUG(1, ("Could not get convert sid %s from string\n",
1349 state
->request
.data
.sid
));
1350 request_error(state
);
1354 /* Get info for the domain */
1355 if ((domain
= find_domain_from_sid_noinit(&user_sid
)) == NULL
) {
1356 DEBUG(0,("could not find domain entry for sid %s\n",
1357 sid_string_static(&user_sid
)));
1358 request_error(state
);
1362 sendto_domain(state
, domain
);
1365 enum winbindd_result
winbindd_dual_getuserdomgroups(struct winbindd_domain
*domain
,
1366 struct winbindd_cli_state
*state
)
1376 /* Ensure null termination */
1377 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1379 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1380 DEBUG(1, ("Could not get convert sid %s from string\n",
1381 state
->request
.data
.sid
));
1382 return WINBINDD_ERROR
;
1385 status
= domain
->methods
->lookup_usergroups(domain
, state
->mem_ctx
,
1386 &user_sid
, &num_groups
,
1388 if (!NT_STATUS_IS_OK(status
))
1389 return WINBINDD_ERROR
;
1391 if (num_groups
== 0) {
1392 state
->response
.data
.num_entries
= 0;
1393 state
->response
.extra_data
.data
= NULL
;
1397 if (!print_sidlist(NULL
, groups
, num_groups
, &sidstring
, &len
)) {
1398 DEBUG(0, ("malloc failed\n"));
1399 return WINBINDD_ERROR
;
1402 state
->response
.extra_data
.data
= sidstring
;
1403 state
->response
.length
+= len
+1;
1404 state
->response
.data
.num_entries
= num_groups
;