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/>.
28 extern bool opt_nocache
;
31 #define DBGC_CLASS DBGC_WINBIND
33 static void add_member(const char *domain
, const char *user
,
34 char **pp_members
, size_t *p_num_members
)
38 fill_domain_username(name
, domain
, user
, True
);
39 safe_strcat(name
, ",", sizeof(name
)-1);
40 string_append(pp_members
, name
);
44 /**********************************************************************
45 Add member users resulting from sid. Expand if it is a domain group.
46 **********************************************************************/
48 static void add_expanded_sid(const DOM_SID
*sid
,
50 size_t *p_num_members
)
54 struct winbindd_domain
*domain
;
57 char *domain_name
= NULL
;
59 enum lsa_SidType type
;
68 TALLOC_CTX
*mem_ctx
= talloc_init("add_expanded_sid");
70 if (mem_ctx
== NULL
) {
71 DEBUG(1, ("talloc_init failed\n"));
75 sid_copy(&dom_sid
, sid
);
76 sid_split_rid(&dom_sid
, &rid
);
78 domain
= find_lookup_domain_from_sid(sid
);
81 DEBUG(3, ("Could not find domain for sid %s\n",
82 sid_string_dbg(sid
)));
86 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
,
87 &domain_name
, &name
, &type
);
89 if (!NT_STATUS_IS_OK(result
)) {
90 DEBUG(3, ("sid_to_name failed for sid %s\n",
91 sid_string_dbg(sid
)));
95 DEBUG(10, ("Found name %s, type %d\n", name
, type
));
97 if (type
== SID_NAME_USER
) {
98 add_member(domain_name
, name
, pp_members
, p_num_members
);
102 if (type
!= SID_NAME_DOM_GRP
) {
103 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
108 /* Expand the domain group, this must be done via the target domain */
110 domain
= find_domain_from_sid(sid
);
112 if (domain
== NULL
) {
113 DEBUG(3, ("Could not find domain from SID %s\n",
114 sid_string_dbg(sid
)));
118 result
= domain
->methods
->lookup_groupmem(domain
, mem_ctx
,
123 if (!NT_STATUS_IS_OK(result
)) {
124 DEBUG(10, ("Could not lookup group members for %s: %s\n",
125 name
, nt_errstr(result
)));
129 for (i
=0; i
<num_names
; i
++) {
130 DEBUG(10, ("Adding group member SID %s\n",
131 sid_string_dbg(&sid_mem
[i
])));
133 if (types
[i
] != SID_NAME_USER
) {
134 DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
135 "Ignoring.\n", names
[i
], name
));
139 add_member(domain
->name
, names
[i
], pp_members
, p_num_members
);
143 talloc_destroy(mem_ctx
);
147 static bool fill_passdb_alias_grmem(struct winbindd_domain
*domain
,
148 DOM_SID
*group_sid
, size_t *num_gr_mem
,
149 char **gr_mem
, size_t *gr_mem_len
)
152 size_t i
, num_members
;
158 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid
, &members
,
162 for (i
=0; i
<num_members
; i
++) {
163 add_expanded_sid(&members
[i
], gr_mem
, num_gr_mem
);
166 TALLOC_FREE(members
);
168 if (*gr_mem
!= NULL
) {
171 /* We have at least one member, strip off the last "," */
172 len
= strlen(*gr_mem
);
173 (*gr_mem
)[len
-1] = '\0';
180 /* Fill a grent structure from various other information */
182 static bool fill_grent(TALLOC_CTX
*mem_ctx
, struct winbindd_gr
*gr
,
183 const char *dom_name
,
184 char *gr_name
, gid_t unix_gid
)
186 fstring full_group_name
;
187 char *mapped_name
= NULL
;
188 struct winbindd_domain
*domain
= find_domain_from_name_noinit(dom_name
);
189 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
191 nt_status
= normalize_name_map(mem_ctx
, domain
, gr_name
,
194 /* Basic whitespace replacement */
195 if (NT_STATUS_IS_OK(nt_status
)) {
196 fill_domain_username(full_group_name
, dom_name
,
199 /* Mapped to an aliase */
200 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
)) {
201 fstrcpy(full_group_name
, mapped_name
);
205 fill_domain_username( full_group_name
, dom_name
,
209 gr
->gr_gid
= unix_gid
;
211 /* Group name and password */
213 safe_strcpy(gr
->gr_name
, full_group_name
, sizeof(gr
->gr_name
) - 1);
214 safe_strcpy(gr
->gr_passwd
, "x", sizeof(gr
->gr_passwd
) - 1);
219 /***********************************************************************
220 If "enum users" is set to false, and the group being looked
221 up is the Domain Users SID: S-1-5-domain-513, then for the
222 list of members check if the querying user is in that group,
223 and if so only return that user as the gr_mem array.
224 We can change this to a different parameter than "enum users"
225 if neccessaey, or parameterize the group list we do this for.
226 ***********************************************************************/
228 static bool fill_grent_mem_domusers( TALLOC_CTX
*mem_ctx
,
229 struct winbindd_domain
*domain
,
230 struct winbindd_cli_state
*state
,
232 enum lsa_SidType group_name_type
,
233 size_t *num_gr_mem
, char **gr_mem
,
236 DOM_SID querying_user_sid
;
237 DOM_SID
*pquerying_user_sid
= NULL
;
238 uint32 num_groups
= 0;
239 DOM_SID
*user_sids
= NULL
;
240 bool u_in_group
= False
;
243 unsigned int buf_len
= 0;
246 DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
250 uid_t ret_uid
= (uid_t
)-1;
251 if (sys_getpeereid(state
->sock
, &ret_uid
)==0) {
252 /* We know who's asking - look up their SID if
253 it's one we've mapped before. */
254 status
= idmap_uid_to_sid(domain
->name
,
255 &querying_user_sid
, ret_uid
);
256 if (NT_STATUS_IS_OK(status
)) {
257 pquerying_user_sid
= &querying_user_sid
;
258 DEBUG(10,("fill_grent_mem_domain_users: "
259 "querying uid %u -> %s\n",
260 (unsigned int)ret_uid
,
261 sid_string_dbg(pquerying_user_sid
)));
266 /* Only look up if it was a winbindd user in this domain. */
267 if (pquerying_user_sid
&&
268 (sid_compare_domain(pquerying_user_sid
, &domain
->sid
) == 0)) {
270 DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
271 sid_string_dbg(pquerying_user_sid
) ));
273 status
= domain
->methods
->lookup_usergroups(domain
,
278 if (!NT_STATUS_IS_OK(status
)) {
279 DEBUG(1, ("fill_grent_mem_domain_users: "
280 "lookup_usergroups failed "
281 "for sid %s in domain %s (error: %s)\n",
282 sid_string_dbg(pquerying_user_sid
),
288 for (i
= 0; i
< num_groups
; i
++) {
289 if (sid_equal(group_sid
, &user_sids
[i
])) {
290 /* User is in Domain Users, add their name
291 as the only group member. */
300 char *domainname
= NULL
;
301 char *username
= NULL
;
303 char *mapped_name
= NULL
;
304 enum lsa_SidType type
;
305 struct winbindd_domain
*target_domain
= NULL
;
306 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
308 DEBUG(10,("fill_grent_mem_domain_users: "
309 "sid %s in 'Domain Users' in domain %s\n",
310 sid_string_dbg(pquerying_user_sid
),
313 status
= domain
->methods
->sid_to_name(domain
, mem_ctx
,
318 if (!NT_STATUS_IS_OK(status
)) {
319 DEBUG(1, ("could not lookup username for user "
320 "sid %s in domain %s (error: %s)\n",
321 sid_string_dbg(pquerying_user_sid
),
327 target_domain
= find_domain_from_name_noinit(domainname
);
328 name_map_status
= normalize_name_map(mem_ctx
, target_domain
,
329 username
, &mapped_name
);
331 /* Basic whitespace replacement */
332 if (NT_STATUS_IS_OK(name_map_status
)) {
333 fill_domain_username(name
, domainname
, mapped_name
, true);
335 /* Mapped to an alias */
336 else if (NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
)) {
337 fstrcpy(name
, mapped_name
);
339 /* no mapping done...use original name */
341 fill_domain_username(name
, domainname
, username
, true);
346 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
347 DEBUG(1, ("out of memory\n"));
350 memcpy(buf
, name
, buf_len
);
352 DEBUG(10,("fill_grent_mem_domain_users: user %s in "
353 "'Domain Users' in domain %s\n",
354 name
, domain
->name
));
356 /* user is the only member */
361 *gr_mem_len
= buf_len
;
363 DEBUG(10, ("fill_grent_mem_domain_users: "
364 "num_mem = %u, len = %u, mem = %s\n",
365 (unsigned int)*num_gr_mem
,
366 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
371 /***********************************************************************
372 Add names to a list. Assumes a canonical version of the string
374 ***********************************************************************/
376 static int namecmp( const void *a
, const void *b
)
378 return StrCaseCmp( * (char * const *) a
, * (char * const *) b
);
381 static NTSTATUS
add_names_to_list( TALLOC_CTX
*ctx
,
382 char ***list
, uint32
*n_list
,
383 char **names
, uint32 n_names
)
385 char **new_list
= NULL
;
386 uint32 n_new_list
= 0;
389 if ( !names
|| (n_names
== 0) )
392 /* Alloc the maximum size we'll need */
394 if ( *list
== NULL
) {
395 if ((new_list
= TALLOC_ARRAY(ctx
, char *, n_names
)) == NULL
) {
396 return NT_STATUS_NO_MEMORY
;
398 n_new_list
= n_names
;
400 new_list
= TALLOC_REALLOC_ARRAY( ctx
, *list
, char *,
401 (*n_list
) + n_names
);
403 return NT_STATUS_NO_MEMORY
;
404 n_new_list
= (*n_list
) + n_names
;
409 for ( i
=*n_list
, j
=0; i
<n_new_list
; i
++, j
++ ) {
410 new_list
[i
] = talloc_strdup( new_list
, names
[j
] );
413 /* search for duplicates for sorting and looking for matching
416 qsort( new_list
, n_new_list
, sizeof(char*), QSORT_CAST namecmp
);
418 for ( i
=1; i
<n_new_list
; i
++ ) {
419 if ( strcmp( new_list
[i
-1], new_list
[i
] ) == 0 ) {
420 memmove( &new_list
[i
-1], &new_list
[i
],
421 sizeof(char*)*(n_new_list
-i
) );
427 *n_list
= n_new_list
;
432 /***********************************************************************
433 ***********************************************************************/
435 static NTSTATUS
expand_groups( TALLOC_CTX
*ctx
,
436 struct winbindd_domain
*d
,
437 DOM_SID
*glist
, uint32 n_glist
,
438 DOM_SID
**new_glist
, uint32
*n_new_glist
,
439 char ***members
, uint32
*n_members
)
442 NTSTATUS status
= NT_STATUS_OK
;
443 uint32 num_names
= 0;
444 uint32
*name_types
= NULL
;
446 DOM_SID
*sid_mem
= NULL
;
447 TALLOC_CTX
*tmp_ctx
= NULL
;
448 DOM_SID
*new_groups
= NULL
;
449 size_t new_groups_size
= 0;
456 for ( i
=0; i
<n_glist
; i
++ ) {
457 tmp_ctx
= talloc_new( ctx
);
459 /* Lookup the group membership */
461 status
= d
->methods
->lookup_groupmem(d
, tmp_ctx
,
462 &glist
[i
], &num_names
,
465 if ( !NT_STATUS_IS_OK(status
) )
468 /* Separate users and groups into two lists */
470 for ( j
=0; j
<num_names
; j
++ ) {
473 if ( name_types
[j
] == SID_NAME_USER
||
474 name_types
[j
] == SID_NAME_COMPUTER
)
476 status
= add_names_to_list( ctx
, members
,
479 if ( !NT_STATUS_IS_OK(status
) )
486 if ( name_types
[j
] == SID_NAME_DOM_GRP
||
487 name_types
[j
] == SID_NAME_ALIAS
)
489 status
= add_sid_to_array_unique(ctx
,
493 if (!NT_STATUS_IS_OK(status
)) {
501 TALLOC_FREE( tmp_ctx
);
504 *new_glist
= new_groups
;
505 *n_new_glist
= (uint32
)new_groups_size
;
508 TALLOC_FREE( tmp_ctx
);
513 /***********************************************************************
514 Fill in the group membership field of a NT group given by group_sid
515 ***********************************************************************/
517 static bool fill_grent_mem(struct winbindd_domain
*domain
,
518 struct winbindd_cli_state
*state
,
520 enum lsa_SidType group_name_type
,
521 size_t *num_gr_mem
, char **gr_mem
,
524 uint32 num_names
= 0;
525 unsigned int buf_len
= 0, buf_ndx
= 0, i
;
526 char **names
= NULL
, *buf
= NULL
;
530 DOM_SID
*glist
= NULL
;
531 DOM_SID
*new_glist
= NULL
;
532 uint32 n_glist
, n_new_glist
;
533 int max_depth
= lp_winbind_expand_groups();
535 if (!(mem_ctx
= talloc_init("fill_grent_mem(%s)", domain
->name
)))
538 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid
)));
540 /* Initialize with no members */
544 /* HACK ALERT!! This whole routine does not cope with group members
545 * from more than one domain, ie aliases. Thus we have to work it out
546 * ourselves in a special routine. */
548 if (domain
->internal
) {
549 result
= fill_passdb_alias_grmem(domain
, group_sid
,
555 /* Verify name type */
557 if ( !((group_name_type
==SID_NAME_DOM_GRP
) ||
558 ((group_name_type
==SID_NAME_ALIAS
) && domain
->primary
)) )
560 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
561 sid_string_dbg(group_sid
),
562 domain
->name
, group_name_type
));
566 /* OPTIMIZATION / HACK. See comment in
567 fill_grent_mem_domusers() */
569 sid_peek_rid( group_sid
, &group_rid
);
570 if (!lp_winbind_enum_users() && group_rid
== DOMAIN_GROUP_RID_USERS
) {
571 result
= fill_grent_mem_domusers( mem_ctx
, domain
, state
,
572 group_sid
, group_name_type
,
578 /* Real work goes here. Create a list of group names to
579 expand startign with the initial one. Pass that to
580 expand_groups() which returns a list of more group names
581 to expand. Do this up to the max search depth. */
583 if ( (glist
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, 1 )) == NULL
) {
585 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
588 sid_copy( &glist
[0], group_sid
);
591 for ( i
=0; i
<max_depth
&& glist
; i
++ ) {
592 uint32 n_members
= 0;
593 char **members
= NULL
;
597 nt_status
= expand_groups( mem_ctx
, domain
,
599 &new_glist
, &n_new_glist
,
600 &members
, &n_members
);
601 if ( !NT_STATUS_IS_OK(nt_status
) ) {
606 /* Add new group members to list. Pass through the
607 alias mapping function */
609 for (j
=0; j
<n_members
; j
++) {
610 fstring name_domain
, name_acct
;
611 fstring qualified_name
;
612 char *mapped_name
= NULL
;
613 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
614 struct winbindd_domain
*target_domain
= NULL
;
616 if (parse_domain_user(members
[j
], name_domain
, name_acct
)) {
617 target_domain
= find_domain_from_name_noinit(name_domain
);
620 if (!target_domain
) {
621 target_domain
= domain
;
624 name_map_status
= normalize_name_map(members
, target_domain
,
625 name_acct
, &mapped_name
);
627 /* Basic whitespace replacement */
628 if (NT_STATUS_IS_OK(name_map_status
)) {
629 fill_domain_username(qualified_name
, name_domain
,
631 mapped_name
= qualified_name
;
633 /* no mapping at all */
634 else if (!NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
)) {
635 mapped_name
= members
[j
];
638 nt_status
= add_names_to_list( mem_ctx
, &names
,
641 if ( !NT_STATUS_IS_OK(nt_status
) ) {
647 TALLOC_FREE( members
);
649 /* If we have no more groups to expand, break out
652 if (new_glist
== NULL
)
658 n_glist
= n_new_glist
;
660 TALLOC_FREE( glist
);
662 DEBUG(10, ("looked up %d names\n", num_names
));
665 /* Add members to list */
667 for (i
= 0; i
< num_names
; i
++) {
670 DEBUG(10, ("processing name %s\n", names
[i
]));
672 len
= strlen(names
[i
]);
674 /* Add to list or calculate buffer length */
677 buf_len
+= len
+ 1; /* List is comma separated */
679 DEBUG(10, ("buf_len + %d = %d\n", len
+ 1, buf_len
));
681 DEBUG(10, ("appending %s at ndx %d\n",
683 parse_add_domuser(&buf
[buf_ndx
], names
[i
], &len
);
690 /* Allocate buffer */
692 if (!buf
&& buf_len
!= 0) {
693 if (!(buf
= (char *)SMB_MALLOC(buf_len
))) {
694 DEBUG(1, ("out of memory\n"));
698 memset(buf
, 0, buf_len
);
704 if (buf
&& buf_ndx
> 0) {
705 buf
[buf_ndx
- 1] = '\0';
709 *gr_mem_len
= buf_len
;
711 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n",
712 (unsigned int)*num_gr_mem
,
713 (unsigned int)buf_len
, *num_gr_mem
? buf
: "NULL"));
718 talloc_destroy(mem_ctx
);
720 DEBUG(10, ("fill_grent_mem returning %d\n", result
));
725 static void winbindd_getgrsid(struct winbindd_cli_state
*state
, DOM_SID group_sid
);
727 static void getgrnam_recv( void *private_data
, bool success
, const DOM_SID
*sid
,
728 enum lsa_SidType type
)
730 struct winbindd_cli_state
*state
= (struct winbindd_cli_state
*)private_data
;
733 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
734 request_error(state
);
738 if ( (type
!= SID_NAME_DOM_GRP
) && (type
!= SID_NAME_ALIAS
) ) {
739 DEBUG(5,("getgrnam_recv: not a group!\n"));
740 request_error(state
);
744 winbindd_getgrsid( state
, *sid
);
748 /* Return a group structure from a group name */
750 void winbindd_getgrnam(struct winbindd_cli_state
*state
)
752 struct winbindd_domain
*domain
;
753 fstring name_domain
, name_group
;
755 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
757 /* Ensure null termination */
758 state
->request
.data
.groupname
[sizeof(state
->request
.data
.groupname
)-1]='\0';
760 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state
->pid
,
761 state
->request
.data
.groupname
));
763 nt_status
= normalize_name_unmap(state
->mem_ctx
,
764 state
->request
.data
.groupname
,
766 /* If we didn't map anything in the above call, just reset the
767 tmp pointer to the original string */
768 if (!NT_STATUS_IS_OK(nt_status
) &&
769 !NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
))
771 tmp
= state
->request
.data
.groupname
;
774 /* Parse domain and groupname */
776 memset(name_group
, 0, sizeof(name_group
));
778 name_domain
[0] = '\0';
779 name_group
[0] = '\0';
781 parse_domain_user(tmp
, name_domain
, name_group
);
783 /* if no domain or our local domain and no local tdb group, default to
784 * our local domain for aliases */
786 if ( !*name_domain
|| strequal(name_domain
, get_global_sam_name()) ) {
787 fstrcpy(name_domain
, get_global_sam_name());
790 /* Get info for the domain */
792 if ((domain
= find_domain_from_name(name_domain
)) == NULL
) {
793 DEBUG(3, ("could not get domain sid for domain %s\n",
795 request_error(state
);
798 /* should we deal with users for our domain? */
800 if ( lp_winbind_trusted_domains_only() && domain
->primary
) {
801 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
802 "getgrnam() for %s\\%s.\n", name_domain
, name_group
));
803 request_error(state
);
807 /* Get rid and name type from name */
809 fstrcpy( name_group
, tmp
);
811 winbindd_lookupname_async( state
->mem_ctx
, domain
->name
, name_group
,
812 getgrnam_recv
, WINBINDD_GETGRNAM
, state
);
815 struct getgrsid_state
{
816 struct winbindd_cli_state
*state
;
817 struct winbindd_domain
*domain
;
819 enum lsa_SidType group_type
;
824 static void getgrsid_sid2gid_recv(void *private_data
, bool success
, gid_t gid
)
826 struct getgrsid_state
*s
=
827 (struct getgrsid_state
*)private_data
;
828 struct winbindd_domain
*domain
;
832 fstring dom_name
, group_name
;
835 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
836 request_error(s
->state
);
842 if ( !parse_domain_user( s
->group_name
, dom_name
, group_name
) ) {
843 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
844 request_error(s
->state
);
849 /* Fill in group structure */
851 if ( (domain
= find_domain_from_name_noinit(dom_name
)) == NULL
) {
852 DEBUG(1,("Can't find domain from name (%s)\n", dom_name
));
853 request_error(s
->state
);
857 if (!fill_grent(s
->state
->mem_ctx
, &s
->state
->response
.data
.gr
,
858 dom_name
, group_name
, gid
) ||
859 !fill_grent_mem(domain
, s
->state
, &s
->group_sid
, s
->group_type
,
860 &num_gr_mem
, &gr_mem
, &gr_mem_len
))
862 request_error(s
->state
);
866 s
->state
->response
.data
.gr
.num_gr_mem
= (uint32
)num_gr_mem
;
868 /* Group membership lives at start of extra data */
870 s
->state
->response
.data
.gr
.gr_mem_ofs
= 0;
872 s
->state
->response
.length
+= gr_mem_len
;
873 s
->state
->response
.extra_data
.data
= gr_mem
;
875 request_ok(s
->state
);
878 static void getgrsid_lookupsid_recv( void *private_data
, bool success
,
879 const char *dom_name
, const char *name
,
880 enum lsa_SidType name_type
)
882 struct getgrsid_state
*s
= (struct getgrsid_state
*)private_data
;
883 char *mapped_name
= NULL
;
885 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
888 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
889 request_error(s
->state
);
893 /* either it's a domain group, a domain local group, or a
894 local group in an internal domain */
896 if ( !( (name_type
==SID_NAME_DOM_GRP
) ||
897 ((name_type
==SID_NAME_ALIAS
) &&
898 (s
->domain
->primary
|| s
->domain
->internal
)) ) )
900 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
901 dom_name
, name
, name_type
));
902 request_error(s
->state
);
906 /* normalize the name and ensure that we have the DOM\name
907 coming out of here */
909 fstrcpy(raw_name
, name
);
911 nt_status
= normalize_name_unmap(s
->state
->mem_ctx
, raw_name
,
914 /* basiuc whitespace reversal */
915 if (NT_STATUS_IS_OK(nt_status
)) {
916 s
->group_name
= talloc_asprintf(s
->state
->mem_ctx
,
919 *lp_winbind_separator(),
922 /* mapped from alias */
923 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
)) {
924 s
->group_name
= mapped_name
;
926 /* no mapping at all. use original string */
928 s
->group_name
= talloc_asprintf(s
->state
->mem_ctx
,
931 *lp_winbind_separator(),
935 if (s
->group_name
== NULL
) {
936 DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
937 request_error(s
->state
);
941 s
->group_type
= name_type
;
943 winbindd_sid2gid_async(s
->state
->mem_ctx
, &s
->group_sid
,
944 getgrsid_sid2gid_recv
, s
);
947 static void winbindd_getgrsid( struct winbindd_cli_state
*state
, const DOM_SID group_sid
)
949 struct getgrsid_state
*s
;
951 if ( (s
= TALLOC_ZERO_P(state
->mem_ctx
, struct getgrsid_state
)) == NULL
) {
952 DEBUG(0, ("talloc failed\n"));
953 request_error(state
);
959 if ( (s
->domain
= find_domain_from_sid_noinit(&group_sid
)) == NULL
) {
960 DEBUG(3, ("Could not find domain for sid %s\n",
961 sid_string_dbg(&group_sid
)));
962 request_error(state
);
966 sid_copy(&s
->group_sid
, &group_sid
);
968 winbindd_lookupsid_async( s
->state
->mem_ctx
, &group_sid
,
969 getgrsid_lookupsid_recv
, s
);
973 static void getgrgid_recv(void *private_data
, bool success
, const char *sid
)
975 struct winbindd_cli_state
*state
= talloc_get_type_abort(private_data
, struct winbindd_cli_state
);
976 enum lsa_SidType name_type
;
980 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
981 (unsigned long)(state
->request
.data
.gid
), sid
));
983 string_to_sid(&group_sid
, sid
);
984 winbindd_getgrsid(state
, group_sid
);
988 /* Ok, this might be "ours", i.e. an alias */
989 if (pdb_gid_to_sid(state
->request
.data
.gid
, &group_sid
) &&
990 lookup_sid(state
->mem_ctx
, &group_sid
, NULL
, NULL
, &name_type
) &&
991 (name_type
== SID_NAME_ALIAS
)) {
992 /* Hey, got an alias */
993 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
994 (unsigned long)(state
->request
.data
.gid
), sid
));
995 winbindd_getgrsid(state
, group_sid
);
999 DEBUG(1, ("could not convert gid %lu to sid\n",
1000 (unsigned long)state
->request
.data
.gid
));
1001 request_error(state
);
1004 /* Return a group structure from a gid number */
1005 void winbindd_getgrgid(struct winbindd_cli_state
*state
)
1007 gid_t gid
= state
->request
.data
.gid
;
1009 DEBUG(3, ("[%5lu]: getgrgid %lu\n",
1010 (unsigned long)state
->pid
,
1011 (unsigned long)gid
));
1013 /* always use the async interface */
1014 winbindd_gid2sid_async(state
->mem_ctx
, gid
, getgrgid_recv
, state
);
1018 * set/get/endgrent functions
1021 /* "Rewind" file pointer for group database enumeration */
1023 static bool winbindd_setgrent_internal(struct winbindd_cli_state
*state
)
1025 struct winbindd_domain
*domain
;
1027 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state
->pid
));
1029 /* Check user has enabled this */
1031 if (!lp_winbind_enum_groups()) {
1035 /* Free old static data if it exists */
1037 if (state
->getgrent_state
!= NULL
) {
1038 free_getent_state(state
->getgrent_state
);
1039 state
->getgrent_state
= NULL
;
1042 /* Create sam pipes for each domain we know about */
1044 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
1045 struct getent_state
*domain_state
;
1047 /* Create a state record for this domain */
1049 /* don't add our domaina if we are a PDC or if we
1050 are a member of a Samba domain */
1052 if ( lp_winbind_trusted_domains_only() && domain
->primary
)
1057 domain_state
= SMB_MALLOC_P(struct getent_state
);
1058 if (!domain_state
) {
1059 DEBUG(1, ("winbindd_setgrent: "
1060 "malloc failed for domain_state!\n"));
1064 ZERO_STRUCTP(domain_state
);
1066 fstrcpy(domain_state
->domain_name
, domain
->name
);
1068 /* Add to list of open domains */
1070 DLIST_ADD(state
->getgrent_state
, domain_state
);
1073 state
->getgrent_initialized
= True
;
1077 void winbindd_setgrent(struct winbindd_cli_state
*state
)
1079 if (winbindd_setgrent_internal(state
)) {
1082 request_error(state
);
1086 /* Close file pointer to ntdom group database */
1088 void winbindd_endgrent(struct winbindd_cli_state
*state
)
1090 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state
->pid
));
1092 free_getent_state(state
->getgrent_state
);
1093 state
->getgrent_initialized
= False
;
1094 state
->getgrent_state
= NULL
;
1098 /* Get the list of domain groups and domain aliases for a domain. We fill in
1099 the sam_entries and num_sam_entries fields with domain group information.
1100 Return True if some groups were returned, False otherwise. */
1102 bool get_sam_group_entries(struct getent_state
*ent
)
1106 struct acct_info
*name_list
= NULL
;
1107 TALLOC_CTX
*mem_ctx
;
1108 bool result
= False
;
1109 struct acct_info
*sam_grp_entries
= NULL
;
1110 struct winbindd_domain
*domain
;
1112 if (ent
->got_sam_entries
)
1115 if (!(mem_ctx
= talloc_init("get_sam_group_entries(%s)",
1116 ent
->domain_name
))) {
1117 DEBUG(1, ("get_sam_group_entries: "
1118 "could not create talloc context!\n"));
1122 /* Free any existing group info */
1124 SAFE_FREE(ent
->sam_entries
);
1125 ent
->num_sam_entries
= 0;
1126 ent
->got_sam_entries
= True
;
1128 /* Enumerate domain groups */
1132 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
1133 DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
1138 /* always get the domain global groups */
1140 status
= domain
->methods
->enum_dom_groups(domain
, mem_ctx
, &num_entries
,
1143 if (!NT_STATUS_IS_OK(status
)) {
1144 DEBUG(3, ("get_sam_group_entries: "
1145 "could not enumerate domain groups! Error: %s\n",
1146 nt_errstr(status
)));
1151 /* Copy entries into return buffer */
1154 name_list
= SMB_MALLOC_ARRAY(struct acct_info
, num_entries
);
1156 DEBUG(0,("get_sam_group_entries: Failed to malloc "
1157 "memory for %d domain groups!\n",
1162 memcpy(name_list
, sam_grp_entries
,
1163 num_entries
* sizeof(struct acct_info
));
1166 ent
->num_sam_entries
= num_entries
;
1168 /* get the domain local groups if we are a member of a native win2k
1169 * domain and are not using LDAP to get the groups */
1171 if ( ( lp_security() != SEC_ADS
&& domain
->native_mode
1172 && domain
->primary
) || domain
->internal
)
1174 DEBUG(4,("get_sam_group_entries: %s domain; "
1175 "enumerating local groups as well\n",
1176 domain
->native_mode
? "Native Mode 2k":
1177 "BUILTIN or local"));
1179 status
= domain
->methods
->enum_local_groups(domain
, mem_ctx
,
1183 if ( !NT_STATUS_IS_OK(status
) ) {
1184 DEBUG(3,("get_sam_group_entries: "
1185 "Failed to enumerate "
1186 "domain local groups with error %s!\n",
1187 nt_errstr(status
)));
1191 DEBUG(4,("get_sam_group_entries: "
1192 "Returned %d local groups\n",
1195 /* Copy entries into return buffer */
1197 if ( num_entries
) {
1198 name_list
= SMB_REALLOC_ARRAY(name_list
,
1200 ent
->num_sam_entries
+
1203 DEBUG(0,("get_sam_group_entries: "
1204 "Failed to realloc more memory "
1205 "for %d local groups!\n",
1211 memcpy(&name_list
[ent
->num_sam_entries
],
1213 num_entries
* sizeof(struct acct_info
));
1216 ent
->num_sam_entries
+= num_entries
;
1220 /* Fill in remaining fields */
1222 ent
->sam_entries
= name_list
;
1223 ent
->sam_entry_index
= 0;
1225 result
= (ent
->num_sam_entries
> 0);
1228 talloc_destroy(mem_ctx
);
1233 /* Fetch next group entry from ntdom database */
1235 #define MAX_GETGRENT_GROUPS 500
1237 void winbindd_getgrent(struct winbindd_cli_state
*state
)
1239 struct getent_state
*ent
;
1240 struct winbindd_gr
*group_list
= NULL
;
1241 int num_groups
, group_list_ndx
, gr_mem_list_len
= 0;
1242 char *gr_mem_list
= NULL
;
1244 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state
->pid
));
1246 /* Check user has enabled this */
1248 if (!lp_winbind_enum_groups()) {
1249 request_error(state
);
1253 num_groups
= MIN(MAX_GETGRENT_GROUPS
, state
->request
.data
.num_entries
);
1255 if (num_groups
== 0) {
1256 request_error(state
);
1260 group_list
= SMB_MALLOC_ARRAY(struct winbindd_gr
, num_groups
);
1262 request_error(state
);
1265 /* will be freed by process_request() */
1266 state
->response
.extra_data
.data
= group_list
;
1268 memset(state
->response
.extra_data
.data
, '\0',
1269 num_groups
* sizeof(struct winbindd_gr
) );
1271 state
->response
.data
.num_entries
= 0;
1273 if (!state
->getgrent_initialized
)
1274 winbindd_setgrent_internal(state
);
1276 if (!(ent
= state
->getgrent_state
)) {
1277 request_error(state
);
1281 /* Start sending back groups */
1283 for (group_list_ndx
= 0; group_list_ndx
< num_groups
; ) {
1284 struct acct_info
*name_list
= NULL
;
1285 fstring domain_group_name
;
1291 struct winbindd_domain
*domain
;
1293 /* Do we need to fetch another chunk of groups? */
1297 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1298 ent
->sam_entry_index
, ent
->num_sam_entries
));
1300 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
1302 while(ent
&& !get_sam_group_entries(ent
)) {
1303 struct getent_state
*next_ent
;
1305 DEBUG(10, ("freeing state info for domain %s\n",
1308 /* Free state information for this domain */
1310 SAFE_FREE(ent
->sam_entries
);
1312 next_ent
= ent
->next
;
1313 DLIST_REMOVE(state
->getgrent_state
, ent
);
1319 /* No more domains */
1325 name_list
= (struct acct_info
*)ent
->sam_entries
;
1327 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
1328 DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
1334 /* Lookup group info */
1336 sid_copy(&group_sid
, &domain
->sid
);
1337 sid_append_rid(&group_sid
, name_list
[ent
->sam_entry_index
].rid
);
1339 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain
->name
, &group_sid
,
1342 enum lsa_SidType type
;
1344 DEBUG(10, ("SID %s not in idmap\n",
1345 sid_string_dbg(&group_sid
)));
1347 if (!pdb_sid_to_id(&group_sid
, &id
, &type
)) {
1348 DEBUG(1,("could not look up gid for group %s\n",
1349 name_list
[ent
->sam_entry_index
].acct_name
));
1350 ent
->sam_entry_index
++;
1354 if ((type
!= SID_NAME_DOM_GRP
) &&
1355 (type
!= SID_NAME_ALIAS
) &&
1356 (type
!= SID_NAME_WKN_GRP
)) {
1357 DEBUG(1, ("Group %s is a %s, not a group\n",
1358 sid_type_lookup(type
),
1359 name_list
[ent
->sam_entry_index
].acct_name
));
1360 ent
->sam_entry_index
++;
1366 DEBUG(10, ("got gid %lu for group %lu\n",
1367 (unsigned long)group_gid
,
1368 (unsigned long)name_list
[ent
->sam_entry_index
].rid
));
1370 /* Fill in group entry */
1372 fill_domain_username(domain_group_name
, ent
->domain_name
,
1373 name_list
[ent
->sam_entry_index
].acct_name
, True
);
1375 result
= fill_grent(state
->mem_ctx
, &group_list
[group_list_ndx
],
1377 name_list
[ent
->sam_entry_index
].acct_name
,
1380 /* Fill in group membership entry */
1383 size_t num_gr_mem
= 0;
1385 group_list
[group_list_ndx
].num_gr_mem
= 0;
1389 /* Get group membership */
1390 if (state
->request
.cmd
== WINBINDD_GETGRLST
) {
1393 sid_copy(&member_sid
, &domain
->sid
);
1394 sid_append_rid(&member_sid
, name_list
[ent
->sam_entry_index
].rid
);
1395 result
= fill_grent_mem(
1401 &gr_mem
, &gr_mem_len
);
1403 group_list
[group_list_ndx
].num_gr_mem
= (uint32
)num_gr_mem
;
1408 /* Append to group membership list */
1409 gr_mem_list
= (char *)SMB_REALLOC(
1410 gr_mem_list
, gr_mem_list_len
+ gr_mem_len
);
1413 (group_list
[group_list_ndx
].num_gr_mem
!= 0)) {
1414 DEBUG(0, ("out of memory\n"));
1415 gr_mem_list_len
= 0;
1419 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1420 gr_mem_list_len
, (unsigned int)gr_mem_len
));
1422 memcpy(&gr_mem_list
[gr_mem_list_len
], gr_mem
,
1427 group_list
[group_list_ndx
].gr_mem_ofs
=
1430 gr_mem_list_len
+= gr_mem_len
;
1433 ent
->sam_entry_index
++;
1435 /* Add group to return list */
1439 DEBUG(10, ("adding group num_entries = %d\n",
1440 state
->response
.data
.num_entries
));
1443 state
->response
.data
.num_entries
++;
1445 state
->response
.length
+=
1446 sizeof(struct winbindd_gr
);
1449 DEBUG(0, ("could not lookup domain group %s\n",
1450 domain_group_name
));
1454 /* Copy the list of group memberships to the end of the extra data */
1456 if (group_list_ndx
== 0)
1459 state
->response
.extra_data
.data
= SMB_REALLOC(
1460 state
->response
.extra_data
.data
,
1461 group_list_ndx
* sizeof(struct winbindd_gr
) + gr_mem_list_len
);
1463 if (!state
->response
.extra_data
.data
) {
1464 DEBUG(0, ("out of memory\n"));
1466 SAFE_FREE(gr_mem_list
);
1467 request_error(state
);
1471 memcpy(&((char *)state
->response
.extra_data
.data
)
1472 [group_list_ndx
* sizeof(struct winbindd_gr
)],
1473 gr_mem_list
, gr_mem_list_len
);
1475 state
->response
.length
+= gr_mem_list_len
;
1477 DEBUG(10, ("returning %d groups, length = %d\n",
1478 group_list_ndx
, gr_mem_list_len
));
1480 /* Out of domains */
1484 SAFE_FREE(gr_mem_list
);
1486 if (group_list_ndx
> 0)
1489 request_error(state
);
1492 /* List domain groups without mapping to unix ids */
1493 void winbindd_list_groups(struct winbindd_cli_state
*state
)
1495 winbindd_list_ent(state
, LIST_GROUPS
);
1498 /* Get user supplementary groups. This is much quicker than trying to
1499 invert the groups database. We merge the groups from the gids and
1500 other_sids info3 fields as trusted domain, universal group
1501 memberships, and nested groups (win2k native mode only) are not
1502 returned by the getgroups RPC call but are present in the info3. */
1504 struct getgroups_state
{
1505 struct winbindd_cli_state
*state
;
1506 struct winbindd_domain
*domain
;
1511 const DOM_SID
*token_sids
;
1512 size_t i
, num_token_sids
;
1515 size_t num_token_gids
;
1518 static void getgroups_usersid_recv(void *private_data
, bool success
,
1519 const DOM_SID
*sid
, enum lsa_SidType type
);
1520 static void getgroups_tokensids_recv(void *private_data
, bool success
,
1521 DOM_SID
*token_sids
, size_t num_token_sids
);
1522 static void getgroups_sid2gid_recv(void *private_data
, bool success
, gid_t gid
);
1524 void winbindd_getgroups(struct winbindd_cli_state
*state
)
1526 struct getgroups_state
*s
;
1527 char *real_name
= NULL
;
1528 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
1530 /* Ensure null termination */
1531 state
->request
.data
.username
1532 [sizeof(state
->request
.data
.username
)-1]='\0';
1534 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state
->pid
,
1535 state
->request
.data
.username
));
1537 /* Parse domain and username */
1539 s
= TALLOC_P(state
->mem_ctx
, struct getgroups_state
);
1541 DEBUG(0, ("talloc failed\n"));
1542 request_error(state
);
1548 nt_status
= normalize_name_unmap(state
->mem_ctx
,
1549 state
->request
.data
.username
,
1552 /* Reset the real_name pointer if we didn't do anything
1553 productive in the above call */
1554 if (!NT_STATUS_IS_OK(nt_status
) &&
1555 !NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
))
1557 real_name
= state
->request
.data
.username
;
1560 if (!parse_domain_user_talloc(state
->mem_ctx
, real_name
,
1561 &s
->domname
, &s
->username
)) {
1562 DEBUG(5, ("Could not parse domain user: %s\n",
1565 /* error out if we do not have nested group support */
1567 if ( !lp_winbind_nested_groups() ) {
1568 request_error(state
);
1572 s
->domname
= talloc_strdup(state
->mem_ctx
,
1573 get_global_sam_name());
1574 s
->username
= talloc_strdup(state
->mem_ctx
,
1575 state
->request
.data
.username
);
1578 /* Get info for the domain (either by short domain name or
1579 DNS name in the case of a UPN) */
1581 s
->domain
= find_domain_from_name_noinit(s
->domname
);
1583 char *p
= strchr(s
->username
, '@');
1586 s
->domain
= find_domain_from_name_noinit(p
+1);
1591 if (s
->domain
== NULL
) {
1592 DEBUG(7, ("could not find domain entry for domain %s\n",
1594 request_error(state
);
1598 if ( s
->domain
->primary
&& lp_winbind_trusted_domains_only()) {
1599 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1600 "getgroups() for %s\\%s.\n", s
->domname
,
1602 request_error(state
);
1606 /* Get rid and name type from name. The following costs 1 packet */
1608 winbindd_lookupname_async(state
->mem_ctx
,
1609 s
->domname
, s
->username
,
1610 getgroups_usersid_recv
,
1611 WINBINDD_GETGROUPS
, s
);
1614 static void getgroups_usersid_recv(void *private_data
, bool success
,
1615 const DOM_SID
*sid
, enum lsa_SidType type
)
1617 struct getgroups_state
*s
=
1618 (struct getgroups_state
*)private_data
;
1621 ((type
!= SID_NAME_USER
) && (type
!= SID_NAME_COMPUTER
))) {
1622 request_error(s
->state
);
1626 sid_copy(&s
->user_sid
, sid
);
1628 winbindd_gettoken_async(s
->state
->mem_ctx
, &s
->user_sid
,
1629 getgroups_tokensids_recv
, s
);
1632 static void getgroups_tokensids_recv(void *private_data
, bool success
,
1633 DOM_SID
*token_sids
, size_t num_token_sids
)
1635 struct getgroups_state
*s
=
1636 (struct getgroups_state
*)private_data
;
1638 /* We need at least the user sid and the primary group in the token,
1639 * otherwise it's an error */
1641 if ((!success
) || (num_token_sids
< 2)) {
1642 request_error(s
->state
);
1646 s
->token_sids
= token_sids
;
1647 s
->num_token_sids
= num_token_sids
;
1650 s
->token_gids
= NULL
;
1651 s
->num_token_gids
= 0;
1653 getgroups_sid2gid_recv(s
, False
, 0);
1656 static void getgroups_sid2gid_recv(void *private_data
, bool success
, gid_t gid
)
1658 struct getgroups_state
*s
=
1659 (struct getgroups_state
*)private_data
;
1662 if (!add_gid_to_array_unique(s
->state
->mem_ctx
, gid
,
1664 &s
->num_token_gids
)) {
1669 if (s
->i
< s
->num_token_sids
) {
1670 const DOM_SID
*sid
= &s
->token_sids
[s
->i
];
1673 if (sid_equal(sid
, &s
->user_sid
)) {
1674 getgroups_sid2gid_recv(s
, False
, 0);
1678 winbindd_sid2gid_async(s
->state
->mem_ctx
, sid
,
1679 getgroups_sid2gid_recv
, s
);
1683 s
->state
->response
.data
.num_entries
= s
->num_token_gids
;
1684 if (s
->num_token_gids
) {
1685 /* s->token_gids are talloced */
1686 s
->state
->response
.extra_data
.data
=
1687 smb_xmemdup(s
->token_gids
,
1688 s
->num_token_gids
* sizeof(gid_t
));
1689 s
->state
->response
.length
+= s
->num_token_gids
* sizeof(gid_t
);
1691 request_ok(s
->state
);
1694 /* Get user supplementary sids. This is equivalent to the
1695 winbindd_getgroups() function but it involves a SID->SIDs mapping
1696 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1697 idmap. This call is designed to be used with applications that need
1698 to do ACL evaluation themselves. Note that the cached info3 data is
1701 this function assumes that the SID that comes in is a user SID. If
1702 you pass in another type of SID then you may get unpredictable
1706 static void getusersids_recv(void *private_data
, bool success
, DOM_SID
*sids
,
1709 void winbindd_getusersids(struct winbindd_cli_state
*state
)
1713 /* Ensure null termination */
1714 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1716 user_sid
= TALLOC_P(state
->mem_ctx
, DOM_SID
);
1717 if (user_sid
== NULL
) {
1718 DEBUG(1, ("talloc failed\n"));
1719 request_error(state
);
1723 if (!string_to_sid(user_sid
, state
->request
.data
.sid
)) {
1724 DEBUG(1, ("Could not get convert sid %s from string\n",
1725 state
->request
.data
.sid
));
1726 request_error(state
);
1730 winbindd_gettoken_async(state
->mem_ctx
, user_sid
, getusersids_recv
,
1734 static void getusersids_recv(void *private_data
, bool success
, DOM_SID
*sids
,
1737 struct winbindd_cli_state
*state
=
1738 (struct winbindd_cli_state
*)private_data
;
1740 unsigned ofs
, ret_size
= 0;
1744 request_error(state
);
1748 /* work out the response size */
1749 for (i
= 0; i
< num_sids
; i
++) {
1751 sid_to_fstring(s
, &sids
[i
]);
1752 ret_size
+= strlen(s
) + 1;
1755 /* build the reply */
1756 ret
= (char *)SMB_MALLOC(ret_size
);
1758 DEBUG(0, ("malloc failed\n"));
1759 request_error(state
);
1763 for (i
= 0; i
< num_sids
; i
++) {
1765 sid_to_fstring(s
, &sids
[i
]);
1766 safe_strcpy(ret
+ ofs
, s
, ret_size
- ofs
- 1);
1767 ofs
+= strlen(ret
+ofs
) + 1;
1770 /* Send data back to client */
1771 state
->response
.data
.num_entries
= num_sids
;
1772 state
->response
.extra_data
.data
= ret
;
1773 state
->response
.length
+= ret_size
;
1777 void winbindd_getuserdomgroups(struct winbindd_cli_state
*state
)
1780 struct winbindd_domain
*domain
;
1782 /* Ensure null termination */
1783 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1785 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1786 DEBUG(1, ("Could not get convert sid %s from string\n",
1787 state
->request
.data
.sid
));
1788 request_error(state
);
1792 /* Get info for the domain */
1793 if ((domain
= find_domain_from_sid_noinit(&user_sid
)) == NULL
) {
1794 DEBUG(0,("could not find domain entry for sid %s\n",
1795 sid_string_dbg(&user_sid
)));
1796 request_error(state
);
1800 sendto_domain(state
, domain
);
1803 enum winbindd_result
winbindd_dual_getuserdomgroups(struct winbindd_domain
*domain
,
1804 struct winbindd_cli_state
*state
)
1814 /* Ensure null termination */
1815 state
->request
.data
.sid
[sizeof(state
->request
.data
.sid
)-1]='\0';
1817 if (!string_to_sid(&user_sid
, state
->request
.data
.sid
)) {
1818 DEBUG(1, ("Could not get convert sid %s from string\n",
1819 state
->request
.data
.sid
));
1820 return WINBINDD_ERROR
;
1823 status
= domain
->methods
->lookup_usergroups(domain
, state
->mem_ctx
,
1824 &user_sid
, &num_groups
,
1826 if (!NT_STATUS_IS_OK(status
))
1827 return WINBINDD_ERROR
;
1829 if (num_groups
== 0) {
1830 state
->response
.data
.num_entries
= 0;
1831 state
->response
.extra_data
.data
= NULL
;
1835 if (!print_sidlist(state
->mem_ctx
,
1837 &sidstring
, &len
)) {
1838 DEBUG(0, ("talloc failed\n"));
1839 return WINBINDD_ERROR
;
1842 state
->response
.extra_data
.data
= SMB_STRDUP(sidstring
);
1843 if (!state
->response
.extra_data
.data
) {
1844 return WINBINDD_ERROR
;
1846 state
->response
.length
+= len
+1;
1847 state
->response
.data
.num_entries
= num_groups
;