Make winbindd_cli_state->response a pointer instead of a struct member
[Samba.git] / source3 / winbindd / winbindd_group.c
blobf78becb69902da0e6b00d44e5187b4c1c4b00556
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, talloc_tos(),
161 &members, &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 DEBUG(10,("expand_groups:\n"));
465 for ( i=0; i<n_glist; i++ ) {
467 NTSTATUS lookup_status;
469 tmp_ctx = talloc_new( ctx );
471 /* Lookup the group membership */
473 lookup_status = d->methods->lookup_groupmem(d, tmp_ctx,
474 &glist[i], &num_names,
475 &sid_mem, &names,
476 &name_types);
477 if (!NT_STATUS_IS_OK(lookup_status)) {
478 DEBUG(10,("expand_groups: lookup_groupmem for "
479 "sid %s failed with: %s\n",
480 sid_string_dbg(&glist[i]),
481 nt_errstr(lookup_status)));
483 /* we might have hit a logic error when called for an
484 * alias, in that case just continue with group
485 * expansion - Guenther */
487 if (NT_STATUS_EQUAL(lookup_status, NT_STATUS_NO_SUCH_GROUP)) {
488 continue;
490 status = lookup_status;
491 goto out;
494 /* Separate users and groups into two lists */
496 for ( j=0; j<num_names; j++ ) {
498 /* Users */
499 if ( name_types[j] == SID_NAME_USER ||
500 name_types[j] == SID_NAME_COMPUTER )
502 status = add_names_to_list( ctx, members,
503 n_members,
504 names+j, 1 );
505 if ( !NT_STATUS_IS_OK(status) )
506 goto out;
508 continue;
511 /* Groups */
512 if ( name_types[j] == SID_NAME_DOM_GRP ||
513 name_types[j] == SID_NAME_ALIAS )
515 status = add_sid_to_array_unique(ctx,
516 &sid_mem[j],
517 &new_groups,
518 &new_groups_size);
519 if (!NT_STATUS_IS_OK(status)) {
520 goto out;
523 continue;
527 TALLOC_FREE( tmp_ctx );
530 *new_glist = new_groups;
531 *n_new_glist = (uint32)new_groups_size;
533 out:
534 TALLOC_FREE( tmp_ctx );
536 if (!NT_STATUS_IS_OK(status)) {
537 DEBUG(10,("expand_groups: returning with %s\n",
538 nt_errstr(status)));
541 return status;
544 /***********************************************************************
545 Fill in the group membership field of a NT group given by group_sid
546 ***********************************************************************/
548 static bool fill_grent_mem(struct winbindd_domain *domain,
549 struct winbindd_cli_state *state,
550 DOM_SID *group_sid,
551 enum lsa_SidType group_name_type,
552 size_t *num_gr_mem, char **gr_mem,
553 size_t *gr_mem_len)
555 uint32 num_names = 0;
556 unsigned int buf_len = 0, buf_ndx = 0, i;
557 char **names = NULL, *buf = NULL;
558 bool result = False;
559 TALLOC_CTX *mem_ctx;
560 uint32 group_rid;
561 DOM_SID *glist = NULL;
562 DOM_SID *new_glist = NULL;
563 uint32 n_glist, n_new_glist;
564 int max_depth = lp_winbind_expand_groups();
566 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
567 return False;
569 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
571 /* Initialize with no members */
573 *num_gr_mem = 0;
575 /* HACK ALERT!! This whole routine does not cope with group members
576 * from more than one domain, ie aliases. Thus we have to work it out
577 * ourselves in a special routine. */
579 if (domain->internal) {
580 result = fill_passdb_alias_grmem(domain, group_sid,
581 num_gr_mem,
582 gr_mem, gr_mem_len);
583 goto done;
586 /* Verify name type */
588 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
589 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
591 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
592 sid_string_dbg(group_sid),
593 domain->name, group_name_type));
594 goto done;
597 /* OPTIMIZATION / HACK. See comment in
598 fill_grent_mem_domusers() */
600 sid_peek_rid( group_sid, &group_rid );
601 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
602 result = fill_grent_mem_domusers( mem_ctx, domain, state,
603 group_sid, group_name_type,
604 num_gr_mem, gr_mem,
605 gr_mem_len );
606 goto done;
609 /* Real work goes here. Create a list of group names to
610 expand starting with the initial one. Pass that to
611 expand_groups() which returns a list of more group names
612 to expand. Do this up to the max search depth. */
614 if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
615 result = False;
616 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
617 goto done;
619 sid_copy( &glist[0], group_sid );
620 n_glist = 1;
622 for ( i=0; i<max_depth && glist; i++ ) {
623 uint32 n_members = 0;
624 char **members = NULL;
625 NTSTATUS nt_status;
626 int j;
628 nt_status = expand_groups( mem_ctx, domain,
629 glist, n_glist,
630 &new_glist, &n_new_glist,
631 &members, &n_members);
632 if ( !NT_STATUS_IS_OK(nt_status) ) {
633 result = False;
634 goto done;
637 /* Add new group members to list. Pass through the
638 alias mapping function */
640 for (j=0; j<n_members; j++) {
641 fstring name_domain, name_acct;
642 fstring qualified_name;
643 char *mapped_name = NULL;
644 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
645 struct winbindd_domain *target_domain = NULL;
647 if (parse_domain_user(members[j], name_domain, name_acct)) {
648 target_domain = find_domain_from_name_noinit(name_domain);
649 /* NOW WHAT ? */
651 if (!target_domain) {
652 target_domain = domain;
655 name_map_status = normalize_name_map(members, target_domain,
656 name_acct, &mapped_name);
658 /* Basic whitespace replacement */
659 if (NT_STATUS_IS_OK(name_map_status)) {
660 fill_domain_username(qualified_name, name_domain,
661 mapped_name, true);
662 mapped_name = qualified_name;
664 /* no mapping at all */
665 else if (!NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
666 mapped_name = members[j];
669 nt_status = add_names_to_list( mem_ctx, &names,
670 &num_names,
671 &mapped_name, 1);
672 if ( !NT_STATUS_IS_OK(nt_status) ) {
673 result = False;
674 goto done;
678 TALLOC_FREE( members );
680 /* If we have no more groups to expand, break out
681 early */
683 if (new_glist == NULL)
684 break;
686 /* One more round */
687 TALLOC_FREE(glist);
688 glist = new_glist;
689 n_glist = n_new_glist;
691 TALLOC_FREE( glist );
693 sort_unique_list(&names, &num_names);
695 DEBUG(10, ("looked up %d names\n", num_names));
697 again:
698 /* Add members to list */
700 for (i = 0; i < num_names; i++) {
701 int len;
703 DEBUG(10, ("processing name %s\n", names[i]));
705 len = strlen(names[i]);
707 /* Add to list or calculate buffer length */
709 if (!buf) {
710 buf_len += len + 1; /* List is comma separated */
711 (*num_gr_mem)++;
712 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
713 } else {
714 DEBUG(10, ("appending %s at ndx %d\n",
715 names[i], buf_ndx));
716 parse_add_domuser(&buf[buf_ndx], names[i], &len);
717 buf_ndx += len;
718 buf[buf_ndx] = ',';
719 buf_ndx++;
723 /* Allocate buffer */
725 if (!buf && buf_len != 0) {
726 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
727 DEBUG(1, ("out of memory\n"));
728 result = False;
729 goto done;
731 memset(buf, 0, buf_len);
732 goto again;
735 /* Now we're done */
737 if (buf && buf_ndx > 0) {
738 buf[buf_ndx - 1] = '\0';
741 *gr_mem = buf;
742 *gr_mem_len = buf_len;
744 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n",
745 (unsigned int)*num_gr_mem,
746 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
747 result = True;
749 done:
751 talloc_destroy(mem_ctx);
753 DEBUG(10,("fill_grent_mem returning %s\n",
754 result == true ? "true" : "false"));
756 return result;
759 static void winbindd_getgrsid(struct winbindd_cli_state *state, DOM_SID group_sid);
761 static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
762 enum lsa_SidType type )
764 struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
766 if (!success) {
767 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
768 request_error(state);
769 return;
772 if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
773 DEBUG(5,("getgrnam_recv: not a group!\n"));
774 request_error(state);
775 return;
778 winbindd_getgrsid( state, *sid );
782 /* Return a group structure from a group name */
784 void winbindd_getgrnam(struct winbindd_cli_state *state)
786 struct winbindd_domain *domain;
787 fstring name_domain, name_group;
788 char *tmp;
789 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
791 /* Ensure null termination */
792 state->request->data.groupname[sizeof(state->request->data.groupname)-1]='\0';
794 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
795 state->request->data.groupname));
797 nt_status = normalize_name_unmap(state->mem_ctx,
798 state->request->data.groupname,
799 &tmp);
800 /* If we didn't map anything in the above call, just reset the
801 tmp pointer to the original string */
802 if (!NT_STATUS_IS_OK(nt_status) &&
803 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
805 tmp = state->request->data.groupname;
808 /* Parse domain and groupname */
810 memset(name_group, 0, sizeof(name_group));
812 name_domain[0] = '\0';
813 name_group[0] = '\0';
815 parse_domain_user(tmp, name_domain, name_group);
817 /* if no domain or our local domain and no local tdb group, default to
818 * our local domain for aliases */
820 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
821 fstrcpy(name_domain, get_global_sam_name());
824 /* Get info for the domain */
826 if ((domain = find_domain_from_name_noinit(name_domain)) == NULL) {
827 DEBUG(3, ("could not get domain sid for domain %s\n",
828 name_domain));
829 request_error(state);
830 return;
832 /* should we deal with users for our domain? */
834 if ( lp_winbind_trusted_domains_only() && domain->primary) {
835 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
836 "getgrnam() for %s\\%s.\n", name_domain, name_group));
837 request_error(state);
838 return;
841 /* Get rid and name type from name */
843 fstrcpy( name_group, tmp );
845 winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
846 getgrnam_recv, WINBINDD_GETGRNAM, state );
849 struct getgrsid_state {
850 struct winbindd_cli_state *state;
851 struct winbindd_domain *domain;
852 char *group_name;
853 enum lsa_SidType group_type;
854 uid_t gid;
855 DOM_SID group_sid;
858 static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
860 struct getgrsid_state *s =
861 (struct getgrsid_state *)private_data;
862 struct winbindd_domain *domain;
863 size_t gr_mem_len;
864 size_t num_gr_mem;
865 char *gr_mem;
866 fstring dom_name, group_name;
868 if (!success) {
869 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
870 request_error(s->state);
871 return;
874 s->gid = gid;
876 if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
877 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
878 request_error(s->state);
879 return;
883 /* Fill in group structure */
885 if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
886 DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
887 request_error(s->state);
888 return;
891 if (!fill_grent(s->state->mem_ctx, &s->state->response->data.gr,
892 dom_name, group_name, gid) ||
893 !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
894 &num_gr_mem, &gr_mem, &gr_mem_len))
896 request_error(s->state);
897 return;
900 s->state->response->data.gr.num_gr_mem = (uint32)num_gr_mem;
902 /* Group membership lives at start of extra data */
904 s->state->response->data.gr.gr_mem_ofs = 0;
906 s->state->response->length += gr_mem_len;
907 s->state->response->extra_data.data = talloc_memdup(
908 s->state->mem_ctx, gr_mem, gr_mem_len);
909 if (s->state->response->extra_data.data == NULL) {
910 request_error(s->state);
911 return;
914 request_ok(s->state);
917 static void getgrsid_lookupsid_recv( void *private_data, bool success,
918 const char *dom_name, const char *name,
919 enum lsa_SidType name_type )
921 struct getgrsid_state *s = (struct getgrsid_state *)private_data;
922 char *mapped_name = NULL;
923 fstring raw_name;
924 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
926 if (!success) {
927 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
928 request_error(s->state);
929 return;
932 /* either it's a domain group, a domain local group, or a
933 local group in an internal domain */
935 if ( !( (name_type==SID_NAME_DOM_GRP) ||
936 ((name_type==SID_NAME_ALIAS) &&
937 (s->domain->primary || s->domain->internal)) ) )
939 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
940 dom_name, name, name_type));
941 request_error(s->state);
942 return;
945 /* normalize the name and ensure that we have the DOM\name
946 coming out of here */
948 fstrcpy(raw_name, name);
950 nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name,
951 &mapped_name);
953 /* basic whitespace reversal */
954 if (NT_STATUS_IS_OK(nt_status)) {
955 s->group_name = talloc_asprintf(s->state->mem_ctx,
956 "%s%c%s",
957 dom_name,
958 *lp_winbind_separator(),
959 mapped_name);
961 /* mapped from alias */
962 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
963 s->group_name = mapped_name;
965 /* no mapping at all. use original string */
966 else {
967 s->group_name = talloc_asprintf(s->state->mem_ctx,
968 "%s%c%s",
969 dom_name,
970 *lp_winbind_separator(),
971 raw_name);
974 if (s->group_name == NULL) {
975 DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
976 request_error(s->state);
977 return;
980 s->group_type = name_type;
982 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
983 getgrsid_sid2gid_recv, s);
986 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
988 struct getgrsid_state *s;
990 if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
991 DEBUG(0, ("talloc failed\n"));
992 request_error(state);
993 return;
996 s->state = state;
998 if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
999 DEBUG(3, ("Could not find domain for sid %s\n",
1000 sid_string_dbg(&group_sid)));
1001 request_error(state);
1002 return;
1005 sid_copy(&s->group_sid, &group_sid);
1007 winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
1008 getgrsid_lookupsid_recv, s );
1012 static void getgrgid_recv(void *private_data, bool success, const char *sid)
1014 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
1015 enum lsa_SidType name_type;
1016 DOM_SID group_sid;
1018 if (success) {
1019 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
1020 (unsigned long)(state->request->data.gid), sid));
1022 if (!string_to_sid(&group_sid, sid)) {
1023 DEBUG(1,("getgrgid_recv: Could not convert sid %s "
1024 "from string\n", sid));
1025 request_error(state);
1026 return;
1029 winbindd_getgrsid(state, group_sid);
1030 return;
1033 /* Ok, this might be "ours", i.e. an alias */
1034 if (pdb_gid_to_sid(state->request->data.gid, &group_sid) &&
1035 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
1036 (name_type == SID_NAME_ALIAS)) {
1037 /* Hey, got an alias */
1038 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
1039 (unsigned long)(state->request->data.gid), sid));
1040 winbindd_getgrsid(state, group_sid);
1041 return;
1044 DEBUG(1, ("could not convert gid %lu to sid\n",
1045 (unsigned long)state->request->data.gid));
1046 request_error(state);
1049 /* Return a group structure from a gid number */
1050 void winbindd_getgrgid(struct winbindd_cli_state *state)
1052 gid_t gid = state->request->data.gid;
1054 DEBUG(3, ("[%5lu]: getgrgid %lu\n",
1055 (unsigned long)state->pid,
1056 (unsigned long)gid));
1058 /* always use the async interface */
1059 winbindd_gid2sid_async(state->mem_ctx, gid, getgrgid_recv, state);
1063 * set/get/endgrent functions
1066 /* "Rewind" file pointer for group database enumeration */
1068 static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
1070 struct winbindd_domain *domain;
1072 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
1074 /* Check user has enabled this */
1076 if (!lp_winbind_enum_groups()) {
1077 return False;
1080 /* Free old static data if it exists */
1082 if (state->getgrent_state != NULL) {
1083 free_getent_state(state->getgrent_state);
1084 state->getgrent_state = NULL;
1087 /* Create sam pipes for each domain we know about */
1089 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1090 struct getent_state *domain_state;
1092 /* Create a state record for this domain */
1094 /* don't add our domaina if we are a PDC or if we
1095 are a member of a Samba domain */
1097 if ( lp_winbind_trusted_domains_only() && domain->primary )
1099 continue;
1102 domain_state = SMB_MALLOC_P(struct getent_state);
1103 if (!domain_state) {
1104 DEBUG(1, ("winbindd_setgrent: "
1105 "malloc failed for domain_state!\n"));
1106 return False;
1109 ZERO_STRUCTP(domain_state);
1111 fstrcpy(domain_state->domain_name, domain->name);
1113 /* Add to list of open domains */
1115 DLIST_ADD(state->getgrent_state, domain_state);
1118 state->getgrent_initialized = True;
1119 return True;
1122 void winbindd_setgrent(struct winbindd_cli_state *state)
1124 if (winbindd_setgrent_internal(state)) {
1125 request_ok(state);
1126 } else {
1127 request_error(state);
1131 /* Close file pointer to ntdom group database */
1133 void winbindd_endgrent(struct winbindd_cli_state *state)
1135 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
1137 free_getent_state(state->getgrent_state);
1138 state->getgrent_initialized = False;
1139 state->getgrent_state = NULL;
1140 request_ok(state);
1143 /* Get the list of domain groups and domain aliases for a domain. We fill in
1144 the sam_entries and num_sam_entries fields with domain group information.
1145 Return True if some groups were returned, False otherwise. */
1147 bool get_sam_group_entries(struct getent_state *ent)
1149 NTSTATUS status;
1150 uint32 num_entries;
1151 struct acct_info *name_list = NULL;
1152 TALLOC_CTX *mem_ctx;
1153 bool result = False;
1154 struct acct_info *sam_grp_entries = NULL;
1155 struct winbindd_domain *domain;
1157 if (ent->got_sam_entries)
1158 return False;
1160 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
1161 ent->domain_name))) {
1162 DEBUG(1, ("get_sam_group_entries: "
1163 "could not create talloc context!\n"));
1164 return False;
1167 /* Free any existing group info */
1169 SAFE_FREE(ent->sam_entries);
1170 ent->num_sam_entries = 0;
1171 ent->got_sam_entries = True;
1173 /* Enumerate domain groups */
1175 num_entries = 0;
1177 if (!(domain = find_domain_from_name(ent->domain_name))) {
1178 DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
1179 ent->domain_name));
1180 goto done;
1183 /* always get the domain global groups */
1185 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries,
1186 &sam_grp_entries);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 DEBUG(3, ("get_sam_group_entries: "
1190 "could not enumerate domain groups! Error: %s\n",
1191 nt_errstr(status)));
1192 result = False;
1193 goto done;
1196 /* Copy entries into return buffer */
1198 if (num_entries) {
1199 name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries);
1200 if (!name_list) {
1201 DEBUG(0,("get_sam_group_entries: Failed to malloc "
1202 "memory for %d domain groups!\n",
1203 num_entries));
1204 result = False;
1205 goto done;
1207 memcpy(name_list, sam_grp_entries,
1208 num_entries * sizeof(struct acct_info));
1211 ent->num_sam_entries = num_entries;
1213 /* get the domain local groups if we are a member of a native win2k
1214 * domain and are not using LDAP to get the groups */
1216 if ( ( lp_security() != SEC_ADS && domain->native_mode
1217 && domain->primary) || domain->internal )
1219 DEBUG(4,("get_sam_group_entries: %s domain; "
1220 "enumerating local groups as well\n",
1221 domain->native_mode ? "Native Mode 2k":
1222 "BUILTIN or local"));
1224 status = domain->methods->enum_local_groups(domain, mem_ctx,
1225 &num_entries,
1226 &sam_grp_entries);
1228 if ( !NT_STATUS_IS_OK(status) ) {
1229 DEBUG(3,("get_sam_group_entries: "
1230 "Failed to enumerate "
1231 "domain local groups with error %s!\n",
1232 nt_errstr(status)));
1233 num_entries = 0;
1235 else
1236 DEBUG(4,("get_sam_group_entries: "
1237 "Returned %d local groups\n",
1238 num_entries));
1240 /* Copy entries into return buffer */
1242 if ( num_entries ) {
1243 name_list = SMB_REALLOC_ARRAY(name_list,
1244 struct acct_info,
1245 ent->num_sam_entries+
1246 num_entries);
1247 if (!name_list) {
1248 DEBUG(0,("get_sam_group_entries: "
1249 "Failed to realloc more memory "
1250 "for %d local groups!\n",
1251 num_entries));
1252 result = False;
1253 goto done;
1256 memcpy(&name_list[ent->num_sam_entries],
1257 sam_grp_entries,
1258 num_entries * sizeof(struct acct_info));
1261 ent->num_sam_entries += num_entries;
1265 /* Fill in remaining fields */
1267 ent->sam_entries = name_list;
1268 ent->sam_entry_index = 0;
1270 result = (ent->num_sam_entries > 0);
1272 done:
1273 talloc_destroy(mem_ctx);
1275 return result;
1278 /* Fetch next group entry from ntdom database */
1280 #define MAX_GETGRENT_GROUPS 500
1282 void winbindd_getgrent(struct winbindd_cli_state *state)
1284 struct getent_state *ent;
1285 struct winbindd_gr *group_list = NULL;
1286 int num_groups, group_list_ndx, gr_mem_list_len = 0;
1287 char *gr_mem_list = NULL;
1289 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1291 /* Check user has enabled this */
1293 if (!lp_winbind_enum_groups()) {
1294 request_error(state);
1295 return;
1298 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request->data.num_entries);
1300 if (num_groups == 0) {
1301 request_error(state);
1302 return;
1305 group_list = talloc_zero_array(state->mem_ctx, struct winbindd_gr,
1306 num_groups);
1307 if (!group_list) {
1308 request_error(state);
1309 return;
1311 state->response->extra_data.data = group_list;
1313 state->response->data.num_entries = 0;
1315 if (!state->getgrent_initialized)
1316 winbindd_setgrent_internal(state);
1318 if (!(ent = state->getgrent_state)) {
1319 request_error(state);
1320 return;
1323 /* Start sending back groups */
1325 for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
1326 struct acct_info *name_list = NULL;
1327 fstring domain_group_name;
1328 uint32 result;
1329 gid_t group_gid;
1330 size_t gr_mem_len;
1331 char *gr_mem;
1332 DOM_SID group_sid;
1333 struct winbindd_domain *domain;
1335 /* Do we need to fetch another chunk of groups? */
1337 tryagain:
1339 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1340 ent->sam_entry_index, ent->num_sam_entries));
1342 if (ent->num_sam_entries == ent->sam_entry_index) {
1344 while(ent && !get_sam_group_entries(ent)) {
1345 struct getent_state *next_ent;
1347 DEBUG(10, ("freeing state info for domain %s\n",
1348 ent->domain_name));
1350 /* Free state information for this domain */
1352 SAFE_FREE(ent->sam_entries);
1354 next_ent = ent->next;
1355 DLIST_REMOVE(state->getgrent_state, ent);
1357 SAFE_FREE(ent);
1358 ent = next_ent;
1361 /* No more domains */
1363 if (!ent)
1364 break;
1367 name_list = (struct acct_info *)ent->sam_entries;
1369 if (!(domain = find_domain_from_name(ent->domain_name))) {
1370 DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
1371 ent->domain_name));
1372 result = False;
1373 goto done;
1376 /* Lookup group info */
1378 sid_copy(&group_sid, &domain->sid);
1379 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1381 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->have_idmap_config
1382 ? domain->name : "",
1383 &group_sid, &group_gid)))
1385 union unid_t id;
1386 enum lsa_SidType type;
1388 DEBUG(10, ("SID %s not in idmap\n",
1389 sid_string_dbg(&group_sid)));
1391 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1392 DEBUG(1,("could not look up gid for group %s\n",
1393 name_list[ent->sam_entry_index].acct_name));
1394 ent->sam_entry_index++;
1395 goto tryagain;
1398 if ((type != SID_NAME_DOM_GRP) &&
1399 (type != SID_NAME_ALIAS) &&
1400 (type != SID_NAME_WKN_GRP)) {
1401 DEBUG(1, ("Group %s is a %s, not a group\n",
1402 sid_type_lookup(type),
1403 name_list[ent->sam_entry_index].acct_name));
1404 ent->sam_entry_index++;
1405 goto tryagain;
1407 group_gid = id.gid;
1410 DEBUG(10, ("got gid %lu for group %lu\n",
1411 (unsigned long)group_gid,
1412 (unsigned long)name_list[ent->sam_entry_index].rid));
1414 /* Fill in group entry */
1416 fill_domain_username(domain_group_name, ent->domain_name,
1417 name_list[ent->sam_entry_index].acct_name, True);
1419 result = fill_grent(state->mem_ctx, &group_list[group_list_ndx],
1420 ent->domain_name,
1421 name_list[ent->sam_entry_index].acct_name,
1422 group_gid);
1424 /* Fill in group membership entry */
1426 if (result) {
1427 size_t num_gr_mem = 0;
1428 DOM_SID member_sid;
1429 group_list[group_list_ndx].num_gr_mem = 0;
1430 gr_mem = NULL;
1431 gr_mem_len = 0;
1433 /* Get group membership */
1434 if (state->request->cmd == WINBINDD_GETGRLST) {
1435 result = True;
1436 } else {
1437 sid_copy(&member_sid, &domain->sid);
1438 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1439 result = fill_grent_mem(
1440 domain,
1441 NULL,
1442 &member_sid,
1443 SID_NAME_DOM_GRP,
1444 &num_gr_mem,
1445 &gr_mem, &gr_mem_len);
1447 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1451 if (result) {
1452 /* Append to group membership list */
1453 gr_mem_list = (char *)SMB_REALLOC(
1454 gr_mem_list, gr_mem_list_len + gr_mem_len);
1456 if (!gr_mem_list &&
1457 (group_list[group_list_ndx].num_gr_mem != 0)) {
1458 DEBUG(0, ("out of memory\n"));
1459 gr_mem_list_len = 0;
1460 break;
1463 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1464 gr_mem_list_len, (unsigned int)gr_mem_len));
1466 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1467 gr_mem_len);
1469 SAFE_FREE(gr_mem);
1471 group_list[group_list_ndx].gr_mem_ofs =
1472 gr_mem_list_len;
1474 gr_mem_list_len += gr_mem_len;
1477 ent->sam_entry_index++;
1479 /* Add group to return list */
1481 if (result) {
1483 DEBUG(10, ("adding group num_entries = %d\n",
1484 state->response->data.num_entries));
1486 group_list_ndx++;
1487 state->response->data.num_entries++;
1489 state->response->length +=
1490 sizeof(struct winbindd_gr);
1492 } else {
1493 DEBUG(0, ("could not lookup domain group %s\n",
1494 domain_group_name));
1498 /* Copy the list of group memberships to the end of the extra data */
1500 if (group_list_ndx == 0)
1501 goto done;
1503 state->response->extra_data.data = talloc_realloc_size(
1504 state->mem_ctx, state->response->extra_data.data,
1505 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1507 if (!state->response->extra_data.data) {
1508 DEBUG(0, ("out of memory\n"));
1509 group_list_ndx = 0;
1510 SAFE_FREE(gr_mem_list);
1511 request_error(state);
1512 return;
1515 memcpy(&((char *)state->response->extra_data.data)
1516 [group_list_ndx * sizeof(struct winbindd_gr)],
1517 gr_mem_list, gr_mem_list_len);
1519 state->response->length += gr_mem_list_len;
1521 DEBUG(10, ("returning %d groups, length = %d\n",
1522 group_list_ndx, gr_mem_list_len));
1524 /* Out of domains */
1526 done:
1528 SAFE_FREE(gr_mem_list);
1530 if (group_list_ndx > 0)
1531 request_ok(state);
1532 else
1533 request_error(state);
1536 /* List domain groups without mapping to unix ids */
1537 void winbindd_list_groups(struct winbindd_cli_state *state)
1539 winbindd_list_ent(state, LIST_GROUPS);
1542 /* Get user supplementary groups. This is much quicker than trying to
1543 invert the groups database. We merge the groups from the gids and
1544 other_sids info3 fields as trusted domain, universal group
1545 memberships, and nested groups (win2k native mode only) are not
1546 returned by the getgroups RPC call but are present in the info3. */
1548 struct getgroups_state {
1549 struct winbindd_cli_state *state;
1550 struct winbindd_domain *domain;
1551 char *domname;
1552 char *username;
1553 DOM_SID user_sid;
1555 const DOM_SID *token_sids;
1556 size_t i, num_token_sids;
1558 gid_t *token_gids;
1559 size_t num_token_gids;
1562 static void getgroups_usersid_recv(void *private_data, bool success,
1563 const DOM_SID *sid, enum lsa_SidType type);
1564 static void getgroups_tokensids_recv(void *private_data, bool success,
1565 DOM_SID *token_sids, size_t num_token_sids);
1566 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1568 void winbindd_getgroups(struct winbindd_cli_state *state)
1570 struct getgroups_state *s;
1571 char *real_name = NULL;
1572 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1574 /* Ensure null termination */
1575 state->request->data.username
1576 [sizeof(state->request->data.username)-1]='\0';
1578 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1579 state->request->data.username));
1581 /* Parse domain and username */
1583 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1584 if (s == NULL) {
1585 DEBUG(0, ("talloc failed\n"));
1586 request_error(state);
1587 return;
1590 s->state = state;
1592 nt_status = normalize_name_unmap(state->mem_ctx,
1593 state->request->data.username,
1594 &real_name);
1596 /* Reset the real_name pointer if we didn't do anything
1597 productive in the above call */
1598 if (!NT_STATUS_IS_OK(nt_status) &&
1599 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
1601 real_name = state->request->data.username;
1604 if (!parse_domain_user_talloc(state->mem_ctx, real_name,
1605 &s->domname, &s->username)) {
1606 DEBUG(5, ("Could not parse domain user: %s\n",
1607 real_name));
1609 /* error out if we do not have nested group support */
1611 if ( !lp_winbind_nested_groups() ) {
1612 request_error(state);
1613 return;
1616 s->domname = talloc_strdup(state->mem_ctx,
1617 get_global_sam_name());
1618 s->username = talloc_strdup(state->mem_ctx,
1619 state->request->data.username);
1622 /* Get info for the domain (either by short domain name or
1623 DNS name in the case of a UPN) */
1625 s->domain = find_domain_from_name_noinit(s->domname);
1626 if (!s->domain) {
1627 char *p = strchr(s->username, '@');
1629 if (p) {
1630 s->domain = find_domain_from_name_noinit(p+1);
1635 if (s->domain == NULL) {
1636 DEBUG(7, ("could not find domain entry for domain %s\n",
1637 s->domname));
1638 request_error(state);
1639 return;
1642 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1643 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1644 "getgroups() for %s\\%s.\n", s->domname,
1645 s->username));
1646 request_error(state);
1647 return;
1650 /* Get rid and name type from name. The following costs 1 packet */
1652 winbindd_lookupname_async(state->mem_ctx,
1653 s->domname, s->username,
1654 getgroups_usersid_recv,
1655 WINBINDD_GETGROUPS, s);
1658 static void getgroups_usersid_recv(void *private_data, bool success,
1659 const DOM_SID *sid, enum lsa_SidType type)
1661 struct getgroups_state *s =
1662 (struct getgroups_state *)private_data;
1664 if ((!success) ||
1665 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1666 request_error(s->state);
1667 return;
1670 sid_copy(&s->user_sid, sid);
1672 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1673 getgroups_tokensids_recv, s);
1676 static void getgroups_tokensids_recv(void *private_data, bool success,
1677 DOM_SID *token_sids, size_t num_token_sids)
1679 struct getgroups_state *s =
1680 (struct getgroups_state *)private_data;
1682 /* We need at least the user sid and the primary group in the token,
1683 * otherwise it's an error */
1685 if ((!success) || (num_token_sids < 2)) {
1686 request_error(s->state);
1687 return;
1690 s->token_sids = token_sids;
1691 s->num_token_sids = num_token_sids;
1692 s->i = 0;
1694 s->token_gids = NULL;
1695 s->num_token_gids = 0;
1697 getgroups_sid2gid_recv(s, False, 0);
1700 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
1702 struct getgroups_state *s =
1703 (struct getgroups_state *)private_data;
1705 if (success) {
1706 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1707 &s->token_gids,
1708 &s->num_token_gids)) {
1709 return;
1713 if (s->i < s->num_token_sids) {
1714 const DOM_SID *sid = &s->token_sids[s->i];
1715 s->i += 1;
1717 if (sid_equal(sid, &s->user_sid)) {
1718 getgroups_sid2gid_recv(s, False, 0);
1719 return;
1722 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1723 getgroups_sid2gid_recv, s);
1724 return;
1727 s->state->response->data.num_entries = s->num_token_gids;
1728 if (s->num_token_gids) {
1729 s->state->response->extra_data.data = s->token_gids;
1730 s->state->response->length += s->num_token_gids * sizeof(gid_t);
1732 request_ok(s->state);
1735 /* Get user supplementary sids. This is equivalent to the
1736 winbindd_getgroups() function but it involves a SID->SIDs mapping
1737 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1738 idmap. This call is designed to be used with applications that need
1739 to do ACL evaluation themselves. Note that the cached info3 data is
1740 not used
1742 this function assumes that the SID that comes in is a user SID. If
1743 you pass in another type of SID then you may get unpredictable
1744 results.
1747 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1748 size_t num_sids);
1750 void winbindd_getusersids(struct winbindd_cli_state *state)
1752 DOM_SID *user_sid;
1754 /* Ensure null termination */
1755 state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
1757 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1758 if (user_sid == NULL) {
1759 DEBUG(1, ("talloc failed\n"));
1760 request_error(state);
1761 return;
1764 if (!string_to_sid(user_sid, state->request->data.sid)) {
1765 DEBUG(1, ("Could not get convert sid %s from string\n",
1766 state->request->data.sid));
1767 request_error(state);
1768 return;
1771 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1772 state);
1775 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1776 size_t num_sids)
1778 struct winbindd_cli_state *state =
1779 (struct winbindd_cli_state *)private_data;
1780 char *ret = NULL;
1781 unsigned ofs, ret_size = 0;
1782 size_t i;
1784 if (!success) {
1785 request_error(state);
1786 return;
1789 /* work out the response size */
1790 for (i = 0; i < num_sids; i++) {
1791 fstring s;
1792 sid_to_fstring(s, &sids[i]);
1793 ret_size += strlen(s) + 1;
1796 /* build the reply */
1797 ret = talloc_array(state->mem_ctx, char, ret_size);
1798 if (!ret) {
1799 DEBUG(0, ("malloc failed\n"));
1800 request_error(state);
1801 return;
1803 ofs = 0;
1804 for (i = 0; i < num_sids; i++) {
1805 fstring s;
1806 sid_to_fstring(s, &sids[i]);
1807 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1808 ofs += strlen(ret+ofs) + 1;
1811 /* Send data back to client */
1812 state->response->data.num_entries = num_sids;
1813 state->response->extra_data.data = ret;
1814 state->response->length += ret_size;
1815 request_ok(state);
1818 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1820 DOM_SID user_sid;
1821 struct winbindd_domain *domain;
1823 /* Ensure null termination */
1824 state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
1826 if (!string_to_sid(&user_sid, state->request->data.sid)) {
1827 DEBUG(1, ("Could not get convert sid %s from string\n",
1828 state->request->data.sid));
1829 request_error(state);
1830 return;
1833 /* Get info for the domain */
1834 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1835 DEBUG(0,("could not find domain entry for sid %s\n",
1836 sid_string_dbg(&user_sid)));
1837 request_error(state);
1838 return;
1841 sendto_domain(state, domain);
1844 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1845 struct winbindd_cli_state *state)
1847 DOM_SID user_sid;
1848 NTSTATUS status;
1850 char *sidstring;
1851 ssize_t len;
1852 DOM_SID *groups;
1853 uint32 num_groups;
1855 /* Ensure null termination */
1856 state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
1858 if (!string_to_sid(&user_sid, state->request->data.sid)) {
1859 DEBUG(1, ("Could not get convert sid %s from string\n",
1860 state->request->data.sid));
1861 return WINBINDD_ERROR;
1864 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1865 &user_sid, &num_groups,
1866 &groups);
1867 if (!NT_STATUS_IS_OK(status))
1868 return WINBINDD_ERROR;
1870 if (num_groups == 0) {
1871 state->response->data.num_entries = 0;
1872 state->response->extra_data.data = NULL;
1873 return WINBINDD_OK;
1876 if (!print_sidlist(state->mem_ctx,
1877 groups, num_groups,
1878 &sidstring, &len)) {
1879 DEBUG(0, ("talloc failed\n"));
1880 return WINBINDD_ERROR;
1883 state->response->extra_data.data = sidstring;
1884 state->response->length += len+1;
1885 state->response->data.num_entries = num_groups;
1887 return WINBINDD_OK;
1890 void winbindd_getsidaliases(struct winbindd_cli_state *state)
1892 DOM_SID domain_sid;
1893 struct winbindd_domain *domain;
1895 /* Ensure null termination */
1896 state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
1898 if (!string_to_sid(&domain_sid, state->request->data.sid)) {
1899 DEBUG(1, ("Could not get convert sid %s from string\n",
1900 state->request->data.sid));
1901 request_error(state);
1902 return;
1905 /* Get info for the domain */
1906 if ((domain = find_domain_from_sid_noinit(&domain_sid)) == NULL) {
1907 DEBUG(0,("could not find domain entry for sid %s\n",
1908 sid_string_dbg(&domain_sid)));
1909 request_error(state);
1910 return;
1913 sendto_domain(state, domain);
1916 enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
1917 struct winbindd_cli_state *state)
1919 DOM_SID *sids = NULL;
1920 size_t num_sids = 0;
1921 char *sidstr = NULL;
1922 ssize_t len;
1923 size_t i;
1924 uint32 num_aliases;
1925 uint32 *alias_rids;
1926 NTSTATUS result;
1928 DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
1930 sidstr = state->request->extra_data.data;
1931 if (sidstr == NULL) {
1932 sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
1933 if (!sidstr) {
1934 DEBUG(0, ("Out of memory\n"));
1935 return WINBINDD_ERROR;
1939 DEBUG(10, ("Sidlist: %s\n", sidstr));
1941 if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
1942 DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
1943 return WINBINDD_ERROR;
1946 num_aliases = 0;
1947 alias_rids = NULL;
1949 result = domain->methods->lookup_useraliases(domain,
1950 state->mem_ctx,
1951 num_sids, sids,
1952 &num_aliases,
1953 &alias_rids);
1955 if (!NT_STATUS_IS_OK(result)) {
1956 DEBUG(3, ("Could not lookup_useraliases: %s\n",
1957 nt_errstr(result)));
1958 return WINBINDD_ERROR;
1961 num_sids = 0;
1962 sids = NULL;
1963 sidstr = NULL;
1965 DEBUG(10, ("Got %d aliases\n", num_aliases));
1967 for (i=0; i<num_aliases; i++) {
1968 DOM_SID sid;
1969 DEBUGADD(10, (" rid %d\n", alias_rids[i]));
1970 sid_copy(&sid, &domain->sid);
1971 sid_append_rid(&sid, alias_rids[i]);
1972 result = add_sid_to_array(state->mem_ctx, &sid, &sids,
1973 &num_sids);
1974 if (!NT_STATUS_IS_OK(result)) {
1975 return WINBINDD_ERROR;
1980 if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
1981 DEBUG(0, ("Could not print_sidlist\n"));
1982 state->response->extra_data.data = NULL;
1983 return WINBINDD_ERROR;
1986 state->response->extra_data.data = NULL;
1988 if (sidstr) {
1989 state->response->extra_data.data = sidstr;
1990 DEBUG(10, ("aliases_list: %s\n",
1991 (char *)state->response->extra_data.data));
1992 state->response->length += len+1;
1993 state->response->data.num_entries = num_sids;
1996 return WINBINDD_OK;