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 3 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, see <http://www.gnu.org/licenses/>.
29 #define DBGC_CLASS DBGC_WINBIND
31 static void add_member(const char *domain
, const char *user
,
32 char **pp_members
, size_t *p_num_members
)
37 fill_domain_username(name
, domain
, user
, True
);
41 safe_strcat(name
, ",", sizeof(name
)-1);
42 string_append(pp_members
, name
);
46 /**********************************************************************
47 Add member users resulting from sid. Expand if it is a domain group.
48 **********************************************************************/
50 static void add_expanded_sid(const DOM_SID
*sid
,
52 size_t *p_num_members
)
56 struct winbindd_domain
*domain
;
59 char *domain_name
= NULL
;
61 enum lsa_SidType type
;
70 TALLOC_CTX
*mem_ctx
= talloc_init("add_expanded_sid");
72 if (mem_ctx
== NULL
) {
73 DEBUG(1, ("talloc_init failed\n"));
77 sid_copy(&dom_sid
, sid
);
78 sid_split_rid(&dom_sid
, &rid
);
80 domain
= find_lookup_domain_from_sid(sid
);
83 DEBUG(3, ("Could not find domain for sid %s\n",
84 sid_string_dbg(sid
)));
88 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
,
89 &domain_name
, &name
, &type
);
91 if (!NT_STATUS_IS_OK(result
)) {
92 DEBUG(3, ("sid_to_name failed for sid %s\n",
93 sid_string_dbg(sid
)));
97 DEBUG(10, ("Found name %s, type %d\n", name
, type
));
99 if (type
== SID_NAME_USER
) {
100 add_member(domain_name
, name
, pp_members
, p_num_members
);
104 if (type
!= SID_NAME_DOM_GRP
) {
105 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
110 /* Expand the domain group, this must be done via the target domain */
112 domain
= find_domain_from_sid(sid
);
114 if (domain
== NULL
) {
115 DEBUG(3, ("Could not find domain from SID %s\n",
116 sid_string_dbg(sid
)));
120 result
= domain
->methods
->lookup_groupmem(domain
, mem_ctx
,
125 if (!NT_STATUS_IS_OK(result
)) {
126 DEBUG(10, ("Could not lookup group members for %s: %s\n",
127 name
, nt_errstr(result
)));
131 for (i
=0; i
<num_names
; i
++) {
132 DEBUG(10, ("Adding group member SID %s\n",
133 sid_string_dbg(&sid_mem
[i
])));
135 if (types
[i
] != SID_NAME_USER
) {
136 DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
137 "Ignoring.\n", names
[i
], name
));
141 add_member(NULL
, names
[i
], pp_members
, p_num_members
);
145 talloc_destroy(mem_ctx
);
149 static bool fill_passdb_alias_grmem(struct winbindd_domain
*domain
,
150 DOM_SID
*group_sid
, size_t *num_gr_mem
,
151 char **gr_mem
, size_t *gr_mem_len
)
154 size_t i
, num_members
;
160 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid
, &members
,
164 for (i
=0; i
<num_members
; i
++) {
165 add_expanded_sid(&members
[i
], gr_mem
, num_gr_mem
);
168 TALLOC_FREE(members
);
170 if (*gr_mem
!= NULL
) {
173 /* We have at least one member, strip off the last "," */
174 len
= strlen(*gr_mem
);
175 (*gr_mem
)[len
-1] = '\0';
182 /* Fill a grent structure from various other information */
184 static bool fill_grent(TALLOC_CTX
*mem_ctx
, struct winbindd_gr
*gr
,
185 const char *dom_name
,
186 char *gr_name
, gid_t unix_gid
)
188 fstring full_group_name
;
189 char *mapped_name
= NULL
;
190 struct winbindd_domain
*domain
= find_domain_from_name_noinit(dom_name
);
191 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
193 nt_status
= normalize_name_map(mem_ctx
, domain
, gr_name
,
196 /* Basic whitespace replacement */
197 if (NT_STATUS_IS_OK(nt_status
)) {
198 fill_domain_username(full_group_name
, dom_name
,
201 /* Mapped to an aliase */
202 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
)) {
203 fstrcpy(full_group_name
, mapped_name
);
207 fill_domain_username( full_group_name
, dom_name
,
211 gr
->gr_gid
= unix_gid
;
213 /* Group name and password */
215 safe_strcpy(gr
->gr_name
, full_group_name
, sizeof(gr
->gr_name
) - 1);
216 safe_strcpy(gr
->gr_passwd
, "x", sizeof(gr
->gr_passwd
) - 1);
221 /***********************************************************************
222 If "enum users" is set to false, and the group being looked
223 up is the Domain Users SID: S-1-5-domain-513, then for the
224 list of members check if the querying user is in that group,
225 and if so only return that user as the gr_mem array.
226 We can change this to a different parameter than "enum users"
227 if neccessaey, or parameterize the group list we do this for.
228 ***********************************************************************/
230 static bool fill_grent_mem_domusers( TALLOC_CTX
*mem_ctx
,
231 struct winbindd_domain
*domain
,
232 struct winbindd_cli_state
*state
,
234 enum lsa_SidType group_name_type
,
235 size_t *num_gr_mem
, char **gr_mem
,
238 DOM_SID querying_user_sid
;
239 DOM_SID
*pquerying_user_sid
= NULL
;
240 uint32 num_groups
= 0;
241 DOM_SID
*user_sids
= NULL
;
242 bool u_in_group
= False
;
245 unsigned int buf_len
= 0;
248 DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
252 uid_t ret_uid
= (uid_t
)-1;
253 if (sys_getpeereid(state
->sock
, &ret_uid
)==0) {
254 /* We know who's asking - look up their SID if
255 it's one we've mapped before. */
256 status
= idmap_uid_to_sid(domain
->name
,
257 &querying_user_sid
, ret_uid
);
258 if (NT_STATUS_IS_OK(status
)) {
259 pquerying_user_sid
= &querying_user_sid
;
260 DEBUG(10,("fill_grent_mem_domain_users: "
261 "querying uid %u -> %s\n",
262 (unsigned int)ret_uid
,
263 sid_string_dbg(pquerying_user_sid
)));
268 /* Only look up if it was a winbindd user in this domain. */
269 if (pquerying_user_sid
&&
270 (sid_compare_domain(pquerying_user_sid
, &domain
->sid
) == 0)) {
272 DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
273 sid_string_dbg(pquerying_user_sid
) ));
275 status
= domain
->methods
->lookup_usergroups(domain
,
280 if (!NT_STATUS_IS_OK(status
)) {
281 DEBUG(1, ("fill_grent_mem_domain_users: "
282 "lookup_usergroups failed "
283 "for sid %s in domain %s (error: %s)\n",
284 sid_string_dbg(pquerying_user_sid
),
290 for (i
= 0; i
< num_groups
; i
++) {
291 if (sid_equal(group_sid
, &user_sids
[i
])) {
292 /* User is in Domain Users, add their name
293 as the only group member. */
302 char *domainname
= NULL
;
303 char *username
= NULL
;
305 char *mapped_name
= NULL
;
306 enum lsa_SidType type
;
307 struct winbindd_domain
*target_domain
= NULL
;
308 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
310 DEBUG(10,("fill_grent_mem_domain_users: "
311 "sid %s in 'Domain Users' in domain %s\n",
312 sid_string_dbg(pquerying_user_sid
),
315 status
= domain
->methods
->sid_to_name(domain
, mem_ctx
,
320 if (!NT_STATUS_IS_OK(status
)) {
321 DEBUG(1, ("could not lookup username for user "
322 "sid %s in domain %s (error: %s)\n",
323 sid_string_dbg(pquerying_user_sid
),
329 target_domain
= find_domain_from_name_noinit(domainname
);
330 name_map_status
= normalize_name_map(mem_ctx
, target_domain
,
331 username
, &mapped_name
);
333 /* Basic whitespace replacement */
334 if (NT_STATUS_IS_OK(name_map_status
)) {
335 fill_domain_username(name
, domainname
, mapped_name
, true);
337 /* Mapped to an alias */
338 else if (NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
)) {
339 fstrcpy(name
, mapped_name
);
341 /* no mapping done...use original name */
343 fill_domain_username(name
, domainname
, username
, true);
348 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
349 DEBUG(1, ("out of memory\n"));
352 memcpy(buf
, name
, buf_len
);
354 DEBUG(10,("fill_grent_mem_domain_users: user %s in "
355 "'Domain Users' in domain %s\n",
356 name
, domain
->name
));
358 /* user is the only member */
363 *gr_mem_len
= buf_len
;
365 DEBUG(10, ("fill_grent_mem_domain_users: "
366 "num_mem = %u, len = %u, mem = %s\n",
367 (unsigned int)*num_gr_mem
,
368 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
373 /***********************************************************************
374 Add names to a list. Assumes a canonical version of the string
376 ***********************************************************************/
378 static int namecmp( const void *a
, const void *b
)
380 return StrCaseCmp( * (char * const *) a
, * (char * const *) b
);
383 static void sort_unique_list(char ***list
, uint32
*n_list
)
387 /* search for duplicates for sorting and looking for matching
390 qsort(*list
, *n_list
, sizeof(char*), QSORT_CAST namecmp
);
392 for (i
=1; i
< *n_list
; i
++) {
393 if (strcmp((*list
)[i
-1], (*list
)[i
]) == 0) {
394 memmove(&((*list
)[i
-1]), &((*list
)[i
]),
395 sizeof(char*)*((*n_list
)-i
));
401 static NTSTATUS
add_names_to_list( TALLOC_CTX
*ctx
,
402 char ***list
, uint32
*n_list
,
403 char **names
, uint32 n_names
)
405 char **new_list
= NULL
;
406 uint32 n_new_list
= 0;
409 if ( !names
|| (n_names
== 0) )
412 /* Alloc the maximum size we'll need */
414 if ( *list
== NULL
) {
415 if ((new_list
= TALLOC_ARRAY(ctx
, char *, n_names
)) == NULL
) {
416 return NT_STATUS_NO_MEMORY
;
418 n_new_list
= n_names
;
420 new_list
= TALLOC_REALLOC_ARRAY( ctx
, *list
, char *,
421 (*n_list
) + n_names
);
423 return NT_STATUS_NO_MEMORY
;
424 n_new_list
= (*n_list
) + n_names
;
429 for ( i
=*n_list
, j
=0; i
<n_new_list
; i
++, j
++ ) {
430 new_list
[i
] = talloc_strdup( new_list
, names
[j
] );
434 *n_list
= n_new_list
;
439 /***********************************************************************
440 ***********************************************************************/
442 static NTSTATUS
expand_groups( TALLOC_CTX
*ctx
,
443 struct winbindd_domain
*d
,
444 DOM_SID
*glist
, uint32 n_glist
,
445 DOM_SID
**new_glist
, uint32
*n_new_glist
,
446 char ***members
, uint32
*n_members
)
449 NTSTATUS status
= NT_STATUS_OK
;
450 uint32 num_names
= 0;
451 uint32
*name_types
= NULL
;
453 DOM_SID
*sid_mem
= NULL
;
454 TALLOC_CTX
*tmp_ctx
= NULL
;
455 DOM_SID
*new_groups
= NULL
;
456 size_t new_groups_size
= 0;
463 for ( i
=0; i
<n_glist
; i
++ ) {
464 tmp_ctx
= talloc_new( ctx
);
466 /* Lookup the group membership */
468 status
= d
->methods
->lookup_groupmem(d
, tmp_ctx
,
469 &glist
[i
], &num_names
,
472 if ( !NT_STATUS_IS_OK(status
) )
475 /* Separate users and groups into two lists */
477 for ( j
=0; j
<num_names
; j
++ ) {
480 if ( name_types
[j
] == SID_NAME_USER
||
481 name_types
[j
] == SID_NAME_COMPUTER
)
483 status
= add_names_to_list( ctx
, members
,
486 if ( !NT_STATUS_IS_OK(status
) )
493 if ( name_types
[j
] == SID_NAME_DOM_GRP
||
494 name_types
[j
] == SID_NAME_ALIAS
)
496 status
= add_sid_to_array_unique(ctx
,
500 if (!NT_STATUS_IS_OK(status
)) {
508 TALLOC_FREE( tmp_ctx
);
511 *new_glist
= new_groups
;
512 *n_new_glist
= (uint32
)new_groups_size
;
515 TALLOC_FREE( tmp_ctx
);
520 /***********************************************************************
521 Fill in the group membership field of a NT group given by group_sid
522 ***********************************************************************/
524 static bool fill_grent_mem(struct winbindd_domain
*domain
,
525 struct winbindd_cli_state
*state
,
527 enum lsa_SidType group_name_type
,
528 size_t *num_gr_mem
, char **gr_mem
,
531 uint32 num_names
= 0;
532 unsigned int buf_len
= 0, buf_ndx
= 0, i
;
533 char **names
= NULL
, *buf
= NULL
;
537 DOM_SID
*glist
= NULL
;
538 DOM_SID
*new_glist
= NULL
;
539 uint32 n_glist
, n_new_glist
;
540 int max_depth
= lp_winbind_expand_groups();
542 if (!(mem_ctx
= talloc_init("fill_grent_mem(%s)", domain
->name
)))
545 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid
)));
547 /* Initialize with no members */
551 /* HACK ALERT!! This whole routine does not cope with group members
552 * from more than one domain, ie aliases. Thus we have to work it out
553 * ourselves in a special routine. */
555 if (domain
->internal
) {
556 result
= fill_passdb_alias_grmem(domain
, group_sid
,
562 /* Verify name type */
564 if ( !((group_name_type
==SID_NAME_DOM_GRP
) ||
565 ((group_name_type
==SID_NAME_ALIAS
) && domain
->primary
)) )
567 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
568 sid_string_dbg(group_sid
),
569 domain
->name
, group_name_type
));
573 /* OPTIMIZATION / HACK. See comment in
574 fill_grent_mem_domusers() */
576 sid_peek_rid( group_sid
, &group_rid
);
577 if (!lp_winbind_enum_users() && group_rid
== DOMAIN_GROUP_RID_USERS
) {
578 result
= fill_grent_mem_domusers( mem_ctx
, domain
, state
,
579 group_sid
, group_name_type
,
585 /* Real work goes here. Create a list of group names to
586 expand starting with the initial one. Pass that to
587 expand_groups() which returns a list of more group names
588 to expand. Do this up to the max search depth. */
590 if ( (glist
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, 1 )) == NULL
) {
592 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
595 sid_copy( &glist
[0], group_sid
);
598 for ( i
=0; i
<max_depth
&& glist
; i
++ ) {
599 uint32 n_members
= 0;
600 char **members
= NULL
;
604 nt_status
= expand_groups( mem_ctx
, domain
,
606 &new_glist
, &n_new_glist
,
607 &members
, &n_members
);
608 if ( !NT_STATUS_IS_OK(nt_status
) ) {
613 /* Add new group members to list. Pass through the
614 alias mapping function */
616 for (j
=0; j
<n_members
; j
++) {
617 fstring name_domain
, name_acct
;
618 fstring qualified_name
;
619 char *mapped_name
= NULL
;
620 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
621 struct winbindd_domain
*target_domain
= NULL
;
623 if (parse_domain_user(members
[j
], name_domain
, name_acct
)) {
624 target_domain
= find_domain_from_name_noinit(name_domain
);
627 if (!target_domain
) {
628 target_domain
= domain
;
631 name_map_status
= normalize_name_map(members
, target_domain
,
632 name_acct
, &mapped_name
);
634 /* Basic whitespace replacement */
635 if (NT_STATUS_IS_OK(name_map_status
)) {
636 fill_domain_username(qualified_name
, name_domain
,
638 mapped_name
= qualified_name
;
640 /* no mapping at all */
641 else if (!NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
)) {
642 mapped_name
= members
[j
];
645 nt_status
= add_names_to_list( mem_ctx
, &names
,
648 if ( !NT_STATUS_IS_OK(nt_status
) ) {
654 TALLOC_FREE( members
);
656 /* If we have no more groups to expand, break out
659 if (new_glist
== NULL
)
665 n_glist
= n_new_glist
;
667 TALLOC_FREE( glist
);
669 sort_unique_list(&names
, &num_names
);
671 DEBUG(10, ("looked up %d names\n", num_names
));
674 /* Add members to list */
676 for (i
= 0; i
< num_names
; i
++) {
679 DEBUG(10, ("processing name %s\n", names
[i
]));
681 len
= strlen(names
[i
]);
683 /* Add to list or calculate buffer length */
686 buf_len
+= len
+ 1; /* List is comma separated */
688 DEBUG(10, ("buf_len + %d = %d\n", len
+ 1, buf_len
));
690 DEBUG(10, ("appending %s at ndx %d\n",
692 parse_add_domuser(&buf
[buf_ndx
], names
[i
], &len
);
699 /* Allocate buffer */
701 if (!buf
&& buf_len
!= 0) {
702 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
703 DEBUG(1, ("out of memory\n"));
707 memset(buf
, 0, buf_len
);
713 if (buf
&& buf_ndx
> 0) {
714 buf
[buf_ndx
- 1] = '\0';
718 *gr_mem_len
= buf_len
;
720 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n",
721 (unsigned int)*num_gr_mem
,
722 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
727 talloc_destroy(mem_ctx
);
729 DEBUG(10, ("fill_grent_mem returning %d\n", result
));
734 static void winbindd_getgrsid(struct winbindd_cli_state
*state
, DOM_SID group_sid
);
736 static void getgrnam_recv( void *private_data
, bool success
, const DOM_SID
*sid
,
737 enum lsa_SidType type
)
739 struct winbindd_cli_state
*state
= (struct winbindd_cli_state
*)private_data
;
742 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
743 request_error(state
);
747 if ( (type
!= SID_NAME_DOM_GRP
) && (type
!= SID_NAME_ALIAS
) ) {
748 DEBUG(5,("getgrnam_recv: not a group!\n"));
749 request_error(state
);
753 winbindd_getgrsid( state
, *sid
);
757 /* Return a group structure from a group name */
759 void winbindd_getgrnam(struct winbindd_cli_state
*state
)
761 struct winbindd_domain
*domain
;
762 fstring name_domain
, name_group
;
764 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
766 /* Ensure null termination */
767 state
->request
.data
.groupname
[sizeof(state
->request
.data
.groupname
)-1]='\0';
769 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state
->pid
,
770 state
->request
.data
.groupname
));
772 nt_status
= normalize_name_unmap(state
->mem_ctx
,
773 state
->request
.data
.groupname
,
775 /* If we didn't map anything in the above call, just reset the
776 tmp pointer to the original string */
777 if (!NT_STATUS_IS_OK(nt_status
) &&
778 !NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
))
780 tmp
= state
->request
.data
.groupname
;
783 /* Parse domain and groupname */
785 memset(name_group
, 0, sizeof(name_group
));
787 name_domain
[0] = '\0';
788 name_group
[0] = '\0';
790 parse_domain_user(tmp
, name_domain
, name_group
);
792 /* if no domain or our local domain and no local tdb group, default to
793 * our local domain for aliases */
795 if ( !*name_domain
|| strequal(name_domain
, get_global_sam_name()) ) {
796 fstrcpy(name_domain
, get_global_sam_name());
799 /* Get info for the domain */
801 if ((domain
= find_domain_from_name_noinit(name_domain
)) == NULL
) {
802 DEBUG(3, ("could not get domain sid for domain %s\n",
804 request_error(state
);
807 /* should we deal with users for our domain? */
809 if ( lp_winbind_trusted_domains_only() && domain
->primary
) {
810 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
811 "getgrnam() for %s\\%s.\n", name_domain
, name_group
));
812 request_error(state
);
816 /* Get rid and name type from name */
818 fstrcpy( name_group
, tmp
);
820 winbindd_lookupname_async( state
->mem_ctx
, domain
->name
, name_group
,
821 getgrnam_recv
, WINBINDD_GETGRNAM
, state
);
824 struct getgrsid_state
{
825 struct winbindd_cli_state
*state
;
826 struct winbindd_domain
*domain
;
828 enum lsa_SidType group_type
;
833 static void getgrsid_sid2gid_recv(void *private_data
, bool success
, gid_t gid
)
835 struct getgrsid_state
*s
=
836 (struct getgrsid_state
*)private_data
;
837 struct winbindd_domain
*domain
;
841 fstring dom_name
, group_name
;
844 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
845 request_error(s
->state
);
851 if ( !parse_domain_user( s
->group_name
, dom_name
, group_name
) ) {
852 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
853 request_error(s
->state
);
858 /* Fill in group structure */
860 if ( (domain
= find_domain_from_name_noinit(dom_name
)) == NULL
) {
861 DEBUG(1,("Can't find domain from name (%s)\n", dom_name
));
862 request_error(s
->state
);
866 if (!fill_grent(s
->state
->mem_ctx
, &s
->state
->response
.data
.gr
,
867 dom_name
, group_name
, gid
) ||
868 !fill_grent_mem(domain
, s
->state
, &s
->group_sid
, s
->group_type
,
869 &num_gr_mem
, &gr_mem
, &gr_mem_len
))
871 request_error(s
->state
);
875 s
->state
->response
.data
.gr
.num_gr_mem
= (uint32
)num_gr_mem
;
877 /* Group membership lives at start of extra data */
879 s
->state
->response
.data
.gr
.gr_mem_ofs
= 0;
881 s
->state
->response
.length
+= gr_mem_len
;
882 s
->state
->response
.extra_data
.data
= gr_mem
;
884 request_ok(s
->state
);
887 static void getgrsid_lookupsid_recv( void *private_data
, bool success
,
888 const char *dom_name
, const char *name
,
889 enum lsa_SidType name_type
)
891 struct getgrsid_state
*s
= (struct getgrsid_state
*)private_data
;
892 char *mapped_name
= NULL
;
894 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
897 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
898 request_error(s
->state
);
902 /* either it's a domain group, a domain local group, or a
903 local group in an internal domain */
905 if ( !( (name_type
==SID_NAME_DOM_GRP
) ||
906 ((name_type
==SID_NAME_ALIAS
) &&
907 (s
->domain
->primary
|| s
->domain
->internal
)) ) )
909 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
910 dom_name
, name
, name_type
));
911 request_error(s
->state
);
915 /* normalize the name and ensure that we have the DOM\name
916 coming out of here */
918 fstrcpy(raw_name
, name
);
920 nt_status
= normalize_name_unmap(s
->state
->mem_ctx
, raw_name
,
923 /* basic whitespace reversal */
924 if (NT_STATUS_IS_OK(nt_status
)) {
925 s
->group_name
= talloc_asprintf(s
->state
->mem_ctx
,
928 *lp_winbind_separator(),
931 /* mapped from alias */
932 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
)) {
933 s
->group_name
= mapped_name
;
935 /* no mapping at all. use original string */
937 s
->group_name
= talloc_asprintf(s
->state
->mem_ctx
,
940 *lp_winbind_separator(),
944 if (s
->group_name
== NULL
) {
945 DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
946 request_error(s
->state
);
950 s
->group_type
= name_type
;
952 winbindd_sid2gid_async(s
->state
->mem_ctx
, &s
->group_sid
,
953 getgrsid_sid2gid_recv
, s
);
956 static void winbindd_getgrsid( struct winbindd_cli_state
*state
, const DOM_SID group_sid
)
958 struct getgrsid_state
*s
;
960 if ( (s
= TALLOC_ZERO_P(state
->mem_ctx
, struct getgrsid_state
)) == NULL
) {
961 DEBUG(0, ("talloc failed\n"));
962 request_error(state
);
968 if ( (s
->domain
= find_domain_from_sid_noinit(&group_sid
)) == NULL
) {
969 DEBUG(3, ("Could not find domain for sid %s\n",
970 sid_string_dbg(&group_sid
)));
971 request_error(state
);
975 sid_copy(&s
->group_sid
, &group_sid
);
977 winbindd_lookupsid_async( s
->state
->mem_ctx
, &group_sid
,
978 getgrsid_lookupsid_recv
, s
);
982 static void getgrgid_recv(void *private_data
, bool success
, const char *sid
)
984 struct winbindd_cli_state
*state
= talloc_get_type_abort(private_data
, struct winbindd_cli_state
);
985 enum lsa_SidType name_type
;
989 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
990 (unsigned long)(state
->request
.data
.gid
), sid
));
992 if (!string_to_sid(&group_sid
, sid
)) {
993 DEBUG(1,("getgrgid_recv: Could not convert sid %s "
994 "from string\n", sid
));
995 request_error(state
);
999 winbindd_getgrsid(state
, group_sid
);
1003 /* Ok, this might be "ours", i.e. an alias */
1004 if (pdb_gid_to_sid(state
->request
.data
.gid
, &group_sid
) &&
1005 lookup_sid(state
->mem_ctx
, &group_sid
, NULL
, NULL
, &name_type
) &&
1006 (name_type
== SID_NAME_ALIAS
)) {
1007 /* Hey, got an alias */
1008 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
1009 (unsigned long)(state
->request
.data
.gid
), sid
));
1010 winbindd_getgrsid(state
, group_sid
);
1014 DEBUG(1, ("could not convert gid %lu to sid\n",
1015 (unsigned long)state
->request
.data
.gid
));
1016 request_error(state
);
1019 /* Return a group structure from a gid number */
1020 void winbindd_getgrgid(struct winbindd_cli_state
*state
)
1022 gid_t gid
= state
->request
.data
.gid
;
1024 DEBUG(3, ("[%5lu]: getgrgid %lu\n",
1025 (unsigned long)state
->pid
,
1026 (unsigned long)gid
));
1028 /* always use the async interface */
1029 winbindd_gid2sid_async(state
->mem_ctx
, gid
, getgrgid_recv
, state
);
1033 * set/get/endgrent functions
1036 /* "Rewind" file pointer for group database enumeration */
1038 static bool winbindd_setgrent_internal(struct winbindd_cli_state
*state
)
1040 struct winbindd_domain
*domain
;
1042 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state
->pid
));
1044 /* Check user has enabled this */
1046 if (!lp_winbind_enum_groups()) {
1050 /* Free old static data if it exists */
1052 if (state
->getgrent_state
!= NULL
) {
1053 free_getent_state(state
->getgrent_state
);
1054 state
->getgrent_state
= NULL
;
1057 /* Create sam pipes for each domain we know about */
1059 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
1060 struct getent_state
*domain_state
;
1062 /* Create a state record for this domain */
1064 /* don't add our domaina if we are a PDC or if we
1065 are a member of a Samba domain */
1067 if ( lp_winbind_trusted_domains_only() && domain
->primary
)
1072 domain_state
= SMB_MALLOC_P(struct getent_state
);
1073 if (!domain_state
) {
1074 DEBUG(1, ("winbindd_setgrent: "
1075 "malloc failed for domain_state!\n"));
1079 ZERO_STRUCTP(domain_state
);
1081 fstrcpy(domain_state
->domain_name
, domain
->name
);
1083 /* Add to list of open domains */
1085 DLIST_ADD(state
->getgrent_state
, domain_state
);
1088 state
->getgrent_initialized
= True
;
1092 void winbindd_setgrent(struct winbindd_cli_state
*state
)
1094 if (winbindd_setgrent_internal(state
)) {
1097 request_error(state
);
1101 /* Close file pointer to ntdom group database */
1103 void winbindd_endgrent(struct winbindd_cli_state
*state
)
1105 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state
->pid
));
1107 free_getent_state(state
->getgrent_state
);
1108 state
->getgrent_initialized
= False
;
1109 state
->getgrent_state
= NULL
;
1113 /* Get the list of domain groups and domain aliases for a domain. We fill in
1114 the sam_entries and num_sam_entries fields with domain group information.
1115 Return True if some groups were returned, False otherwise. */
1117 bool get_sam_group_entries(struct getent_state
*ent
)
1121 struct acct_info
*name_list
= NULL
;
1122 TALLOC_CTX
*mem_ctx
;
1123 bool result
= False
;
1124 struct acct_info
*sam_grp_entries
= NULL
;
1125 struct winbindd_domain
*domain
;
1127 if (ent
->got_sam_entries
)
1130 if (!(mem_ctx
= talloc_init("get_sam_group_entries(%s)",
1131 ent
->domain_name
))) {
1132 DEBUG(1, ("get_sam_group_entries: "
1133 "could not create talloc context!\n"));
1137 /* Free any existing group info */
1139 SAFE_FREE(ent
->sam_entries
);
1140 ent
->num_sam_entries
= 0;
1141 ent
->got_sam_entries
= True
;
1143 /* Enumerate domain groups */
1147 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
1148 DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
1153 /* always get the domain global groups */
1155 status
= domain
->methods
->enum_dom_groups(domain
, mem_ctx
, &num_entries
,
1158 if (!NT_STATUS_IS_OK(status
)) {
1159 DEBUG(3, ("get_sam_group_entries: "
1160 "could not enumerate domain groups! Error: %s\n",
1161 nt_errstr(status
)));
1166 /* Copy entries into return buffer */
1169 name_list
= SMB_MALLOC_ARRAY(struct acct_info
, num_entries
);
1171 DEBUG(0,("get_sam_group_entries: Failed to malloc "
1172 "memory for %d domain groups!\n",
1177 memcpy(name_list
, sam_grp_entries
,
1178 num_entries
* sizeof(struct acct_info
));
1181 ent
->num_sam_entries
= num_entries
;
1183 /* get the domain local groups if we are a member of a native win2k
1184 * domain and are not using LDAP to get the groups */
1186 if ( ( lp_security() != SEC_ADS
&& domain
->native_mode
1187 && domain
->primary
) || domain
->internal
)
1189 DEBUG(4,("get_sam_group_entries: %s domain; "
1190 "enumerating local groups as well\n",
1191 domain
->native_mode
? "Native Mode 2k":
1192 "BUILTIN or local"));
1194 status
= domain
->methods
->enum_local_groups(domain
, mem_ctx
,
1198 if ( !NT_STATUS_IS_OK(status
) ) {
1199 DEBUG(3,("get_sam_group_entries: "
1200 "Failed to enumerate "
1201 "domain local groups with error %s!\n",
1202 nt_errstr(status
)));
1206 DEBUG(4,("get_sam_group_entries: "
1207 "Returned %d local groups\n",
1210 /* Copy entries into return buffer */
1212 if ( num_entries
) {
1213 name_list
= SMB_REALLOC_ARRAY(name_list
,
1215 ent
->num_sam_entries
+
1218 DEBUG(0,("get_sam_group_entries: "
1219 "Failed to realloc more memory "
1220 "for %d local groups!\n",
1226 memcpy(&name_list
[ent
->num_sam_entries
],
1228 num_entries
* sizeof(struct acct_info
));
1231 ent
->num_sam_entries
+= num_entries
;
1235 /* Fill in remaining fields */
1237 ent
->sam_entries
= name_list
;
1238 ent
->sam_entry_index
= 0;
1240 result
= (ent
->num_sam_entries
> 0);
1243 talloc_destroy(mem_ctx
);
1248 /* Fetch next group entry from ntdom database */
1250 #define MAX_GETGRENT_GROUPS 500
1252 void winbindd_getgrent(struct winbindd_cli_state
*state
)
1254 struct getent_state
*ent
;
1255 struct winbindd_gr
*group_list
= NULL
;
1256 int num_groups
, group_list_ndx
, gr_mem_list_len
= 0;
1257 char *gr_mem_list
= NULL
;
1259 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state
->pid
));
1261 /* Check user has enabled this */
1263 if (!lp_winbind_enum_groups()) {
1264 request_error(state
);
1268 num_groups
= MIN(MAX_GETGRENT_GROUPS
, state
->request
.data
.num_entries
);
1270 if (num_groups
== 0) {
1271 request_error(state
);
1275 group_list
= SMB_MALLOC_ARRAY(struct winbindd_gr
, num_groups
);
1277 request_error(state
);
1280 /* will be freed by process_request() */
1281 state
->response
.extra_data
.data
= group_list
;
1283 memset(state
->response
.extra_data
.data
, '\0',
1284 num_groups
* sizeof(struct winbindd_gr
) );
1286 state
->response
.data
.num_entries
= 0;
1288 if (!state
->getgrent_initialized
)
1289 winbindd_setgrent_internal(state
);
1291 if (!(ent
= state
->getgrent_state
)) {
1292 request_error(state
);
1296 /* Start sending back groups */
1298 for (group_list_ndx
= 0; group_list_ndx
< num_groups
; ) {
1299 struct acct_info
*name_list
= NULL
;
1300 fstring domain_group_name
;
1306 struct winbindd_domain
*domain
;
1308 /* Do we need to fetch another chunk of groups? */
1312 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1313 ent
->sam_entry_index
, ent
->num_sam_entries
));
1315 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
1317 while(ent
&& !get_sam_group_entries(ent
)) {
1318 struct getent_state
*next_ent
;
1320 DEBUG(10, ("freeing state info for domain %s\n",
1323 /* Free state information for this domain */
1325 SAFE_FREE(ent
->sam_entries
);
1327 next_ent
= ent
->next
;
1328 DLIST_REMOVE(state
->getgrent_state
, ent
);
1334 /* No more domains */
1340 name_list
= (struct acct_info
*)ent
->sam_entries
;
1342 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
1343 DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
1349 /* Lookup group info */
1351 sid_copy(&group_sid
, &domain
->sid
);
1352 sid_append_rid(&group_sid
, name_list
[ent
->sam_entry_index
].rid
);
1354 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain
->have_idmap_config
1355 ? domain
->name
: "",
1356 &group_sid
, &group_gid
)))
1359 enum lsa_SidType type
;
1361 DEBUG(10, ("SID %s not in idmap\n",
1362 sid_string_dbg(&group_sid
)));
1364 if (!pdb_sid_to_id(&group_sid
, &id
, &type
)) {
1365 DEBUG(1,("could not look up gid for group %s\n",
1366 name_list
[ent
->sam_entry_index
].acct_name
));
1367 ent
->sam_entry_index
++;
1371 if ((type
!= SID_NAME_DOM_GRP
) &&
1372 (type
!= SID_NAME_ALIAS
) &&
1373 (type
!= SID_NAME_WKN_GRP
)) {
1374 DEBUG(1, ("Group %s is a %s, not a group\n",
1375 sid_type_lookup(type
),
1376 name_list
[ent
->sam_entry_index
].acct_name
));
1377 ent
->sam_entry_index
++;
1383 DEBUG(10, ("got gid %lu for group %lu\n",
1384 (unsigned long)group_gid
,
1385 (unsigned long)name_list
[ent
->sam_entry_index
].rid
));
1387 /* Fill in group entry */
1389 fill_domain_username(domain_group_name
, ent
->domain_name
,
1390 name_list
[ent
->sam_entry_index
].acct_name
, True
);
1392 result
= fill_grent(state
->mem_ctx
, &group_list
[group_list_ndx
],
1394 name_list
[ent
->sam_entry_index
].acct_name
,
1397 /* Fill in group membership entry */
1400 size_t num_gr_mem
= 0;
1402 group_list
[group_list_ndx
].num_gr_mem
= 0;
1406 /* Get group membership */
1407 if (state
->request
.cmd
== WINBINDD_GETGRLST
) {
1410 sid_copy(&member_sid
, &domain
->sid
);
1411 sid_append_rid(&member_sid
, name_list
[ent
->sam_entry_index
].rid
);
1412 result
= fill_grent_mem(
1418 &gr_mem
, &gr_mem_len
);
1420 group_list
[group_list_ndx
].num_gr_mem
= (uint32
)num_gr_mem
;
1425 /* Append to group membership list */
1426 gr_mem_list
= (char *)SMB_REALLOC(
1427 gr_mem_list
, gr_mem_list_len
+ gr_mem_len
);
1430 (group_list
[group_list_ndx
].num_gr_mem
!= 0)) {
1431 DEBUG(0, ("out of memory\n"));
1432 gr_mem_list_len
= 0;
1436 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1437 gr_mem_list_len
, (unsigned int)gr_mem_len
));
1439 memcpy(&gr_mem_list
[gr_mem_list_len
], gr_mem
,
1444 group_list
[group_list_ndx
].gr_mem_ofs
=
1447 gr_mem_list_len
+= gr_mem_len
;
1450 ent
->sam_entry_index
++;
1452 /* Add group to return list */
1456 DEBUG(10, ("adding group num_entries = %d\n",
1457 state
->response
.data
.num_entries
));
1460 state
->response
.data
.num_entries
++;
1462 state
->response
.length
+=
1463 sizeof(struct winbindd_gr
);
1466 DEBUG(0, ("could not lookup domain group %s\n",
1467 domain_group_name
));
1471 /* Copy the list of group memberships to the end of the extra data */
1473 if (group_list_ndx
== 0)
1476 state
->response
.extra_data
.data
= SMB_REALLOC(
1477 state
->response
.extra_data
.data
,
1478 group_list_ndx
* sizeof(struct winbindd_gr
) + gr_mem_list_len
);
1480 if (!state
->response
.extra_data
.data
) {
1481 DEBUG(0, ("out of memory\n"));
1483 SAFE_FREE(gr_mem_list
);
1484 request_error(state
);
1488 memcpy(&((char *)state
->response
.extra_data
.data
)
1489 [group_list_ndx
* sizeof(struct winbindd_gr
)],
1490 gr_mem_list
, gr_mem_list_len
);
1492 state
->response
.length
+= gr_mem_list_len
;
1494 DEBUG(10, ("returning %d groups, length = %d\n",
1495 group_list_ndx
, gr_mem_list_len
));
1497 /* Out of domains */
1501 SAFE_FREE(gr_mem_list
);
1503 if (group_list_ndx
> 0)
1506 request_error(state
);
1509 /* List domain groups without mapping to unix ids */
1510 void winbindd_list_groups(struct winbindd_cli_state
*state
)
1512 winbindd_list_ent(state
, LIST_GROUPS
);
1515 /* Get user supplementary groups. This is much quicker than trying to
1516 invert the groups database. We merge the groups from the gids and
1517 other_sids info3 fields as trusted domain, universal group
1518 memberships, and nested groups (win2k native mode only) are not
1519 returned by the getgroups RPC call but are present in the info3. */
1521 struct getgroups_state
{
1522 struct winbindd_cli_state
*state
;
1523 struct winbindd_domain
*domain
;
1528 const DOM_SID
*token_sids
;
1529 size_t i
, num_token_sids
;
1532 size_t num_token_gids
;
1535 static void getgroups_usersid_recv(void *private_data
, bool success
,
1536 const DOM_SID
*sid
, enum lsa_SidType type
);
1537 static void getgroups_tokensids_recv(void *private_data
, bool success
,
1538 DOM_SID
*token_sids
, size_t num_token_sids
);
1539 static void getgroups_sid2gid_recv(void *private_data
, bool success
, gid_t gid
);
1541 void winbindd_getgroups(struct winbindd_cli_state
*state
)
1543 struct getgroups_state
*s
;
1544 char *real_name
= NULL
;
1545 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
1547 /* Ensure null termination */
1548 state
->request
.data
.username
1549 [sizeof(state
->request
.data
.username
)-1]='\0';
1551 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state
->pid
,
1552 state
->request
.data
.username
));
1554 /* Parse domain and username */
1556 s
= TALLOC_P(state
->mem_ctx
, struct getgroups_state
);
1558 DEBUG(0, ("talloc failed\n"));
1559 request_error(state
);
1565 nt_status
= normalize_name_unmap(state
->mem_ctx
,
1566 state
->request
.data
.username
,
1569 /* Reset the real_name pointer if we didn't do anything
1570 productive in the above call */
1571 if (!NT_STATUS_IS_OK(nt_status
) &&
1572 !NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
))
1574 real_name
= state
->request
.data
.username
;
1577 if (!parse_domain_user_talloc(state
->mem_ctx
, real_name
,
1578 &s
->domname
, &s
->username
)) {
1579 DEBUG(5, ("Could not parse domain user: %s\n",
1582 /* error out if we do not have nested group support */
1584 if ( !lp_winbind_nested_groups() ) {
1585 request_error(state
);
1589 s
->domname
= talloc_strdup(state
->mem_ctx
,
1590 get_global_sam_name());
1591 s
->username
= talloc_strdup(state
->mem_ctx
,
1592 state
->request
.data
.username
);
1595 /* Get info for the domain (either by short domain name or
1596 DNS name in the case of a UPN) */
1598 s
->domain
= find_domain_from_name_noinit(s
->domname
);
1600 char *p
= strchr(s
->username
, '@');
1603 s
->domain
= find_domain_from_name_noinit(p
+1);
1608 if (s
->domain
== NULL
) {
1609 DEBUG(7, ("could not find domain entry for domain %s\n",
1611 request_error(state
);
1615 if ( s
->domain
->primary
&& lp_winbind_trusted_domains_only()) {
1616 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1617 "getgroups() for %s\\%s.\n", s
->domname
,
1619 request_error(state
);
1623 /* Get rid and name type from name. The following costs 1 packet */
1625 winbindd_lookupname_async(state
->mem_ctx
,
1626 s
->domname
, s
->username
,
1627 getgroups_usersid_recv
,
1628 WINBINDD_GETGROUPS
, s
);
1631 static void getgroups_usersid_recv(void *private_data
, bool success
,
1632 const DOM_SID
*sid
, enum lsa_SidType type
)
1634 struct getgroups_state
*s
=
1635 (struct getgroups_state
*)private_data
;
1638 ((type
!= SID_NAME_USER
) && (type
!= SID_NAME_COMPUTER
))) {
1639 request_error(s
->state
);
1643 sid_copy(&s
->user_sid
, sid
);
1645 winbindd_gettoken_async(s
->state
->mem_ctx
, &s
->user_sid
,
1646 getgroups_tokensids_recv
, s
);
1649 static void getgroups_tokensids_recv(void *private_data
, bool success
,
1650 DOM_SID
*token_sids
, size_t num_token_sids
)
1652 struct getgroups_state
*s
=
1653 (struct getgroups_state
*)private_data
;
1655 /* We need at least the user sid and the primary group in the token,
1656 * otherwise it's an error */
1658 if ((!success
) || (num_token_sids
< 2)) {
1659 request_error(s
->state
);
1663 s
->token_sids
= token_sids
;
1664 s
->num_token_sids
= num_token_sids
;
1667 s
->token_gids
= NULL
;
1668 s
->num_token_gids
= 0;
1670 getgroups_sid2gid_recv(s
, False
, 0);
1673 static void getgroups_sid2gid_recv(void *private_data
, bool success
, gid_t gid
)
1675 struct getgroups_state
*s
=
1676 (struct getgroups_state
*)private_data
;
1679 if (!add_gid_to_array_unique(s
->state
->mem_ctx
, gid
,
1681 &s
->num_token_gids
)) {
1686 if (s
->i
< s
->num_token_sids
) {
1687 const DOM_SID
*sid
= &s
->token_sids
[s
->i
];
1690 if (sid_equal(sid
, &s
->user_sid
)) {
1691 getgroups_sid2gid_recv(s
, False
, 0);
1695 winbindd_sid2gid_async(s
->state
->mem_ctx
, sid
,
1696 getgroups_sid2gid_recv
, s
);
1700 s
->state
->response
.data
.num_entries
= s
->num_token_gids
;
1701 if (s
->num_token_gids
) {
1702 /* s->token_gids are talloced */
1703 s
->state
->response
.extra_data
.data
=
1704 smb_xmemdup(s
->token_gids
,
1705 s
->num_token_gids
* sizeof(gid_t
));
1706 s
->state
->response
.length
+= s
->num_token_gids
* sizeof(gid_t
);
1708 request_ok(s
->state
);
1711 /* Get user supplementary sids. This is equivalent to the
1712 winbindd_getgroups() function but it involves a SID->SIDs mapping
1713 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1714 idmap. This call is designed to be used with applications that need
1715 to do ACL evaluation themselves. Note that the cached info3 data is
1718 this function assumes that the SID that comes in is a user SID. If
1719 you pass in another type of SID then you may get unpredictable
1723 static void getusersids_recv(void *private_data
, bool success
, DOM_SID
*sids
,
1726 void winbindd_getusersids(struct winbindd_cli_state
*state
)
1730 /* Ensure null termination */
1731 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1733 user_sid
= TALLOC_P(state
->mem_ctx
, DOM_SID
);
1734 if (user_sid
== NULL
) {
1735 DEBUG(1, ("talloc failed\n"));
1736 request_error(state
);
1740 if (!string_to_sid(user_sid
, state
->request
.data
.sid
)) {
1741 DEBUG(1, ("Could not get convert sid %s from string\n",
1742 state
->request
.data
.sid
));
1743 request_error(state
);
1747 winbindd_gettoken_async(state
->mem_ctx
, user_sid
, getusersids_recv
,
1751 static void getusersids_recv(void *private_data
, bool success
, DOM_SID
*sids
,
1754 struct winbindd_cli_state
*state
=
1755 (struct winbindd_cli_state
*)private_data
;
1757 unsigned ofs
, ret_size
= 0;
1761 request_error(state
);
1765 /* work out the response size */
1766 for (i
= 0; i
< num_sids
; i
++) {
1768 sid_to_fstring(s
, &sids
[i
]);
1769 ret_size
+= strlen(s
) + 1;
1772 /* build the reply */
1773 ret
= (char *)SMB_MALLOC(ret_size
);
1775 DEBUG(0, ("malloc failed\n"));
1776 request_error(state
);
1780 for (i
= 0; i
< num_sids
; i
++) {
1782 sid_to_fstring(s
, &sids
[i
]);
1783 safe_strcpy(ret
+ ofs
, s
, ret_size
- ofs
- 1);
1784 ofs
+= strlen(ret
+ofs
) + 1;
1787 /* Send data back to client */
1788 state
->response
.data
.num_entries
= num_sids
;
1789 state
->response
.extra_data
.data
= ret
;
1790 state
->response
.length
+= ret_size
;
1794 void winbindd_getuserdomgroups(struct winbindd_cli_state
*state
)
1797 struct winbindd_domain
*domain
;
1799 /* Ensure null termination */
1800 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1802 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1803 DEBUG(1, ("Could not get convert sid %s from string\n",
1804 state
->request
.data
.sid
));
1805 request_error(state
);
1809 /* Get info for the domain */
1810 if ((domain
= find_domain_from_sid_noinit(&user_sid
)) == NULL
) {
1811 DEBUG(0,("could not find domain entry for sid %s\n",
1812 sid_string_dbg(&user_sid
)));
1813 request_error(state
);
1817 sendto_domain(state
, domain
);
1820 enum winbindd_result
winbindd_dual_getuserdomgroups(struct winbindd_domain
*domain
,
1821 struct winbindd_cli_state
*state
)
1831 /* Ensure null termination */
1832 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1834 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1835 DEBUG(1, ("Could not get convert sid %s from string\n",
1836 state
->request
.data
.sid
));
1837 return WINBINDD_ERROR
;
1840 status
= domain
->methods
->lookup_usergroups(domain
, state
->mem_ctx
,
1841 &user_sid
, &num_groups
,
1843 if (!NT_STATUS_IS_OK(status
))
1844 return WINBINDD_ERROR
;
1846 if (num_groups
== 0) {
1847 state
->response
.data
.num_entries
= 0;
1848 state
->response
.extra_data
.data
= NULL
;
1852 if (!print_sidlist(state
->mem_ctx
,
1854 &sidstring
, &len
)) {
1855 DEBUG(0, ("talloc failed\n"));
1856 return WINBINDD_ERROR
;
1859 state
->response
.extra_data
.data
= SMB_STRDUP(sidstring
);
1860 if (!state
->response
.extra_data
.data
) {
1861 return WINBINDD_ERROR
;
1863 state
->response
.length
+= len
+1;
1864 state
->response
.data
.num_entries
= num_groups
;
1869 void winbindd_getsidaliases(struct winbindd_cli_state
*state
)
1872 struct winbindd_domain
*domain
;
1874 /* Ensure null termination */
1875 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1877 if (!string_to_sid(&domain_sid
, state
->request
.data
.sid
)) {
1878 DEBUG(1, ("Could not get convert sid %s from string\n",
1879 state
->request
.data
.sid
));
1880 request_error(state
);
1884 /* Get info for the domain */
1885 if ((domain
= find_domain_from_sid_noinit(&domain_sid
)) == NULL
) {
1886 DEBUG(0,("could not find domain entry for sid %s\n",
1887 sid_string_dbg(&domain_sid
)));
1888 request_error(state
);
1892 sendto_domain(state
, domain
);
1895 enum winbindd_result
winbindd_dual_getsidaliases(struct winbindd_domain
*domain
,
1896 struct winbindd_cli_state
*state
)
1898 DOM_SID
*sids
= NULL
;
1899 size_t num_sids
= 0;
1900 char *sidstr
= NULL
;
1907 DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state
->pid
));
1909 sidstr
= state
->request
.extra_data
.data
;
1910 if (sidstr
== NULL
) {
1911 sidstr
= talloc_strdup(state
->mem_ctx
, "\n"); /* No SID */
1913 DEBUG(0, ("Out of memory\n"));
1914 return WINBINDD_ERROR
;
1918 DEBUG(10, ("Sidlist: %s\n", sidstr
));
1920 if (!parse_sidlist(state
->mem_ctx
, sidstr
, &sids
, &num_sids
)) {
1921 DEBUG(0, ("Could not parse SID list: %s\n", sidstr
));
1922 return WINBINDD_ERROR
;
1928 result
= domain
->methods
->lookup_useraliases(domain
,
1934 if (!NT_STATUS_IS_OK(result
)) {
1935 DEBUG(3, ("Could not lookup_useraliases: %s\n",
1936 nt_errstr(result
)));
1937 return WINBINDD_ERROR
;
1944 DEBUG(10, ("Got %d aliases\n", num_aliases
));
1946 for (i
=0; i
<num_aliases
; i
++) {
1948 DEBUGADD(10, (" rid %d\n", alias_rids
[i
]));
1949 sid_copy(&sid
, &domain
->sid
);
1950 sid_append_rid(&sid
, alias_rids
[i
]);
1951 result
= add_sid_to_array(state
->mem_ctx
, &sid
, &sids
,
1953 if (!NT_STATUS_IS_OK(result
)) {
1954 return WINBINDD_ERROR
;
1959 if (!print_sidlist(state
->mem_ctx
, sids
, num_sids
, &sidstr
, &len
)) {
1960 DEBUG(0, ("Could not print_sidlist\n"));
1961 state
->response
.extra_data
.data
= NULL
;
1962 return WINBINDD_ERROR
;
1965 state
->response
.extra_data
.data
= NULL
;
1968 state
->response
.extra_data
.data
= SMB_STRDUP(sidstr
);
1969 if (!state
->response
.extra_data
.data
) {
1970 DEBUG(0, ("Out of memory\n"));
1971 return WINBINDD_ERROR
;
1973 DEBUG(10, ("aliases_list: %s\n",
1974 (char *)state
->response
.extra_data
.data
));
1975 state
->response
.length
+= len
+1;
1976 state
->response
.data
.num_entries
= num_sids
;