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 DEBUG(10,("expand_groups:\n"));
465 for ( i=0; i<n_glist; i++ ) {
466 tmp_ctx = talloc_new( ctx );
468 /* Lookup the group membership */
470 status = d->methods->lookup_groupmem(d, tmp_ctx,
471 &glist[i], &num_names,
474 if (!NT_STATUS_IS_OK(status)) {
475 DEBUG(10,("expand_groups: lookup_groupmem for "
476 "sid %s failed with: %s\n",
477 sid_string_dbg(&glist[i]), nt_errstr(status)));
481 /* Separate users and groups into two lists */
483 for ( j=0; j<num_names; j++ ) {
486 if ( name_types[j] == SID_NAME_USER ||
487 name_types[j] == SID_NAME_COMPUTER )
489 status = add_names_to_list( ctx, members,
492 if ( !NT_STATUS_IS_OK(status) )
499 if ( name_types[j] == SID_NAME_DOM_GRP ||
500 name_types[j] == SID_NAME_ALIAS )
502 status = add_sid_to_array_unique(ctx,
506 if (!NT_STATUS_IS_OK(status)) {
514 TALLOC_FREE( tmp_ctx );
517 *new_glist = new_groups;
518 *n_new_glist = (uint32)new_groups_size;
521 TALLOC_FREE( tmp_ctx );
523 if (!NT_STATUS_IS_OK(status)) {
524 DEBUG(10,("expand_groups: returning with %s\n",
531 /***********************************************************************
532 Fill in the group membership field of a NT group given by group_sid
533 ***********************************************************************/
535 static bool fill_grent_mem(struct winbindd_domain *domain,
536 struct winbindd_cli_state *state,
538 enum lsa_SidType group_name_type,
539 size_t *num_gr_mem, char **gr_mem,
542 uint32 num_names = 0;
543 unsigned int buf_len = 0, buf_ndx = 0, i;
544 char **names = NULL, *buf = NULL;
548 DOM_SID *glist = NULL;
549 DOM_SID *new_glist = NULL;
550 uint32 n_glist, n_new_glist;
551 int max_depth = lp_winbind_expand_groups();
553 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
556 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
558 /* Initialize with no members */
562 /* HACK ALERT!! This whole routine does not cope with group members
563 * from more than one domain, ie aliases. Thus we have to work it out
564 * ourselves in a special routine. */
566 if (domain->internal) {
567 result = fill_passdb_alias_grmem(domain, group_sid,
573 /* Verify name type */
575 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
576 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
578 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
579 sid_string_dbg(group_sid),
580 domain->name, group_name_type));
584 /* OPTIMIZATION / HACK. See comment in
585 fill_grent_mem_domusers() */
587 sid_peek_rid( group_sid, &group_rid );
588 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
589 result = fill_grent_mem_domusers( mem_ctx, domain, state,
590 group_sid, group_name_type,
596 /* Real work goes here. Create a list of group names to
597 expand starting with the initial one. Pass that to
598 expand_groups() which returns a list of more group names
599 to expand. Do this up to the max search depth. */
601 if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
603 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
606 sid_copy( &glist[0], group_sid );
609 for ( i=0; i<max_depth && glist; i++ ) {
610 uint32 n_members = 0;
611 char **members = NULL;
615 nt_status = expand_groups( mem_ctx, domain,
617 &new_glist, &n_new_glist,
618 &members, &n_members);
619 if ( !NT_STATUS_IS_OK(nt_status) ) {
624 /* Add new group members to list. Pass through the
625 alias mapping function */
627 for (j=0; j<n_members; j++) {
628 fstring name_domain, name_acct;
629 fstring qualified_name;
630 char *mapped_name = NULL;
631 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
632 struct winbindd_domain *target_domain = NULL;
634 if (parse_domain_user(members[j], name_domain, name_acct)) {
635 target_domain = find_domain_from_name_noinit(name_domain);
638 if (!target_domain) {
639 target_domain = domain;
642 name_map_status = normalize_name_map(members, target_domain,
643 name_acct, &mapped_name);
645 /* Basic whitespace replacement */
646 if (NT_STATUS_IS_OK(name_map_status)) {
647 fill_domain_username(qualified_name, name_domain,
649 mapped_name = qualified_name;
651 /* no mapping at all */
652 else if (!NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
653 mapped_name = members[j];
656 nt_status = add_names_to_list( mem_ctx, &names,
659 if ( !NT_STATUS_IS_OK(nt_status) ) {
665 TALLOC_FREE( members );
667 /* If we have no more groups to expand, break out
670 if (new_glist == NULL)
676 n_glist = n_new_glist;
678 TALLOC_FREE( glist );
680 sort_unique_list(&names, &num_names);
682 DEBUG(10, ("looked up %d names\n", num_names));
685 /* Add members to list */
687 for (i = 0; i < num_names; i++) {
690 DEBUG(10, ("processing name %s\n", names[i]));
692 len = strlen(names[i]);
694 /* Add to list or calculate buffer length */
697 buf_len += len + 1; /* List is comma separated */
699 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
701 DEBUG(10, ("appending %s at ndx %d\n",
703 parse_add_domuser(&buf[buf_ndx], names[i], &len);
710 /* Allocate buffer */
712 if (!buf && buf_len != 0) {
713 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
714 DEBUG(1, ("out of memory\n"));
718 memset(buf, 0, buf_len);
724 if (buf && buf_ndx > 0) {
725 buf[buf_ndx - 1] = '\0';
729 *gr_mem_len = buf_len;
731 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n",
732 (unsigned int)*num_gr_mem,
733 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
738 talloc_destroy(mem_ctx);
740 DEBUG(10,("fill_grent_mem returning %s\n",
741 result == true ? "true" : "false"));
746 static void winbindd_getgrsid(struct winbindd_cli_state *state, DOM_SID group_sid);
748 static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
749 enum lsa_SidType type )
751 struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
754 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
755 request_error(state);
759 if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
760 DEBUG(5,("getgrnam_recv: not a group!\n"));
761 request_error(state);
765 winbindd_getgrsid( state, *sid );
769 /* Return a group structure from a group name */
771 void winbindd_getgrnam(struct winbindd_cli_state *state)
773 struct winbindd_domain *domain;
774 fstring name_domain, name_group;
776 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
778 /* Ensure null termination */
779 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
781 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
782 state->request.data.groupname));
784 nt_status = normalize_name_unmap(state->mem_ctx,
785 state->request.data.groupname,
787 /* If we didn't map anything in the above call, just reset the
788 tmp pointer to the original string */
789 if (!NT_STATUS_IS_OK(nt_status) &&
790 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
792 tmp = state->request.data.groupname;
795 /* Parse domain and groupname */
797 memset(name_group, 0, sizeof(name_group));
799 name_domain[0] = '\0';
800 name_group[0] = '\0';
802 parse_domain_user(tmp, name_domain, name_group);
804 /* if no domain or our local domain and no local tdb group, default to
805 * our local domain for aliases */
807 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
808 fstrcpy(name_domain, get_global_sam_name());
811 /* Get info for the domain */
813 if ((domain = find_domain_from_name_noinit(name_domain)) == NULL) {
814 DEBUG(3, ("could not get domain sid for domain %s\n",
816 request_error(state);
819 /* should we deal with users for our domain? */
821 if ( lp_winbind_trusted_domains_only() && domain->primary) {
822 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
823 "getgrnam() for %s\\%s.\n", name_domain, name_group));
824 request_error(state);
828 /* Get rid and name type from name */
830 fstrcpy( name_group, tmp );
832 winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
833 getgrnam_recv, WINBINDD_GETGRNAM, state );
836 struct getgrsid_state {
837 struct winbindd_cli_state *state;
838 struct winbindd_domain *domain;
840 enum lsa_SidType group_type;
845 static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
847 struct getgrsid_state *s =
848 (struct getgrsid_state *)private_data;
849 struct winbindd_domain *domain;
853 fstring dom_name, group_name;
856 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
857 request_error(s->state);
863 if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
864 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
865 request_error(s->state);
870 /* Fill in group structure */
872 if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
873 DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
874 request_error(s->state);
878 if (!fill_grent(s->state->mem_ctx, &s->state->response.data.gr,
879 dom_name, group_name, gid) ||
880 !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
881 &num_gr_mem, &gr_mem, &gr_mem_len))
883 request_error(s->state);
887 s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
889 /* Group membership lives at start of extra data */
891 s->state->response.data.gr.gr_mem_ofs = 0;
893 s->state->response.length += gr_mem_len;
894 s->state->response.extra_data.data = talloc_memdup(
895 s->state->mem_ctx, gr_mem, gr_mem_len);
896 if (s->state->response.extra_data.data == NULL) {
897 request_error(s->state);
901 request_ok(s->state);
904 static void getgrsid_lookupsid_recv( void *private_data, bool success,
905 const char *dom_name, const char *name,
906 enum lsa_SidType name_type )
908 struct getgrsid_state *s = (struct getgrsid_state *)private_data;
909 char *mapped_name = NULL;
911 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
914 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
915 request_error(s->state);
919 /* either it's a domain group, a domain local group, or a
920 local group in an internal domain */
922 if ( !( (name_type==SID_NAME_DOM_GRP) ||
923 ((name_type==SID_NAME_ALIAS) &&
924 (s->domain->primary || s->domain->internal)) ) )
926 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
927 dom_name, name, name_type));
928 request_error(s->state);
932 /* normalize the name and ensure that we have the DOM\name
933 coming out of here */
935 fstrcpy(raw_name, name);
937 nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name,
940 /* basic whitespace reversal */
941 if (NT_STATUS_IS_OK(nt_status)) {
942 s->group_name = talloc_asprintf(s->state->mem_ctx,
945 *lp_winbind_separator(),
948 /* mapped from alias */
949 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
950 s->group_name = mapped_name;
952 /* no mapping at all. use original string */
954 s->group_name = talloc_asprintf(s->state->mem_ctx,
957 *lp_winbind_separator(),
961 if (s->group_name == NULL) {
962 DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
963 request_error(s->state);
967 s->group_type = name_type;
969 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
970 getgrsid_sid2gid_recv, s);
973 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
975 struct getgrsid_state *s;
977 if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
978 DEBUG(0, ("talloc failed\n"));
979 request_error(state);
985 if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
986 DEBUG(3, ("Could not find domain for sid %s\n",
987 sid_string_dbg(&group_sid)));
988 request_error(state);
992 sid_copy(&s->group_sid, &group_sid);
994 winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
995 getgrsid_lookupsid_recv, s );
999 static void getgrgid_recv(void *private_data, bool success, const char *sid)
1001 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
1002 enum lsa_SidType name_type;
1006 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
1007 (unsigned long)(state->request.data.gid), sid));
1009 if (!string_to_sid(&group_sid, sid)) {
1010 DEBUG(1,("getgrgid_recv: Could not convert sid %s "
1011 "from string\n", sid));
1012 request_error(state);
1016 winbindd_getgrsid(state, group_sid);
1020 /* Ok, this might be "ours", i.e. an alias */
1021 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
1022 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
1023 (name_type == SID_NAME_ALIAS)) {
1024 /* Hey, got an alias */
1025 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
1026 (unsigned long)(state->request.data.gid), sid));
1027 winbindd_getgrsid(state, group_sid);
1031 DEBUG(1, ("could not convert gid %lu to sid\n",
1032 (unsigned long)state->request.data.gid));
1033 request_error(state);
1036 /* Return a group structure from a gid number */
1037 void winbindd_getgrgid(struct winbindd_cli_state *state)
1039 gid_t gid = state->request.data.gid;
1041 DEBUG(3, ("[%5lu]: getgrgid %lu\n",
1042 (unsigned long)state->pid,
1043 (unsigned long)gid));
1045 /* always use the async interface */
1046 winbindd_gid2sid_async(state->mem_ctx, gid, getgrgid_recv, state);
1050 * set/get/endgrent functions
1053 /* "Rewind" file pointer for group database enumeration */
1055 static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
1057 struct winbindd_domain *domain;
1059 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
1061 /* Check user has enabled this */
1063 if (!lp_winbind_enum_groups()) {
1067 /* Free old static data if it exists */
1069 if (state->getgrent_state != NULL) {
1070 free_getent_state(state->getgrent_state);
1071 state->getgrent_state = NULL;
1074 /* Create sam pipes for each domain we know about */
1076 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1077 struct getent_state *domain_state;
1079 /* Create a state record for this domain */
1081 /* don't add our domaina if we are a PDC or if we
1082 are a member of a Samba domain */
1084 if ( lp_winbind_trusted_domains_only() && domain->primary )
1089 domain_state = SMB_MALLOC_P(struct getent_state);
1090 if (!domain_state) {
1091 DEBUG(1, ("winbindd_setgrent: "
1092 "malloc failed for domain_state!\n"));
1096 ZERO_STRUCTP(domain_state);
1098 fstrcpy(domain_state->domain_name, domain->name);
1100 /* Add to list of open domains */
1102 DLIST_ADD(state->getgrent_state, domain_state);
1105 state->getgrent_initialized = True;
1109 void winbindd_setgrent(struct winbindd_cli_state *state)
1111 if (winbindd_setgrent_internal(state)) {
1114 request_error(state);
1118 /* Close file pointer to ntdom group database */
1120 void winbindd_endgrent(struct winbindd_cli_state *state)
1122 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
1124 free_getent_state(state->getgrent_state);
1125 state->getgrent_initialized = False;
1126 state->getgrent_state = NULL;
1130 /* Get the list of domain groups and domain aliases for a domain. We fill in
1131 the sam_entries and num_sam_entries fields with domain group information.
1132 Return True if some groups were returned, False otherwise. */
1134 bool get_sam_group_entries(struct getent_state *ent)
1138 struct acct_info *name_list = NULL;
1139 TALLOC_CTX *mem_ctx;
1140 bool result = False;
1141 struct acct_info *sam_grp_entries = NULL;
1142 struct winbindd_domain *domain;
1144 if (ent->got_sam_entries)
1147 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
1148 ent->domain_name))) {
1149 DEBUG(1, ("get_sam_group_entries: "
1150 "could not create talloc context!\n"));
1154 /* Free any existing group info */
1156 SAFE_FREE(ent->sam_entries);
1157 ent->num_sam_entries = 0;
1158 ent->got_sam_entries = True;
1160 /* Enumerate domain groups */
1164 if (!(domain = find_domain_from_name(ent->domain_name))) {
1165 DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
1170 /* always get the domain global groups */
1172 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries,
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DEBUG(3, ("get_sam_group_entries: "
1177 "could not enumerate domain groups! Error: %s\n",
1178 nt_errstr(status)));
1183 /* Copy entries into return buffer */
1186 name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries);
1188 DEBUG(0,("get_sam_group_entries: Failed to malloc "
1189 "memory for %d domain groups!\n",
1194 memcpy(name_list, sam_grp_entries,
1195 num_entries * sizeof(struct acct_info));
1198 ent->num_sam_entries = num_entries;
1200 /* get the domain local groups if we are a member of a native win2k
1201 * domain and are not using LDAP to get the groups */
1203 if ( ( lp_security() != SEC_ADS && domain->native_mode
1204 && domain->primary) || domain->internal )
1206 DEBUG(4,("get_sam_group_entries: %s domain; "
1207 "enumerating local groups as well\n",
1208 domain->native_mode ? "Native Mode 2k":
1209 "BUILTIN or local"));
1211 status = domain->methods->enum_local_groups(domain, mem_ctx,
1215 if ( !NT_STATUS_IS_OK(status) ) {
1216 DEBUG(3,("get_sam_group_entries: "
1217 "Failed to enumerate "
1218 "domain local groups with error %s!\n",
1219 nt_errstr(status)));
1223 DEBUG(4,("get_sam_group_entries: "
1224 "Returned %d local groups\n",
1227 /* Copy entries into return buffer */
1229 if ( num_entries ) {
1230 name_list = SMB_REALLOC_ARRAY(name_list,
1232 ent->num_sam_entries+
1235 DEBUG(0,("get_sam_group_entries: "
1236 "Failed to realloc more memory "
1237 "for %d local groups!\n",
1243 memcpy(&name_list[ent->num_sam_entries],
1245 num_entries * sizeof(struct acct_info));
1248 ent->num_sam_entries += num_entries;
1252 /* Fill in remaining fields */
1254 ent->sam_entries = name_list;
1255 ent->sam_entry_index = 0;
1257 result = (ent->num_sam_entries > 0);
1260 talloc_destroy(mem_ctx);
1265 /* Fetch next group entry from ntdom database */
1267 #define MAX_GETGRENT_GROUPS 500
1269 void winbindd_getgrent(struct winbindd_cli_state *state)
1271 struct getent_state *ent;
1272 struct winbindd_gr *group_list = NULL;
1273 int num_groups, group_list_ndx, gr_mem_list_len = 0;
1274 char *gr_mem_list = NULL;
1276 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1278 /* Check user has enabled this */
1280 if (!lp_winbind_enum_groups()) {
1281 request_error(state);
1285 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
1287 if (num_groups == 0) {
1288 request_error(state);
1292 group_list = talloc_zero_array(state->mem_ctx, struct winbindd_gr,
1295 request_error(state);
1298 state->response.extra_data.data = group_list;
1300 state->response.data.num_entries = 0;
1302 if (!state->getgrent_initialized)
1303 winbindd_setgrent_internal(state);
1305 if (!(ent = state->getgrent_state)) {
1306 request_error(state);
1310 /* Start sending back groups */
1312 for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
1313 struct acct_info *name_list = NULL;
1314 fstring domain_group_name;
1320 struct winbindd_domain *domain;
1322 /* Do we need to fetch another chunk of groups? */
1326 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1327 ent->sam_entry_index, ent->num_sam_entries));
1329 if (ent->num_sam_entries == ent->sam_entry_index) {
1331 while(ent && !get_sam_group_entries(ent)) {
1332 struct getent_state *next_ent;
1334 DEBUG(10, ("freeing state info for domain %s\n",
1337 /* Free state information for this domain */
1339 SAFE_FREE(ent->sam_entries);
1341 next_ent = ent->next;
1342 DLIST_REMOVE(state->getgrent_state, ent);
1348 /* No more domains */
1354 name_list = (struct acct_info *)ent->sam_entries;
1356 if (!(domain = find_domain_from_name(ent->domain_name))) {
1357 DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
1363 /* Lookup group info */
1365 sid_copy(&group_sid, &domain->sid);
1366 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1368 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->have_idmap_config
1369 ? domain->name : "",
1370 &group_sid, &group_gid)))
1373 enum lsa_SidType type;
1375 DEBUG(10, ("SID %s not in idmap\n",
1376 sid_string_dbg(&group_sid)));
1378 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1379 DEBUG(1,("could not look up gid for group %s\n",
1380 name_list[ent->sam_entry_index].acct_name));
1381 ent->sam_entry_index++;
1385 if ((type != SID_NAME_DOM_GRP) &&
1386 (type != SID_NAME_ALIAS) &&
1387 (type != SID_NAME_WKN_GRP)) {
1388 DEBUG(1, ("Group %s is a %s, not a group\n",
1389 sid_type_lookup(type),
1390 name_list[ent->sam_entry_index].acct_name));
1391 ent->sam_entry_index++;
1397 DEBUG(10, ("got gid %lu for group %lu\n",
1398 (unsigned long)group_gid,
1399 (unsigned long)name_list[ent->sam_entry_index].rid));
1401 /* Fill in group entry */
1403 fill_domain_username(domain_group_name, ent->domain_name,
1404 name_list[ent->sam_entry_index].acct_name, True);
1406 result = fill_grent(state->mem_ctx, &group_list[group_list_ndx],
1408 name_list[ent->sam_entry_index].acct_name,
1411 /* Fill in group membership entry */
1414 size_t num_gr_mem = 0;
1416 group_list[group_list_ndx].num_gr_mem = 0;
1420 /* Get group membership */
1421 if (state->request.cmd == WINBINDD_GETGRLST) {
1424 sid_copy(&member_sid, &domain->sid);
1425 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1426 result = fill_grent_mem(
1432 &gr_mem, &gr_mem_len);
1434 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1439 /* Append to group membership list */
1440 gr_mem_list = (char *)SMB_REALLOC(
1441 gr_mem_list, gr_mem_list_len + gr_mem_len);
1444 (group_list[group_list_ndx].num_gr_mem != 0)) {
1445 DEBUG(0, ("out of memory\n"));
1446 gr_mem_list_len = 0;
1450 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1451 gr_mem_list_len, (unsigned int)gr_mem_len));
1453 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1458 group_list[group_list_ndx].gr_mem_ofs =
1461 gr_mem_list_len += gr_mem_len;
1464 ent->sam_entry_index++;
1466 /* Add group to return list */
1470 DEBUG(10, ("adding group num_entries = %d\n",
1471 state->response.data.num_entries));
1474 state->response.data.num_entries++;
1476 state->response.length +=
1477 sizeof(struct winbindd_gr);
1480 DEBUG(0, ("could not lookup domain group %s\n",
1481 domain_group_name));
1485 /* Copy the list of group memberships to the end of the extra data */
1487 if (group_list_ndx == 0)
1490 state->response.extra_data.data = talloc_realloc_size(
1491 state->mem_ctx, state->response.extra_data.data,
1492 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1494 if (!state->response.extra_data.data) {
1495 DEBUG(0, ("out of memory\n"));
1497 SAFE_FREE(gr_mem_list);
1498 request_error(state);
1502 memcpy(&((char *)state->response.extra_data.data)
1503 [group_list_ndx * sizeof(struct winbindd_gr)],
1504 gr_mem_list, gr_mem_list_len);
1506 state->response.length += gr_mem_list_len;
1508 DEBUG(10, ("returning %d groups, length = %d\n",
1509 group_list_ndx, gr_mem_list_len));
1511 /* Out of domains */
1515 SAFE_FREE(gr_mem_list);
1517 if (group_list_ndx > 0)
1520 request_error(state);
1523 /* List domain groups without mapping to unix ids */
1524 void winbindd_list_groups(struct winbindd_cli_state *state)
1526 winbindd_list_ent(state, LIST_GROUPS);
1529 /* Get user supplementary groups. This is much quicker than trying to
1530 invert the groups database. We merge the groups from the gids and
1531 other_sids info3 fields as trusted domain, universal group
1532 memberships, and nested groups (win2k native mode only) are not
1533 returned by the getgroups RPC call but are present in the info3. */
1535 struct getgroups_state {
1536 struct winbindd_cli_state *state;
1537 struct winbindd_domain *domain;
1542 const DOM_SID *token_sids;
1543 size_t i, num_token_sids;
1546 size_t num_token_gids;
1549 static void getgroups_usersid_recv(void *private_data, bool success,
1550 const DOM_SID *sid, enum lsa_SidType type);
1551 static void getgroups_tokensids_recv(void *private_data, bool success,
1552 DOM_SID *token_sids, size_t num_token_sids);
1553 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1555 void winbindd_getgroups(struct winbindd_cli_state *state)
1557 struct getgroups_state *s;
1558 char *real_name = NULL;
1559 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1561 /* Ensure null termination */
1562 state->request.data.username
1563 [sizeof(state->request.data.username)-1]='\0';
1565 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1566 state->request.data.username));
1568 /* Parse domain and username */
1570 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1572 DEBUG(0, ("talloc failed\n"));
1573 request_error(state);
1579 nt_status = normalize_name_unmap(state->mem_ctx,
1580 state->request.data.username,
1583 /* Reset the real_name pointer if we didn't do anything
1584 productive in the above call */
1585 if (!NT_STATUS_IS_OK(nt_status) &&
1586 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
1588 real_name = state->request.data.username;
1591 if (!parse_domain_user_talloc(state->mem_ctx, real_name,
1592 &s->domname, &s->username)) {
1593 DEBUG(5, ("Could not parse domain user: %s\n",
1596 /* error out if we do not have nested group support */
1598 if ( !lp_winbind_nested_groups() ) {
1599 request_error(state);
1603 s->domname = talloc_strdup(state->mem_ctx,
1604 get_global_sam_name());
1605 s->username = talloc_strdup(state->mem_ctx,
1606 state->request.data.username);
1609 /* Get info for the domain (either by short domain name or
1610 DNS name in the case of a UPN) */
1612 s->domain = find_domain_from_name_noinit(s->domname);
1614 char *p = strchr(s->username, '@');
1617 s->domain = find_domain_from_name_noinit(p+1);
1622 if (s->domain == NULL) {
1623 DEBUG(7, ("could not find domain entry for domain %s\n",
1625 request_error(state);
1629 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1630 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1631 "getgroups() for %s\\%s.\n", s->domname,
1633 request_error(state);
1637 /* Get rid and name type from name. The following costs 1 packet */
1639 winbindd_lookupname_async(state->mem_ctx,
1640 s->domname, s->username,
1641 getgroups_usersid_recv,
1642 WINBINDD_GETGROUPS, s);
1645 static void getgroups_usersid_recv(void *private_data, bool success,
1646 const DOM_SID *sid, enum lsa_SidType type)
1648 struct getgroups_state *s =
1649 (struct getgroups_state *)private_data;
1652 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1653 request_error(s->state);
1657 sid_copy(&s->user_sid, sid);
1659 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1660 getgroups_tokensids_recv, s);
1663 static void getgroups_tokensids_recv(void *private_data, bool success,
1664 DOM_SID *token_sids, size_t num_token_sids)
1666 struct getgroups_state *s =
1667 (struct getgroups_state *)private_data;
1669 /* We need at least the user sid and the primary group in the token,
1670 * otherwise it's an error */
1672 if ((!success) || (num_token_sids < 2)) {
1673 request_error(s->state);
1677 s->token_sids = token_sids;
1678 s->num_token_sids = num_token_sids;
1681 s->token_gids = NULL;
1682 s->num_token_gids = 0;
1684 getgroups_sid2gid_recv(s, False, 0);
1687 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
1689 struct getgroups_state *s =
1690 (struct getgroups_state *)private_data;
1693 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1695 &s->num_token_gids)) {
1700 if (s->i < s->num_token_sids) {
1701 const DOM_SID *sid = &s->token_sids[s->i];
1704 if (sid_equal(sid, &s->user_sid)) {
1705 getgroups_sid2gid_recv(s, False, 0);
1709 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1710 getgroups_sid2gid_recv, s);
1714 s->state->response.data.num_entries = s->num_token_gids;
1715 if (s->num_token_gids) {
1716 s->state->response.extra_data.data = s->token_gids;
1717 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1719 request_ok(s->state);
1722 /* Get user supplementary sids. This is equivalent to the
1723 winbindd_getgroups() function but it involves a SID->SIDs mapping
1724 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1725 idmap. This call is designed to be used with applications that need
1726 to do ACL evaluation themselves. Note that the cached info3 data is
1729 this function assumes that the SID that comes in is a user SID. If
1730 you pass in another type of SID then you may get unpredictable
1734 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1737 void winbindd_getusersids(struct winbindd_cli_state *state)
1741 /* Ensure null termination */
1742 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1744 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1745 if (user_sid == NULL) {
1746 DEBUG(1, ("talloc failed\n"));
1747 request_error(state);
1751 if (!string_to_sid(user_sid, state->request.data.sid)) {
1752 DEBUG(1, ("Could not get convert sid %s from string\n",
1753 state->request.data.sid));
1754 request_error(state);
1758 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1762 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1765 struct winbindd_cli_state *state =
1766 (struct winbindd_cli_state *)private_data;
1768 unsigned ofs, ret_size = 0;
1772 request_error(state);
1776 /* work out the response size */
1777 for (i = 0; i < num_sids; i++) {
1779 sid_to_fstring(s, &sids[i]);
1780 ret_size += strlen(s) + 1;
1783 /* build the reply */
1784 ret = talloc_array(state->mem_ctx, char, ret_size);
1786 DEBUG(0, ("malloc failed\n"));
1787 request_error(state);
1791 for (i = 0; i < num_sids; i++) {
1793 sid_to_fstring(s, &sids[i]);
1794 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1795 ofs += strlen(ret+ofs) + 1;
1798 /* Send data back to client */
1799 state->response.data.num_entries = num_sids;
1800 state->response.extra_data.data = ret;
1801 state->response.length += ret_size;
1805 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1808 struct winbindd_domain *domain;
1810 /* Ensure null termination */
1811 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1813 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1814 DEBUG(1, ("Could not get convert sid %s from string\n",
1815 state->request.data.sid));
1816 request_error(state);
1820 /* Get info for the domain */
1821 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1822 DEBUG(0,("could not find domain entry for sid %s\n",
1823 sid_string_dbg(&user_sid)));
1824 request_error(state);
1828 sendto_domain(state, domain);
1831 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1832 struct winbindd_cli_state *state)
1842 /* Ensure null termination */
1843 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1845 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1846 DEBUG(1, ("Could not get convert sid %s from string\n",
1847 state->request.data.sid));
1848 return WINBINDD_ERROR;
1851 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1852 &user_sid, &num_groups,
1854 if (!NT_STATUS_IS_OK(status))
1855 return WINBINDD_ERROR;
1857 if (num_groups == 0) {
1858 state->response.data.num_entries = 0;
1859 state->response.extra_data.data = NULL;
1863 if (!print_sidlist(state->mem_ctx,
1865 &sidstring, &len)) {
1866 DEBUG(0, ("talloc failed\n"));
1867 return WINBINDD_ERROR;
1870 state->response.extra_data.data = sidstring;
1871 state->response.length += len+1;
1872 state->response.data.num_entries = num_groups;
1877 void winbindd_getsidaliases(struct winbindd_cli_state *state)
1880 struct winbindd_domain *domain;
1882 /* Ensure null termination */
1883 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1885 if (!string_to_sid(&domain_sid, state->request.data.sid)) {
1886 DEBUG(1, ("Could not get convert sid %s from string\n",
1887 state->request.data.sid));
1888 request_error(state);
1892 /* Get info for the domain */
1893 if ((domain = find_domain_from_sid_noinit(&domain_sid)) == NULL) {
1894 DEBUG(0,("could not find domain entry for sid %s\n",
1895 sid_string_dbg(&domain_sid)));
1896 request_error(state);
1900 sendto_domain(state, domain);
1903 enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
1904 struct winbindd_cli_state *state)
1906 DOM_SID *sids = NULL;
1907 size_t num_sids = 0;
1908 char *sidstr = NULL;
1915 DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
1917 sidstr = state->request.extra_data.data;
1918 if (sidstr == NULL) {
1919 sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
1921 DEBUG(0, ("Out of memory\n"));
1922 return WINBINDD_ERROR;
1926 DEBUG(10, ("Sidlist: %s\n", sidstr));
1928 if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
1929 DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
1930 return WINBINDD_ERROR;
1936 result = domain->methods->lookup_useraliases(domain,
1942 if (!NT_STATUS_IS_OK(result)) {
1943 DEBUG(3, ("Could not lookup_useraliases: %s\n",
1944 nt_errstr(result)));
1945 return WINBINDD_ERROR;
1952 DEBUG(10, ("Got %d aliases\n", num_aliases));
1954 for (i=0; i<num_aliases; i++) {
1956 DEBUGADD(10, (" rid %d\n", alias_rids[i]));
1957 sid_copy(&sid, &domain->sid);
1958 sid_append_rid(&sid, alias_rids[i]);
1959 result = add_sid_to_array(state->mem_ctx, &sid, &sids,
1961 if (!NT_STATUS_IS_OK(result)) {
1962 return WINBINDD_ERROR;
1967 if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
1968 DEBUG(0, ("Could not print_sidlist\n"));
1969 state->response.extra_data.data = NULL;
1970 return WINBINDD_ERROR;
1973 state->response.extra_data.data = NULL;
1976 state->response.extra_data.data = sidstr;
1977 DEBUG(10, ("aliases_list: %s\n",
1978 (char *)state->response.extra_data.data));
1979 state->response.length += len+1;
1980 state->response.data.num_entries = num_sids;