Fix bug 5681: Do not limit the number of network interfaces
[Samba.git] / source3 / winbindd / winbindd_group.c
blob3273a288e253af0923f00044f3f53578c4e743f9
1 /*
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/>.
25 #include "includes.h"
26 #include "winbindd.h"
28 #undef DBGC_CLASS
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)
34 fstring name;
36 if (domain != NULL) {
37 fill_domain_username(name, domain, user, True);
38 } else {
39 fstrcpy(name, user);
41 safe_strcat(name, ",", sizeof(name)-1);
42 string_append(pp_members, name);
43 *p_num_members += 1;
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,
51 char **pp_members,
52 size_t *p_num_members)
54 DOM_SID dom_sid;
55 uint32 rid;
56 struct winbindd_domain *domain;
57 size_t i;
59 char *domain_name = NULL;
60 char *name = NULL;
61 enum lsa_SidType type;
63 uint32 num_names;
64 DOM_SID *sid_mem;
65 char **names;
66 uint32 *types;
68 NTSTATUS result;
70 TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
72 if (mem_ctx == NULL) {
73 DEBUG(1, ("talloc_init failed\n"));
74 return;
77 sid_copy(&dom_sid, sid);
78 sid_split_rid(&dom_sid, &rid);
80 domain = find_lookup_domain_from_sid(sid);
82 if (domain == NULL) {
83 DEBUG(3, ("Could not find domain for sid %s\n",
84 sid_string_dbg(sid)));
85 goto done;
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)));
94 goto done;
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);
101 goto done;
104 if (type != SID_NAME_DOM_GRP) {
105 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
106 name));
107 goto done;
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)));
117 goto done;
120 result = domain->methods->lookup_groupmem(domain, mem_ctx,
121 sid, &num_names,
122 &sid_mem, &names,
123 &types);
125 if (!NT_STATUS_IS_OK(result)) {
126 DEBUG(10, ("Could not lookup group members for %s: %s\n",
127 name, nt_errstr(result)));
128 goto done;
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));
138 continue;
141 add_member(NULL, names[i], pp_members, p_num_members);
144 done:
145 talloc_destroy(mem_ctx);
146 return;
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)
153 DOM_SID *members;
154 size_t i, num_members;
156 *num_gr_mem = 0;
157 *gr_mem = NULL;
158 *gr_mem_len = 0;
160 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
161 &num_members)))
162 return True;
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) {
171 size_t len;
173 /* We have at least one member, strip off the last "," */
174 len = strlen(*gr_mem);
175 (*gr_mem)[len-1] = '\0';
176 *gr_mem_len = len;
179 return True;
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,
194 &mapped_name);
196 /* Basic whitespace replacement */
197 if (NT_STATUS_IS_OK(nt_status)) {
198 fill_domain_username(full_group_name, dom_name,
199 mapped_name, true);
201 /* Mapped to an aliase */
202 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
203 fstrcpy(full_group_name, mapped_name);
205 /* no change */
206 else {
207 fill_domain_username( full_group_name, dom_name,
208 gr_name, True );
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);
218 return True;
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,
233 DOM_SID *group_sid,
234 enum lsa_SidType group_name_type,
235 size_t *num_gr_mem, char **gr_mem,
236 size_t *gr_mem_len)
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;
243 NTSTATUS status;
244 int i;
245 unsigned int buf_len = 0;
246 char *buf = NULL;
248 DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
249 domain->name ));
251 if (state) {
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,
276 mem_ctx,
277 pquerying_user_sid,
278 &num_groups,
279 &user_sids);
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),
285 domain->name,
286 nt_errstr(status)));
287 return False;
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. */
294 u_in_group = True;
295 break;
300 if (u_in_group) {
301 size_t len = 0;
302 char *domainname = NULL;
303 char *username = NULL;
304 fstring name;
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),
313 domain->name ));
315 status = domain->methods->sid_to_name(domain, mem_ctx,
316 pquerying_user_sid,
317 &domainname,
318 &username,
319 &type);
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),
324 domain->name,
325 nt_errstr(status)));
326 return False;
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 */
342 else {
343 fill_domain_username(name, domainname, username, true);
346 len = strlen(name);
347 buf_len = len + 1;
348 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
349 DEBUG(1, ("out of memory\n"));
350 return False;
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 */
359 *num_gr_mem = 1;
362 *gr_mem = buf;
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"));
370 return True;
373 /***********************************************************************
374 Add names to a list. Assumes a canonical version of the string
375 in DOMAIN\user
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)
385 uint32_t i;
387 /* search for duplicates for sorting and looking for matching
388 neighbors */
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));
396 (*n_list)--;
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;
407 int i, j;
409 if ( !names || (n_names == 0) )
410 return NT_STATUS_OK;
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;
419 } else {
420 new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
421 (*n_list) + n_names );
422 if ( !new_list )
423 return NT_STATUS_NO_MEMORY;
424 n_new_list = (*n_list) + n_names;
427 /* Add all names */
429 for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
430 new_list[i] = talloc_strdup( new_list, names[j] );
433 *list = new_list;
434 *n_list = n_new_list;
436 return NT_STATUS_OK;
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 )
448 int i, j;
449 NTSTATUS status = NT_STATUS_OK;
450 uint32 num_names = 0;
451 uint32 *name_types = NULL;
452 char **names = 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;
458 *members = NULL;
459 *n_members = 0;
460 *new_glist = NULL;
461 *n_new_glist = 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,
470 &sid_mem, &names,
471 &name_types);
472 if ( !NT_STATUS_IS_OK(status) )
473 goto out;
475 /* Separate users and groups into two lists */
477 for ( j=0; j<num_names; j++ ) {
479 /* Users */
480 if ( name_types[j] == SID_NAME_USER ||
481 name_types[j] == SID_NAME_COMPUTER )
483 status = add_names_to_list( ctx, members,
484 n_members,
485 names+j, 1 );
486 if ( !NT_STATUS_IS_OK(status) )
487 goto out;
489 continue;
492 /* Groups */
493 if ( name_types[j] == SID_NAME_DOM_GRP ||
494 name_types[j] == SID_NAME_ALIAS )
496 status = add_sid_to_array_unique(ctx,
497 &sid_mem[j],
498 &new_groups,
499 &new_groups_size);
500 if (!NT_STATUS_IS_OK(status)) {
501 goto out;
504 continue;
508 TALLOC_FREE( tmp_ctx );
511 *new_glist = new_groups;
512 *n_new_glist = (uint32)new_groups_size;
514 out:
515 TALLOC_FREE( tmp_ctx );
517 return status;
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,
526 DOM_SID *group_sid,
527 enum lsa_SidType group_name_type,
528 size_t *num_gr_mem, char **gr_mem,
529 size_t *gr_mem_len)
531 uint32 num_names = 0;
532 unsigned int buf_len = 0, buf_ndx = 0, i;
533 char **names = NULL, *buf = NULL;
534 bool result = False;
535 TALLOC_CTX *mem_ctx;
536 uint32 group_rid;
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)))
543 return False;
545 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
547 /* Initialize with no members */
549 *num_gr_mem = 0;
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,
557 num_gr_mem,
558 gr_mem, gr_mem_len);
559 goto done;
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));
570 goto done;
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,
580 num_gr_mem, gr_mem,
581 gr_mem_len );
582 goto done;
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 ) {
591 result = False;
592 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
593 goto done;
595 sid_copy( &glist[0], group_sid );
596 n_glist = 1;
598 for ( i=0; i<max_depth && glist; i++ ) {
599 uint32 n_members = 0;
600 char **members = NULL;
601 NTSTATUS nt_status;
602 int j;
604 nt_status = expand_groups( mem_ctx, domain,
605 glist, n_glist,
606 &new_glist, &n_new_glist,
607 &members, &n_members);
608 if ( !NT_STATUS_IS_OK(nt_status) ) {
609 result = False;
610 goto done;
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);
625 /* NOW WHAT ? */
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,
637 mapped_name, true);
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,
646 &num_names,
647 &mapped_name, 1);
648 if ( !NT_STATUS_IS_OK(nt_status) ) {
649 result = False;
650 goto done;
654 TALLOC_FREE( members );
656 /* If we have no more groups to expand, break out
657 early */
659 if (new_glist == NULL)
660 break;
662 /* One more round */
663 TALLOC_FREE(glist);
664 glist = new_glist;
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));
673 again:
674 /* Add members to list */
676 for (i = 0; i < num_names; i++) {
677 int len;
679 DEBUG(10, ("processing name %s\n", names[i]));
681 len = strlen(names[i]);
683 /* Add to list or calculate buffer length */
685 if (!buf) {
686 buf_len += len + 1; /* List is comma separated */
687 (*num_gr_mem)++;
688 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
689 } else {
690 DEBUG(10, ("appending %s at ndx %d\n",
691 names[i], buf_ndx));
692 parse_add_domuser(&buf[buf_ndx], names[i], &len);
693 buf_ndx += len;
694 buf[buf_ndx] = ',';
695 buf_ndx++;
699 /* Allocate buffer */
701 if (!buf && buf_len != 0) {
702 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
703 DEBUG(1, ("out of memory\n"));
704 result = False;
705 goto done;
707 memset(buf, 0, buf_len);
708 goto again;
711 /* Now we're done */
713 if (buf && buf_ndx > 0) {
714 buf[buf_ndx - 1] = '\0';
717 *gr_mem = buf;
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"));
723 result = True;
725 done:
727 talloc_destroy(mem_ctx);
729 DEBUG(10, ("fill_grent_mem returning %d\n", result));
731 return 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;
741 if (!success) {
742 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
743 request_error(state);
744 return;
747 if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
748 DEBUG(5,("getgrnam_recv: not a group!\n"));
749 request_error(state);
750 return;
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;
763 char *tmp;
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,
774 &tmp);
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",
803 name_domain));
804 request_error(state);
805 return;
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);
813 return;
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;
827 char *group_name;
828 enum lsa_SidType group_type;
829 uid_t gid;
830 DOM_SID group_sid;
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;
838 size_t gr_mem_len;
839 size_t num_gr_mem;
840 char *gr_mem;
841 fstring dom_name, group_name;
843 if (!success) {
844 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
845 request_error(s->state);
846 return;
849 s->gid = gid;
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);
854 return;
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);
863 return;
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);
872 return;
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 = talloc_memdup(
883 s->state->mem_ctx, gr_mem, gr_mem_len);
884 if (s->state->response.extra_data.data == NULL) {
885 request_error(s->state);
886 return;
889 request_ok(s->state);
892 static void getgrsid_lookupsid_recv( void *private_data, bool success,
893 const char *dom_name, const char *name,
894 enum lsa_SidType name_type )
896 struct getgrsid_state *s = (struct getgrsid_state *)private_data;
897 char *mapped_name = NULL;
898 fstring raw_name;
899 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
901 if (!success) {
902 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
903 request_error(s->state);
904 return;
907 /* either it's a domain group, a domain local group, or a
908 local group in an internal domain */
910 if ( !( (name_type==SID_NAME_DOM_GRP) ||
911 ((name_type==SID_NAME_ALIAS) &&
912 (s->domain->primary || s->domain->internal)) ) )
914 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
915 dom_name, name, name_type));
916 request_error(s->state);
917 return;
920 /* normalize the name and ensure that we have the DOM\name
921 coming out of here */
923 fstrcpy(raw_name, name);
925 nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name,
926 &mapped_name);
928 /* basic whitespace reversal */
929 if (NT_STATUS_IS_OK(nt_status)) {
930 s->group_name = talloc_asprintf(s->state->mem_ctx,
931 "%s%c%s",
932 dom_name,
933 *lp_winbind_separator(),
934 mapped_name);
936 /* mapped from alias */
937 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
938 s->group_name = mapped_name;
940 /* no mapping at all. use original string */
941 else {
942 s->group_name = talloc_asprintf(s->state->mem_ctx,
943 "%s%c%s",
944 dom_name,
945 *lp_winbind_separator(),
946 raw_name);
949 if (s->group_name == NULL) {
950 DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
951 request_error(s->state);
952 return;
955 s->group_type = name_type;
957 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
958 getgrsid_sid2gid_recv, s);
961 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
963 struct getgrsid_state *s;
965 if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
966 DEBUG(0, ("talloc failed\n"));
967 request_error(state);
968 return;
971 s->state = state;
973 if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
974 DEBUG(3, ("Could not find domain for sid %s\n",
975 sid_string_dbg(&group_sid)));
976 request_error(state);
977 return;
980 sid_copy(&s->group_sid, &group_sid);
982 winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
983 getgrsid_lookupsid_recv, s );
987 static void getgrgid_recv(void *private_data, bool success, const char *sid)
989 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
990 enum lsa_SidType name_type;
991 DOM_SID group_sid;
993 if (success) {
994 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
995 (unsigned long)(state->request.data.gid), sid));
997 if (!string_to_sid(&group_sid, sid)) {
998 DEBUG(1,("getgrgid_recv: Could not convert sid %s "
999 "from string\n", sid));
1000 request_error(state);
1001 return;
1004 winbindd_getgrsid(state, group_sid);
1005 return;
1008 /* Ok, this might be "ours", i.e. an alias */
1009 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
1010 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
1011 (name_type == SID_NAME_ALIAS)) {
1012 /* Hey, got an alias */
1013 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
1014 (unsigned long)(state->request.data.gid), sid));
1015 winbindd_getgrsid(state, group_sid);
1016 return;
1019 DEBUG(1, ("could not convert gid %lu to sid\n",
1020 (unsigned long)state->request.data.gid));
1021 request_error(state);
1024 /* Return a group structure from a gid number */
1025 void winbindd_getgrgid(struct winbindd_cli_state *state)
1027 gid_t gid = state->request.data.gid;
1029 DEBUG(3, ("[%5lu]: getgrgid %lu\n",
1030 (unsigned long)state->pid,
1031 (unsigned long)gid));
1033 /* always use the async interface */
1034 winbindd_gid2sid_async(state->mem_ctx, gid, getgrgid_recv, state);
1038 * set/get/endgrent functions
1041 /* "Rewind" file pointer for group database enumeration */
1043 static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
1045 struct winbindd_domain *domain;
1047 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
1049 /* Check user has enabled this */
1051 if (!lp_winbind_enum_groups()) {
1052 return False;
1055 /* Free old static data if it exists */
1057 if (state->getgrent_state != NULL) {
1058 free_getent_state(state->getgrent_state);
1059 state->getgrent_state = NULL;
1062 /* Create sam pipes for each domain we know about */
1064 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1065 struct getent_state *domain_state;
1067 /* Create a state record for this domain */
1069 /* don't add our domaina if we are a PDC or if we
1070 are a member of a Samba domain */
1072 if ( lp_winbind_trusted_domains_only() && domain->primary )
1074 continue;
1077 domain_state = SMB_MALLOC_P(struct getent_state);
1078 if (!domain_state) {
1079 DEBUG(1, ("winbindd_setgrent: "
1080 "malloc failed for domain_state!\n"));
1081 return False;
1084 ZERO_STRUCTP(domain_state);
1086 fstrcpy(domain_state->domain_name, domain->name);
1088 /* Add to list of open domains */
1090 DLIST_ADD(state->getgrent_state, domain_state);
1093 state->getgrent_initialized = True;
1094 return True;
1097 void winbindd_setgrent(struct winbindd_cli_state *state)
1099 if (winbindd_setgrent_internal(state)) {
1100 request_ok(state);
1101 } else {
1102 request_error(state);
1106 /* Close file pointer to ntdom group database */
1108 void winbindd_endgrent(struct winbindd_cli_state *state)
1110 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
1112 free_getent_state(state->getgrent_state);
1113 state->getgrent_initialized = False;
1114 state->getgrent_state = NULL;
1115 request_ok(state);
1118 /* Get the list of domain groups and domain aliases for a domain. We fill in
1119 the sam_entries and num_sam_entries fields with domain group information.
1120 Return True if some groups were returned, False otherwise. */
1122 bool get_sam_group_entries(struct getent_state *ent)
1124 NTSTATUS status;
1125 uint32 num_entries;
1126 struct acct_info *name_list = NULL;
1127 TALLOC_CTX *mem_ctx;
1128 bool result = False;
1129 struct acct_info *sam_grp_entries = NULL;
1130 struct winbindd_domain *domain;
1132 if (ent->got_sam_entries)
1133 return False;
1135 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
1136 ent->domain_name))) {
1137 DEBUG(1, ("get_sam_group_entries: "
1138 "could not create talloc context!\n"));
1139 return False;
1142 /* Free any existing group info */
1144 SAFE_FREE(ent->sam_entries);
1145 ent->num_sam_entries = 0;
1146 ent->got_sam_entries = True;
1148 /* Enumerate domain groups */
1150 num_entries = 0;
1152 if (!(domain = find_domain_from_name(ent->domain_name))) {
1153 DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
1154 ent->domain_name));
1155 goto done;
1158 /* always get the domain global groups */
1160 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries,
1161 &sam_grp_entries);
1163 if (!NT_STATUS_IS_OK(status)) {
1164 DEBUG(3, ("get_sam_group_entries: "
1165 "could not enumerate domain groups! Error: %s\n",
1166 nt_errstr(status)));
1167 result = False;
1168 goto done;
1171 /* Copy entries into return buffer */
1173 if (num_entries) {
1174 name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries);
1175 if (!name_list) {
1176 DEBUG(0,("get_sam_group_entries: Failed to malloc "
1177 "memory for %d domain groups!\n",
1178 num_entries));
1179 result = False;
1180 goto done;
1182 memcpy(name_list, sam_grp_entries,
1183 num_entries * sizeof(struct acct_info));
1186 ent->num_sam_entries = num_entries;
1188 /* get the domain local groups if we are a member of a native win2k
1189 * domain and are not using LDAP to get the groups */
1191 if ( ( lp_security() != SEC_ADS && domain->native_mode
1192 && domain->primary) || domain->internal )
1194 DEBUG(4,("get_sam_group_entries: %s domain; "
1195 "enumerating local groups as well\n",
1196 domain->native_mode ? "Native Mode 2k":
1197 "BUILTIN or local"));
1199 status = domain->methods->enum_local_groups(domain, mem_ctx,
1200 &num_entries,
1201 &sam_grp_entries);
1203 if ( !NT_STATUS_IS_OK(status) ) {
1204 DEBUG(3,("get_sam_group_entries: "
1205 "Failed to enumerate "
1206 "domain local groups with error %s!\n",
1207 nt_errstr(status)));
1208 num_entries = 0;
1210 else
1211 DEBUG(4,("get_sam_group_entries: "
1212 "Returned %d local groups\n",
1213 num_entries));
1215 /* Copy entries into return buffer */
1217 if ( num_entries ) {
1218 name_list = SMB_REALLOC_ARRAY(name_list,
1219 struct acct_info,
1220 ent->num_sam_entries+
1221 num_entries);
1222 if (!name_list) {
1223 DEBUG(0,("get_sam_group_entries: "
1224 "Failed to realloc more memory "
1225 "for %d local groups!\n",
1226 num_entries));
1227 result = False;
1228 goto done;
1231 memcpy(&name_list[ent->num_sam_entries],
1232 sam_grp_entries,
1233 num_entries * sizeof(struct acct_info));
1236 ent->num_sam_entries += num_entries;
1240 /* Fill in remaining fields */
1242 ent->sam_entries = name_list;
1243 ent->sam_entry_index = 0;
1245 result = (ent->num_sam_entries > 0);
1247 done:
1248 talloc_destroy(mem_ctx);
1250 return result;
1253 /* Fetch next group entry from ntdom database */
1255 #define MAX_GETGRENT_GROUPS 500
1257 void winbindd_getgrent(struct winbindd_cli_state *state)
1259 struct getent_state *ent;
1260 struct winbindd_gr *group_list = NULL;
1261 int num_groups, group_list_ndx, gr_mem_list_len = 0;
1262 char *gr_mem_list = NULL;
1264 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1266 /* Check user has enabled this */
1268 if (!lp_winbind_enum_groups()) {
1269 request_error(state);
1270 return;
1273 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
1275 if (num_groups == 0) {
1276 request_error(state);
1277 return;
1280 group_list = talloc_zero_array(state->mem_ctx, struct winbindd_gr,
1281 num_groups);
1282 if (!group_list) {
1283 request_error(state);
1284 return;
1286 state->response.extra_data.data = group_list;
1288 state->response.data.num_entries = 0;
1290 if (!state->getgrent_initialized)
1291 winbindd_setgrent_internal(state);
1293 if (!(ent = state->getgrent_state)) {
1294 request_error(state);
1295 return;
1298 /* Start sending back groups */
1300 for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
1301 struct acct_info *name_list = NULL;
1302 fstring domain_group_name;
1303 uint32 result;
1304 gid_t group_gid;
1305 size_t gr_mem_len;
1306 char *gr_mem;
1307 DOM_SID group_sid;
1308 struct winbindd_domain *domain;
1310 /* Do we need to fetch another chunk of groups? */
1312 tryagain:
1314 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1315 ent->sam_entry_index, ent->num_sam_entries));
1317 if (ent->num_sam_entries == ent->sam_entry_index) {
1319 while(ent && !get_sam_group_entries(ent)) {
1320 struct getent_state *next_ent;
1322 DEBUG(10, ("freeing state info for domain %s\n",
1323 ent->domain_name));
1325 /* Free state information for this domain */
1327 SAFE_FREE(ent->sam_entries);
1329 next_ent = ent->next;
1330 DLIST_REMOVE(state->getgrent_state, ent);
1332 SAFE_FREE(ent);
1333 ent = next_ent;
1336 /* No more domains */
1338 if (!ent)
1339 break;
1342 name_list = (struct acct_info *)ent->sam_entries;
1344 if (!(domain = find_domain_from_name(ent->domain_name))) {
1345 DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
1346 ent->domain_name));
1347 result = False;
1348 goto done;
1351 /* Lookup group info */
1353 sid_copy(&group_sid, &domain->sid);
1354 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1356 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->have_idmap_config
1357 ? domain->name : "",
1358 &group_sid, &group_gid)))
1360 union unid_t id;
1361 enum lsa_SidType type;
1363 DEBUG(10, ("SID %s not in idmap\n",
1364 sid_string_dbg(&group_sid)));
1366 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1367 DEBUG(1,("could not look up gid for group %s\n",
1368 name_list[ent->sam_entry_index].acct_name));
1369 ent->sam_entry_index++;
1370 goto tryagain;
1373 if ((type != SID_NAME_DOM_GRP) &&
1374 (type != SID_NAME_ALIAS) &&
1375 (type != SID_NAME_WKN_GRP)) {
1376 DEBUG(1, ("Group %s is a %s, not a group\n",
1377 sid_type_lookup(type),
1378 name_list[ent->sam_entry_index].acct_name));
1379 ent->sam_entry_index++;
1380 goto tryagain;
1382 group_gid = id.gid;
1385 DEBUG(10, ("got gid %lu for group %lu\n",
1386 (unsigned long)group_gid,
1387 (unsigned long)name_list[ent->sam_entry_index].rid));
1389 /* Fill in group entry */
1391 fill_domain_username(domain_group_name, ent->domain_name,
1392 name_list[ent->sam_entry_index].acct_name, True);
1394 result = fill_grent(state->mem_ctx, &group_list[group_list_ndx],
1395 ent->domain_name,
1396 name_list[ent->sam_entry_index].acct_name,
1397 group_gid);
1399 /* Fill in group membership entry */
1401 if (result) {
1402 size_t num_gr_mem = 0;
1403 DOM_SID member_sid;
1404 group_list[group_list_ndx].num_gr_mem = 0;
1405 gr_mem = NULL;
1406 gr_mem_len = 0;
1408 /* Get group membership */
1409 if (state->request.cmd == WINBINDD_GETGRLST) {
1410 result = True;
1411 } else {
1412 sid_copy(&member_sid, &domain->sid);
1413 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1414 result = fill_grent_mem(
1415 domain,
1416 NULL,
1417 &member_sid,
1418 SID_NAME_DOM_GRP,
1419 &num_gr_mem,
1420 &gr_mem, &gr_mem_len);
1422 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1426 if (result) {
1427 /* Append to group membership list */
1428 gr_mem_list = (char *)SMB_REALLOC(
1429 gr_mem_list, gr_mem_list_len + gr_mem_len);
1431 if (!gr_mem_list &&
1432 (group_list[group_list_ndx].num_gr_mem != 0)) {
1433 DEBUG(0, ("out of memory\n"));
1434 gr_mem_list_len = 0;
1435 break;
1438 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1439 gr_mem_list_len, (unsigned int)gr_mem_len));
1441 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1442 gr_mem_len);
1444 SAFE_FREE(gr_mem);
1446 group_list[group_list_ndx].gr_mem_ofs =
1447 gr_mem_list_len;
1449 gr_mem_list_len += gr_mem_len;
1452 ent->sam_entry_index++;
1454 /* Add group to return list */
1456 if (result) {
1458 DEBUG(10, ("adding group num_entries = %d\n",
1459 state->response.data.num_entries));
1461 group_list_ndx++;
1462 state->response.data.num_entries++;
1464 state->response.length +=
1465 sizeof(struct winbindd_gr);
1467 } else {
1468 DEBUG(0, ("could not lookup domain group %s\n",
1469 domain_group_name));
1473 /* Copy the list of group memberships to the end of the extra data */
1475 if (group_list_ndx == 0)
1476 goto done;
1478 state->response.extra_data.data = talloc_realloc_size(
1479 state->mem_ctx, state->response.extra_data.data,
1480 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1482 if (!state->response.extra_data.data) {
1483 DEBUG(0, ("out of memory\n"));
1484 group_list_ndx = 0;
1485 SAFE_FREE(gr_mem_list);
1486 request_error(state);
1487 return;
1490 memcpy(&((char *)state->response.extra_data.data)
1491 [group_list_ndx * sizeof(struct winbindd_gr)],
1492 gr_mem_list, gr_mem_list_len);
1494 state->response.length += gr_mem_list_len;
1496 DEBUG(10, ("returning %d groups, length = %d\n",
1497 group_list_ndx, gr_mem_list_len));
1499 /* Out of domains */
1501 done:
1503 SAFE_FREE(gr_mem_list);
1505 if (group_list_ndx > 0)
1506 request_ok(state);
1507 else
1508 request_error(state);
1511 /* List domain groups without mapping to unix ids */
1512 void winbindd_list_groups(struct winbindd_cli_state *state)
1514 winbindd_list_ent(state, LIST_GROUPS);
1517 /* Get user supplementary groups. This is much quicker than trying to
1518 invert the groups database. We merge the groups from the gids and
1519 other_sids info3 fields as trusted domain, universal group
1520 memberships, and nested groups (win2k native mode only) are not
1521 returned by the getgroups RPC call but are present in the info3. */
1523 struct getgroups_state {
1524 struct winbindd_cli_state *state;
1525 struct winbindd_domain *domain;
1526 char *domname;
1527 char *username;
1528 DOM_SID user_sid;
1530 const DOM_SID *token_sids;
1531 size_t i, num_token_sids;
1533 gid_t *token_gids;
1534 size_t num_token_gids;
1537 static void getgroups_usersid_recv(void *private_data, bool success,
1538 const DOM_SID *sid, enum lsa_SidType type);
1539 static void getgroups_tokensids_recv(void *private_data, bool success,
1540 DOM_SID *token_sids, size_t num_token_sids);
1541 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1543 void winbindd_getgroups(struct winbindd_cli_state *state)
1545 struct getgroups_state *s;
1546 char *real_name = NULL;
1547 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1549 /* Ensure null termination */
1550 state->request.data.username
1551 [sizeof(state->request.data.username)-1]='\0';
1553 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1554 state->request.data.username));
1556 /* Parse domain and username */
1558 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1559 if (s == NULL) {
1560 DEBUG(0, ("talloc failed\n"));
1561 request_error(state);
1562 return;
1565 s->state = state;
1567 nt_status = normalize_name_unmap(state->mem_ctx,
1568 state->request.data.username,
1569 &real_name);
1571 /* Reset the real_name pointer if we didn't do anything
1572 productive in the above call */
1573 if (!NT_STATUS_IS_OK(nt_status) &&
1574 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
1576 real_name = state->request.data.username;
1579 if (!parse_domain_user_talloc(state->mem_ctx, real_name,
1580 &s->domname, &s->username)) {
1581 DEBUG(5, ("Could not parse domain user: %s\n",
1582 real_name));
1584 /* error out if we do not have nested group support */
1586 if ( !lp_winbind_nested_groups() ) {
1587 request_error(state);
1588 return;
1591 s->domname = talloc_strdup(state->mem_ctx,
1592 get_global_sam_name());
1593 s->username = talloc_strdup(state->mem_ctx,
1594 state->request.data.username);
1597 /* Get info for the domain (either by short domain name or
1598 DNS name in the case of a UPN) */
1600 s->domain = find_domain_from_name_noinit(s->domname);
1601 if (!s->domain) {
1602 char *p = strchr(s->username, '@');
1604 if (p) {
1605 s->domain = find_domain_from_name_noinit(p+1);
1610 if (s->domain == NULL) {
1611 DEBUG(7, ("could not find domain entry for domain %s\n",
1612 s->domname));
1613 request_error(state);
1614 return;
1617 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1618 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1619 "getgroups() for %s\\%s.\n", s->domname,
1620 s->username));
1621 request_error(state);
1622 return;
1625 /* Get rid and name type from name. The following costs 1 packet */
1627 winbindd_lookupname_async(state->mem_ctx,
1628 s->domname, s->username,
1629 getgroups_usersid_recv,
1630 WINBINDD_GETGROUPS, s);
1633 static void getgroups_usersid_recv(void *private_data, bool success,
1634 const DOM_SID *sid, enum lsa_SidType type)
1636 struct getgroups_state *s =
1637 (struct getgroups_state *)private_data;
1639 if ((!success) ||
1640 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1641 request_error(s->state);
1642 return;
1645 sid_copy(&s->user_sid, sid);
1647 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1648 getgroups_tokensids_recv, s);
1651 static void getgroups_tokensids_recv(void *private_data, bool success,
1652 DOM_SID *token_sids, size_t num_token_sids)
1654 struct getgroups_state *s =
1655 (struct getgroups_state *)private_data;
1657 /* We need at least the user sid and the primary group in the token,
1658 * otherwise it's an error */
1660 if ((!success) || (num_token_sids < 2)) {
1661 request_error(s->state);
1662 return;
1665 s->token_sids = token_sids;
1666 s->num_token_sids = num_token_sids;
1667 s->i = 0;
1669 s->token_gids = NULL;
1670 s->num_token_gids = 0;
1672 getgroups_sid2gid_recv(s, False, 0);
1675 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
1677 struct getgroups_state *s =
1678 (struct getgroups_state *)private_data;
1680 if (success) {
1681 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1682 &s->token_gids,
1683 &s->num_token_gids)) {
1684 return;
1688 if (s->i < s->num_token_sids) {
1689 const DOM_SID *sid = &s->token_sids[s->i];
1690 s->i += 1;
1692 if (sid_equal(sid, &s->user_sid)) {
1693 getgroups_sid2gid_recv(s, False, 0);
1694 return;
1697 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1698 getgroups_sid2gid_recv, s);
1699 return;
1702 s->state->response.data.num_entries = s->num_token_gids;
1703 if (s->num_token_gids) {
1704 s->state->response.extra_data.data = s->token_gids;
1705 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1707 request_ok(s->state);
1710 /* Get user supplementary sids. This is equivalent to the
1711 winbindd_getgroups() function but it involves a SID->SIDs mapping
1712 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1713 idmap. This call is designed to be used with applications that need
1714 to do ACL evaluation themselves. Note that the cached info3 data is
1715 not used
1717 this function assumes that the SID that comes in is a user SID. If
1718 you pass in another type of SID then you may get unpredictable
1719 results.
1722 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1723 size_t num_sids);
1725 void winbindd_getusersids(struct winbindd_cli_state *state)
1727 DOM_SID *user_sid;
1729 /* Ensure null termination */
1730 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1732 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1733 if (user_sid == NULL) {
1734 DEBUG(1, ("talloc failed\n"));
1735 request_error(state);
1736 return;
1739 if (!string_to_sid(user_sid, state->request.data.sid)) {
1740 DEBUG(1, ("Could not get convert sid %s from string\n",
1741 state->request.data.sid));
1742 request_error(state);
1743 return;
1746 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1747 state);
1750 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1751 size_t num_sids)
1753 struct winbindd_cli_state *state =
1754 (struct winbindd_cli_state *)private_data;
1755 char *ret = NULL;
1756 unsigned ofs, ret_size = 0;
1757 size_t i;
1759 if (!success) {
1760 request_error(state);
1761 return;
1764 /* work out the response size */
1765 for (i = 0; i < num_sids; i++) {
1766 fstring s;
1767 sid_to_fstring(s, &sids[i]);
1768 ret_size += strlen(s) + 1;
1771 /* build the reply */
1772 ret = talloc_array(state->mem_ctx, char, ret_size);
1773 if (!ret) {
1774 DEBUG(0, ("malloc failed\n"));
1775 request_error(state);
1776 return;
1778 ofs = 0;
1779 for (i = 0; i < num_sids; i++) {
1780 fstring s;
1781 sid_to_fstring(s, &sids[i]);
1782 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1783 ofs += strlen(ret+ofs) + 1;
1786 /* Send data back to client */
1787 state->response.data.num_entries = num_sids;
1788 state->response.extra_data.data = ret;
1789 state->response.length += ret_size;
1790 request_ok(state);
1793 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1795 DOM_SID user_sid;
1796 struct winbindd_domain *domain;
1798 /* Ensure null termination */
1799 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1801 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1802 DEBUG(1, ("Could not get convert sid %s from string\n",
1803 state->request.data.sid));
1804 request_error(state);
1805 return;
1808 /* Get info for the domain */
1809 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1810 DEBUG(0,("could not find domain entry for sid %s\n",
1811 sid_string_dbg(&user_sid)));
1812 request_error(state);
1813 return;
1816 sendto_domain(state, domain);
1819 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1820 struct winbindd_cli_state *state)
1822 DOM_SID user_sid;
1823 NTSTATUS status;
1825 char *sidstring;
1826 ssize_t len;
1827 DOM_SID *groups;
1828 uint32 num_groups;
1830 /* Ensure null termination */
1831 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1833 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1834 DEBUG(1, ("Could not get convert sid %s from string\n",
1835 state->request.data.sid));
1836 return WINBINDD_ERROR;
1839 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1840 &user_sid, &num_groups,
1841 &groups);
1842 if (!NT_STATUS_IS_OK(status))
1843 return WINBINDD_ERROR;
1845 if (num_groups == 0) {
1846 state->response.data.num_entries = 0;
1847 state->response.extra_data.data = NULL;
1848 return WINBINDD_OK;
1851 if (!print_sidlist(state->mem_ctx,
1852 groups, num_groups,
1853 &sidstring, &len)) {
1854 DEBUG(0, ("talloc failed\n"));
1855 return WINBINDD_ERROR;
1858 state->response.extra_data.data = sidstring;
1859 state->response.length += len+1;
1860 state->response.data.num_entries = num_groups;
1862 return WINBINDD_OK;
1865 void winbindd_getsidaliases(struct winbindd_cli_state *state)
1867 DOM_SID domain_sid;
1868 struct winbindd_domain *domain;
1870 /* Ensure null termination */
1871 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1873 if (!string_to_sid(&domain_sid, state->request.data.sid)) {
1874 DEBUG(1, ("Could not get convert sid %s from string\n",
1875 state->request.data.sid));
1876 request_error(state);
1877 return;
1880 /* Get info for the domain */
1881 if ((domain = find_domain_from_sid_noinit(&domain_sid)) == NULL) {
1882 DEBUG(0,("could not find domain entry for sid %s\n",
1883 sid_string_dbg(&domain_sid)));
1884 request_error(state);
1885 return;
1888 sendto_domain(state, domain);
1891 enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
1892 struct winbindd_cli_state *state)
1894 DOM_SID *sids = NULL;
1895 size_t num_sids = 0;
1896 char *sidstr = NULL;
1897 ssize_t len;
1898 size_t i;
1899 uint32 num_aliases;
1900 uint32 *alias_rids;
1901 NTSTATUS result;
1903 DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
1905 sidstr = state->request.extra_data.data;
1906 if (sidstr == NULL) {
1907 sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
1908 if (!sidstr) {
1909 DEBUG(0, ("Out of memory\n"));
1910 return WINBINDD_ERROR;
1914 DEBUG(10, ("Sidlist: %s\n", sidstr));
1916 if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
1917 DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
1918 return WINBINDD_ERROR;
1921 num_aliases = 0;
1922 alias_rids = NULL;
1924 result = domain->methods->lookup_useraliases(domain,
1925 state->mem_ctx,
1926 num_sids, sids,
1927 &num_aliases,
1928 &alias_rids);
1930 if (!NT_STATUS_IS_OK(result)) {
1931 DEBUG(3, ("Could not lookup_useraliases: %s\n",
1932 nt_errstr(result)));
1933 return WINBINDD_ERROR;
1936 num_sids = 0;
1937 sids = NULL;
1938 sidstr = NULL;
1940 DEBUG(10, ("Got %d aliases\n", num_aliases));
1942 for (i=0; i<num_aliases; i++) {
1943 DOM_SID sid;
1944 DEBUGADD(10, (" rid %d\n", alias_rids[i]));
1945 sid_copy(&sid, &domain->sid);
1946 sid_append_rid(&sid, alias_rids[i]);
1947 result = add_sid_to_array(state->mem_ctx, &sid, &sids,
1948 &num_sids);
1949 if (!NT_STATUS_IS_OK(result)) {
1950 return WINBINDD_ERROR;
1955 if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
1956 DEBUG(0, ("Could not print_sidlist\n"));
1957 state->response.extra_data.data = NULL;
1958 return WINBINDD_ERROR;
1961 state->response.extra_data.data = NULL;
1963 if (sidstr) {
1964 state->response.extra_data.data = sidstr;
1965 DEBUG(10, ("aliases_list: %s\n",
1966 (char *)state->response.extra_data.data));
1967 state->response.length += len+1;
1968 state->response.data.num_entries = num_sids;
1971 return WINBINDD_OK;