2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
8 Copyright (C) Gerald (Jerry) Carter 2003.
9 Copyright (C) Volker Lendecke 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 extern bool opt_nocache;
31 #define DBGC_CLASS DBGC_WINBIND
33 static void add_member(const char *domain, const char *user,
34 char **pp_members, size_t *p_num_members)
38 fill_domain_username(name, domain, user, True);
39 safe_strcat(name, ",", sizeof(name)-1);
40 string_append(pp_members, name);
44 /**********************************************************************
45 Add member users resulting from sid. Expand if it is a domain group.
46 **********************************************************************/
48 static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
52 struct winbindd_domain *domain;
55 char *domain_name = NULL;
57 enum lsa_SidType type;
66 TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
68 if (mem_ctx == NULL) {
69 DEBUG(1, ("talloc_init failed\n"));
73 sid_copy(&dom_sid, sid);
74 sid_split_rid(&dom_sid, &rid);
76 domain = find_lookup_domain_from_sid(sid);
79 DEBUG(3, ("Could not find domain for sid %s\n",
80 sid_string_dbg(sid)));
84 result = domain->methods->sid_to_name(domain, mem_ctx, sid,
85 &domain_name, &name, &type);
87 if (!NT_STATUS_IS_OK(result)) {
88 DEBUG(3, ("sid_to_name failed for sid %s\n",
89 sid_string_dbg(sid)));
93 DEBUG(10, ("Found name %s, type %d\n", name, type));
95 if (type == SID_NAME_USER) {
96 add_member(domain_name, name, pp_members, p_num_members);
100 if (type != SID_NAME_DOM_GRP) {
101 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
106 /* Expand the domain group, this must be done via the target domain */
108 domain = find_domain_from_sid(sid);
110 if (domain == NULL) {
111 DEBUG(3, ("Could not find domain from SID %s\n",
112 sid_string_dbg(sid)));
116 result = domain->methods->lookup_groupmem(domain, mem_ctx,
121 if (!NT_STATUS_IS_OK(result)) {
122 DEBUG(10, ("Could not lookup group members for %s: %s\n",
123 name, nt_errstr(result)));
127 for (i=0; i<num_names; i++) {
128 DEBUG(10, ("Adding group member SID %s\n",
129 sid_string_dbg(&sid_mem[i])));
131 if (types[i] != SID_NAME_USER) {
132 DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
133 "Ignoring.\n", names[i], name));
137 add_member(domain->name, names[i], pp_members, p_num_members);
141 talloc_destroy(mem_ctx);
145 static bool fill_passdb_alias_grmem(struct winbindd_domain *domain,
147 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
150 size_t i, num_members;
156 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
160 for (i=0; i<num_members; i++) {
161 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
164 TALLOC_FREE(members);
166 if (*gr_mem != NULL) {
169 /* We have at least one member, strip off the last "," */
170 len = strlen(*gr_mem);
171 (*gr_mem)[len-1] = '\0';
178 /* Fill a grent structure from various other information */
180 static bool fill_grent(struct winbindd_gr *gr, const char *dom_name,
181 const char *gr_name, gid_t unix_gid)
183 fstring full_group_name;
185 fill_domain_username( full_group_name, dom_name, gr_name, True );
187 gr->gr_gid = unix_gid;
189 /* Group name and password */
191 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
192 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
197 /***********************************************************************
198 If "enum users" is set to false, and the group being looked
199 up is the Domain Users SID: S-1-5-domain-513, then for the
200 list of members check if the querying user is in that group,
201 and if so only return that user as the gr_mem array.
202 We can change this to a different parameter than "enum users"
203 if neccessaey, or parameterize the group list we do this for.
204 ***********************************************************************/
206 static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
207 struct winbindd_domain *domain,
208 struct winbindd_cli_state *state,
210 enum lsa_SidType group_name_type,
211 size_t *num_gr_mem, char **gr_mem,
214 DOM_SID querying_user_sid;
215 DOM_SID *pquerying_user_sid = NULL;
216 uint32 num_groups = 0;
217 DOM_SID *user_sids = NULL;
218 bool u_in_group = False;
221 unsigned int buf_len = 0;
224 DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
228 uid_t ret_uid = (uid_t)-1;
229 if (sys_getpeereid(state->sock, &ret_uid)==0) {
230 /* We know who's asking - look up their SID if
231 it's one we've mapped before. */
232 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
233 if (NT_STATUS_IS_OK(status)) {
234 pquerying_user_sid = &querying_user_sid;
235 DEBUG(10,("fill_grent_mem_domain_users: querying uid %u -> %s\n",
236 (unsigned int)ret_uid,
237 sid_string_dbg(pquerying_user_sid)));
242 /* Only look up if it was a winbindd user in this domain. */
243 if (pquerying_user_sid &&
244 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
246 DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
247 sid_string_dbg(pquerying_user_sid) ));
249 status = domain->methods->lookup_usergroups(domain,
254 if (!NT_STATUS_IS_OK(status)) {
255 DEBUG(1, ("fill_grent_mem_domain_users: lookup_usergroups failed "
256 "for sid %s in domain %s (error: %s)\n",
257 sid_string_dbg(pquerying_user_sid),
263 for (i = 0; i < num_groups; i++) {
264 if (sid_equal(group_sid, &user_sids[i])) {
265 /* User is in Domain Users, add their name
266 as the only group member. */
275 char *domainname = NULL;
276 char *username = NULL;
278 enum lsa_SidType type;
280 DEBUG(10,("fill_grent_mem_domain_users: sid %s in 'Domain Users' in domain %s\n",
281 sid_string_dbg(pquerying_user_sid),
284 status = domain->methods->sid_to_name(domain, mem_ctx,
289 if (!NT_STATUS_IS_OK(status)) {
290 DEBUG(1, ("could not lookup username for user "
291 "sid %s in domain %s (error: %s)\n",
292 sid_string_dbg(pquerying_user_sid),
297 fill_domain_username(name, domain->name, username, True);
300 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
301 DEBUG(1, ("out of memory\n"));
304 memcpy(buf, name, buf_len);
306 DEBUG(10,("fill_grent_mem_domain_users: user %s in "
307 "'Domain Users' in domain %s\n",
308 name, domain->name ));
310 /* user is the only member */
315 *gr_mem_len = buf_len;
317 DEBUG(10, ("fill_grent_mem_domain_users: num_mem = %u, len = %u, mem = %s\n",
318 (unsigned int)*num_gr_mem,
319 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
324 /***********************************************************************
325 Add names to a list. Assumes a canonical version of the string
327 ***********************************************************************/
329 static int namecmp( const void *a, const void *b )
331 return StrCaseCmp( * (char * const *) a, * (char * const *) b);
334 static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
335 char ***list, uint32 *n_list,
336 char **names, uint32 n_names )
338 char **new_list = NULL;
339 uint32 n_new_list = 0;
342 if ( !names || (n_names == 0) )
345 /* Alloc the maximum size we'll need */
347 if ( *list == NULL ) {
348 if ( (new_list = TALLOC_ARRAY( ctx, char *, n_names )) == NULL )
349 return NT_STATUS_NO_MEMORY;
350 n_new_list = n_names;
352 new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
353 (*n_list) + n_names );
355 return NT_STATUS_NO_MEMORY;
356 n_new_list = (*n_list) + n_names;
361 for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
362 new_list[i] = talloc_strdup( new_list, names[j] );
365 /* search for duplicates for sorting and looking for matching
368 qsort( new_list, n_new_list, sizeof(char*), QSORT_CAST namecmp );
370 for ( i=1; i<n_new_list; i++ ) {
371 if ( strcmp( new_list[i-1], new_list[i] ) == 0 ) {
372 memmove( &new_list[i-1], &new_list[i],
373 sizeof(char*)*(n_new_list-i) );
379 *n_list = n_new_list;
384 /***********************************************************************
385 ***********************************************************************/
387 static NTSTATUS expand_groups( TALLOC_CTX *ctx,
388 struct winbindd_domain *d,
389 DOM_SID *glist, uint32 n_glist,
390 DOM_SID **new_glist, uint32 *n_new_glist,
391 char ***members, uint32 *n_members )
394 NTSTATUS status = NT_STATUS_OK;
395 uint32 num_names = 0;
396 uint32 *name_types = NULL;
398 DOM_SID *sid_mem = NULL;
399 TALLOC_CTX *tmp_ctx = NULL;
400 DOM_SID *new_groups = NULL;
401 size_t new_groups_size = 0;
408 for ( i=0; i<n_glist; i++ ) {
409 tmp_ctx = talloc_new( ctx );
411 /* Lookup the group membership */
413 status = d->methods->lookup_groupmem(d, tmp_ctx,
414 &glist[i], &num_names,
417 if ( !NT_STATUS_IS_OK(status) )
420 /* Separate users and groups into two lists */
422 for ( j=0; j<num_names; j++ ) {
425 if ( name_types[j] == SID_NAME_USER ||
426 name_types[j] == SID_NAME_COMPUTER )
428 status = add_names_to_list( ctx, members,
431 if ( !NT_STATUS_IS_OK(status) )
438 if ( name_types[j] == SID_NAME_DOM_GRP ||
439 name_types[j] == SID_NAME_ALIAS )
443 ret = add_sid_to_array_unique( ctx,
448 status = NT_STATUS_NO_MEMORY;
456 TALLOC_FREE( tmp_ctx );
459 *new_glist = new_groups;
460 *n_new_glist = (uint32)new_groups_size;
463 TALLOC_FREE( tmp_ctx );
468 /***********************************************************************
469 Fill in the group membership field of a NT group given by group_sid
470 ***********************************************************************/
472 static bool fill_grent_mem(struct winbindd_domain *domain,
473 struct winbindd_cli_state *state,
475 enum lsa_SidType group_name_type,
476 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
478 uint32 num_names = 0;
479 unsigned int buf_len = 0, buf_ndx = 0, i;
480 char **names = NULL, *buf = NULL;
484 DOM_SID *glist = NULL;
485 DOM_SID *new_glist = NULL;
486 uint32 n_glist, n_new_glist;
487 int max_depth = lp_winbind_expand_groups();
489 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
492 DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
494 /* Initialize with no members */
498 /* HACK ALERT!! This whole routine does not cope with group members
499 * from more than one domain, ie aliases. Thus we have to work it out
500 * ourselves in a special routine. */
502 if (domain->internal) {
503 result = fill_passdb_alias_grmem(domain, group_sid,
509 /* Verify name type */
511 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
512 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
514 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
515 sid_string_dbg(group_sid),
516 domain->name, group_name_type));
520 /* OPTIMIZATION / HACK. See comment in
521 fill_grent_mem_domusers() */
523 sid_peek_rid( group_sid, &group_rid );
524 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
525 result = fill_grent_mem_domusers( mem_ctx, domain, state,
526 group_sid, group_name_type,
532 /* Real work goes here. Create a list of group names to
533 expand startign with the initial one. Pass that to
534 expand_groups() which returns a list of more group names
535 to expand. Do this up to the max search depth. */
537 if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
539 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
542 sid_copy( &glist[0], group_sid );
545 for ( i=0; i<max_depth && glist; i++ ) {
546 uint32 n_members = 0;
547 char **members = NULL;
550 nt_status = expand_groups( mem_ctx, domain,
552 &new_glist, &n_new_glist,
553 &members, &n_members);
554 if ( !NT_STATUS_IS_OK(nt_status) ) {
559 /* Add new group members to list */
561 nt_status = add_names_to_list( mem_ctx, &names, &num_names,
562 members, n_members );
563 if ( !NT_STATUS_IS_OK(nt_status) ) {
568 TALLOC_FREE( members );
570 /* If we have no more groups to expand, break out
579 n_glist = n_new_glist;
581 TALLOC_FREE( glist );
583 DEBUG(10, ("looked up %d names\n", num_names));
586 /* Add members to list */
588 for (i = 0; i < num_names; i++) {
591 DEBUG(10, ("processing name %s\n", names[i]));
593 len = strlen(names[i]);
595 /* Add to list or calculate buffer length */
598 buf_len += len + 1; /* List is comma separated */
600 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
602 DEBUG(10, ("appending %s at ndx %d\n", names[i], buf_ndx));
603 safe_strcpy(&buf[buf_ndx], names[i], len);
610 /* Allocate buffer */
612 if (!buf && buf_len != 0) {
613 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
614 DEBUG(1, ("out of memory\n"));
618 memset(buf, 0, buf_len);
624 if (buf && buf_ndx > 0) {
625 buf[buf_ndx - 1] = '\0';
629 *gr_mem_len = buf_len;
631 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
632 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
637 talloc_destroy(mem_ctx);
639 DEBUG(10, ("fill_grent_mem returning %d\n", result));
644 static void winbindd_getgrsid( struct winbindd_cli_state *state, DOM_SID group_sid );
646 static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
647 enum lsa_SidType type )
649 struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
652 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
653 request_error(state);
657 if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
658 DEBUG(5,("getgrnam_recv: not a group!\n"));
659 request_error(state);
663 winbindd_getgrsid( state, *sid );
667 /* Return a group structure from a group name */
669 void winbindd_getgrnam(struct winbindd_cli_state *state)
671 struct winbindd_domain *domain;
672 fstring name_domain, name_group;
675 /* Ensure null termination */
676 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
678 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
679 state->request.data.groupname));
681 /* Parse domain and groupname */
683 memset(name_group, 0, sizeof(fstring));
685 tmp = state->request.data.groupname;
687 name_domain[0] = '\0';
688 name_group[0] = '\0';
690 parse_domain_user(tmp, name_domain, name_group);
692 /* if no domain or our local domain and no local tdb group, default to
693 * our local domain for aliases */
695 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
696 fstrcpy(name_domain, get_global_sam_name());
699 /* Get info for the domain */
701 if ((domain = find_domain_from_name(name_domain)) == NULL) {
702 DEBUG(3, ("could not get domain sid for domain %s\n",
704 request_error(state);
707 /* should we deal with users for our domain? */
709 if ( lp_winbind_trusted_domains_only() && domain->primary) {
710 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
711 "getgrnam() for %s\\%s.\n", name_domain, name_group));
712 request_error(state);
716 /* Get rid and name type from name */
718 ws_name_replace( name_group, WB_REPLACE_CHAR );
720 winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
721 getgrnam_recv, WINBINDD_GETGRNAM, state );
724 struct getgrsid_state {
725 struct winbindd_cli_state *state;
726 struct winbindd_domain *domain;
728 enum lsa_SidType group_type;
733 static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
735 struct getgrsid_state *s =
736 (struct getgrsid_state *)private_data;
737 struct winbindd_domain *domain;
741 fstring dom_name, group_name;
744 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
745 request_error(s->state);
751 if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
752 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
753 request_error(s->state);
758 /* Fill in group structure */
760 if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
761 DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
762 request_error(s->state);
766 if (!fill_grent(&s->state->response.data.gr, dom_name, group_name, gid) ||
767 !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
768 &num_gr_mem, &gr_mem, &gr_mem_len))
770 request_error(s->state);
774 s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
776 /* Group membership lives at start of extra data */
778 s->state->response.data.gr.gr_mem_ofs = 0;
780 s->state->response.length += gr_mem_len;
781 s->state->response.extra_data.data = gr_mem;
783 request_ok(s->state);
786 static void getgrsid_lookupsid_recv( void *private_data, bool success,
787 const char *dom_name, const char *name,
788 enum lsa_SidType name_type )
790 struct getgrsid_state *s = (struct getgrsid_state *)private_data;
793 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
794 request_error(s->state);
798 /* either it's a domain group, a domain local group, or a
799 local group in an internal domain */
801 if ( !( (name_type==SID_NAME_DOM_GRP) ||
802 ((name_type==SID_NAME_ALIAS) &&
803 (s->domain->primary || s->domain->internal)) ) )
805 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
806 dom_name, name, name_type));
807 request_error(s->state);
811 if ( (s->group_name = talloc_asprintf( s->state->mem_ctx,
813 dom_name, name )) == NULL )
815 DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n"));
816 request_error(s->state);
820 s->group_type = name_type;
822 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
823 getgrsid_sid2gid_recv, s);
826 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
828 struct getgrsid_state *s;
830 if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
831 DEBUG(0, ("talloc failed\n"));
832 request_error(state);
838 if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
839 DEBUG(3, ("Could not find domain for sid %s\n",
840 sid_string_dbg(&group_sid)));
841 request_error(state);
845 sid_copy(&s->group_sid, &group_sid);
847 winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
848 getgrsid_lookupsid_recv, s );
852 static void getgrgid_recv(void *private_data, bool success, const char *sid)
854 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
855 enum lsa_SidType name_type;
859 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
860 (unsigned long)(state->request.data.gid), sid));
862 string_to_sid(&group_sid, sid);
863 winbindd_getgrsid(state, group_sid);
867 /* Ok, this might be "ours", i.e. an alias */
868 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
869 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
870 (name_type == SID_NAME_ALIAS)) {
871 /* Hey, got an alias */
872 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
873 (unsigned long)(state->request.data.gid), sid));
874 winbindd_getgrsid(state, group_sid);
878 DEBUG(1, ("could not convert gid %lu to sid\n",
879 (unsigned long)state->request.data.gid));
880 request_error(state);
883 /* Return a group structure from a gid number */
884 void winbindd_getgrgid(struct winbindd_cli_state *state)
886 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
887 (unsigned long)state->request.data.gid));
889 /* always use the async interface */
890 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
894 * set/get/endgrent functions
897 /* "Rewind" file pointer for group database enumeration */
899 static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
901 struct winbindd_domain *domain;
903 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
905 /* Check user has enabled this */
907 if (!lp_winbind_enum_groups()) {
911 /* Free old static data if it exists */
913 if (state->getgrent_state != NULL) {
914 free_getent_state(state->getgrent_state);
915 state->getgrent_state = NULL;
918 /* Create sam pipes for each domain we know about */
920 for (domain = domain_list(); domain != NULL; domain = domain->next) {
921 struct getent_state *domain_state;
923 /* Create a state record for this domain */
925 /* don't add our domaina if we are a PDC or if we
926 are a member of a Samba domain */
928 if ( lp_winbind_trusted_domains_only() && domain->primary )
934 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
935 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
939 ZERO_STRUCTP(domain_state);
941 fstrcpy(domain_state->domain_name, domain->name);
943 /* Add to list of open domains */
945 DLIST_ADD(state->getgrent_state, domain_state);
948 state->getgrent_initialized = True;
952 void winbindd_setgrent(struct winbindd_cli_state *state)
954 if (winbindd_setgrent_internal(state)) {
957 request_error(state);
961 /* Close file pointer to ntdom group database */
963 void winbindd_endgrent(struct winbindd_cli_state *state)
965 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
967 free_getent_state(state->getgrent_state);
968 state->getgrent_initialized = False;
969 state->getgrent_state = NULL;
973 /* Get the list of domain groups and domain aliases for a domain. We fill in
974 the sam_entries and num_sam_entries fields with domain group information.
975 The dispinfo_ndx field is incremented to the index of the next group to
976 fetch. Return True if some groups were returned, False otherwise. */
978 static bool get_sam_group_entries(struct getent_state *ent)
982 struct acct_info *name_list = NULL;
985 struct acct_info *sam_grp_entries = NULL;
986 struct winbindd_domain *domain;
988 if (ent->got_sam_entries)
991 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
992 ent->domain_name))) {
993 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
997 /* Free any existing group info */
999 SAFE_FREE(ent->sam_entries);
1000 ent->num_sam_entries = 0;
1001 ent->got_sam_entries = True;
1003 /* Enumerate domain groups */
1007 if (!(domain = find_domain_from_name(ent->domain_name))) {
1008 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
1012 /* always get the domain global groups */
1014 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
1022 /* Copy entries into return buffer */
1025 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
1026 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
1031 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
1034 ent->num_sam_entries = num_entries;
1036 /* get the domain local groups if we are a member of a native win2k domain
1037 and are not using LDAP to get the groups */
1039 if ( ( lp_security() != SEC_ADS && domain->native_mode
1040 && domain->primary) || domain->internal )
1042 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
1043 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
1045 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
1047 if ( !NT_STATUS_IS_OK(status) ) {
1048 DEBUG(3,("get_sam_group_entries: "
1049 "Failed to enumerate "
1050 "domain local groups with error %s!\n",
1051 nt_errstr(status)));
1055 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
1057 /* Copy entries into return buffer */
1059 if ( num_entries ) {
1060 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
1062 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
1068 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
1069 num_entries * sizeof(struct acct_info) );
1072 ent->num_sam_entries += num_entries;
1076 /* Fill in remaining fields */
1078 ent->sam_entries = name_list;
1079 ent->sam_entry_index = 0;
1081 result = (ent->num_sam_entries > 0);
1084 talloc_destroy(mem_ctx);
1089 /* Fetch next group entry from ntdom database */
1091 #define MAX_GETGRENT_GROUPS 500
1093 void winbindd_getgrent(struct winbindd_cli_state *state)
1095 struct getent_state *ent;
1096 struct winbindd_gr *group_list = NULL;
1097 int num_groups, group_list_ndx, gr_mem_list_len = 0;
1098 char *gr_mem_list = NULL;
1100 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1102 /* Check user has enabled this */
1104 if (!lp_winbind_enum_groups()) {
1105 request_error(state);
1109 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
1111 if (num_groups == 0) {
1112 request_error(state);
1116 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
1117 request_error(state);
1121 memset(state->response.extra_data.data, '\0',
1122 num_groups * sizeof(struct winbindd_gr) );
1124 state->response.data.num_entries = 0;
1126 group_list = (struct winbindd_gr *)state->response.extra_data.data;
1128 if (!state->getgrent_initialized)
1129 winbindd_setgrent_internal(state);
1131 if (!(ent = state->getgrent_state)) {
1132 request_error(state);
1136 /* Start sending back groups */
1138 for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
1139 struct acct_info *name_list = NULL;
1140 fstring domain_group_name;
1146 struct winbindd_domain *domain;
1148 /* Do we need to fetch another chunk of groups? */
1152 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1153 ent->sam_entry_index, ent->num_sam_entries));
1155 if (ent->num_sam_entries == ent->sam_entry_index) {
1157 while(ent && !get_sam_group_entries(ent)) {
1158 struct getent_state *next_ent;
1160 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
1162 /* Free state information for this domain */
1164 SAFE_FREE(ent->sam_entries);
1166 next_ent = ent->next;
1167 DLIST_REMOVE(state->getgrent_state, ent);
1173 /* No more domains */
1179 name_list = (struct acct_info *)ent->sam_entries;
1182 find_domain_from_name(ent->domain_name))) {
1183 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
1188 /* Lookup group info */
1190 sid_copy(&group_sid, &domain->sid);
1191 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1193 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
1195 enum lsa_SidType type;
1197 DEBUG(10, ("SID %s not in idmap\n",
1198 sid_string_dbg(&group_sid)));
1200 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1201 DEBUG(1, ("could not look up gid for group "
1203 name_list[ent->sam_entry_index].acct_name));
1204 ent->sam_entry_index++;
1208 if ((type != SID_NAME_DOM_GRP) &&
1209 (type != SID_NAME_ALIAS) &&
1210 (type != SID_NAME_WKN_GRP)) {
1211 DEBUG(1, ("Group %s is a %s, not a group\n",
1212 sid_type_lookup(type),
1213 name_list[ent->sam_entry_index].acct_name));
1214 ent->sam_entry_index++;
1220 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1221 (unsigned long)name_list[ent->sam_entry_index].rid));
1223 /* Fill in group entry */
1225 fill_domain_username(domain_group_name, ent->domain_name,
1226 name_list[ent->sam_entry_index].acct_name, True);
1228 result = fill_grent(&group_list[group_list_ndx],
1230 name_list[ent->sam_entry_index].acct_name,
1233 /* Fill in group membership entry */
1236 size_t num_gr_mem = 0;
1238 group_list[group_list_ndx].num_gr_mem = 0;
1242 /* Get group membership */
1243 if (state->request.cmd == WINBINDD_GETGRLST) {
1246 sid_copy(&member_sid, &domain->sid);
1247 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1248 result = fill_grent_mem(
1254 &gr_mem, &gr_mem_len);
1256 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1261 /* Append to group membership list */
1262 gr_mem_list = (char *)SMB_REALLOC(
1263 gr_mem_list, gr_mem_list_len + gr_mem_len);
1265 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
1266 DEBUG(0, ("out of memory\n"));
1267 gr_mem_list_len = 0;
1271 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1272 gr_mem_list_len, (unsigned int)gr_mem_len));
1274 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1279 group_list[group_list_ndx].gr_mem_ofs =
1282 gr_mem_list_len += gr_mem_len;
1285 ent->sam_entry_index++;
1287 /* Add group to return list */
1291 DEBUG(10, ("adding group num_entries = %d\n",
1292 state->response.data.num_entries));
1295 state->response.data.num_entries++;
1297 state->response.length +=
1298 sizeof(struct winbindd_gr);
1301 DEBUG(0, ("could not lookup domain group %s\n",
1302 domain_group_name));
1306 /* Copy the list of group memberships to the end of the extra data */
1308 if (group_list_ndx == 0)
1311 state->response.extra_data.data = SMB_REALLOC(
1312 state->response.extra_data.data,
1313 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1315 if (!state->response.extra_data.data) {
1316 DEBUG(0, ("out of memory\n"));
1318 SAFE_FREE(gr_mem_list);
1319 request_error(state);
1323 memcpy(&((char *)state->response.extra_data.data)
1324 [group_list_ndx * sizeof(struct winbindd_gr)],
1325 gr_mem_list, gr_mem_list_len);
1327 state->response.length += gr_mem_list_len;
1329 DEBUG(10, ("returning %d groups, length = %d\n",
1330 group_list_ndx, gr_mem_list_len));
1332 /* Out of domains */
1336 SAFE_FREE(gr_mem_list);
1338 if (group_list_ndx > 0)
1341 request_error(state);
1344 /* List domain groups without mapping to unix ids */
1346 void winbindd_list_groups(struct winbindd_cli_state *state)
1348 uint32 total_entries = 0;
1349 struct winbindd_domain *domain;
1350 const char *which_domain;
1351 char *extra_data = NULL;
1352 unsigned int extra_data_len = 0, i;
1354 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1356 /* Ensure null termination */
1357 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1358 which_domain = state->request.domain_name;
1360 /* Enumerate over trusted domains */
1362 for (domain = domain_list(); domain; domain = domain->next) {
1363 struct getent_state groups;
1365 /* if we have a domain name restricting the request and this
1366 one in the list doesn't match, then just bypass the remainder
1369 if ( *which_domain && !strequal(which_domain, domain->name) )
1372 ZERO_STRUCT(groups);
1374 /* Get list of sam groups */
1376 fstrcpy(groups.domain_name, domain->name);
1378 get_sam_group_entries(&groups);
1380 if (groups.num_sam_entries == 0) {
1381 /* this domain is empty or in an error state */
1385 /* keep track the of the total number of groups seen so
1386 far over all domains */
1387 total_entries += groups.num_sam_entries;
1389 /* Allocate some memory for extra data. Note that we limit
1390 account names to sizeof(fstring) = 128 characters. */
1391 extra_data = (char *)SMB_REALLOC(
1392 extra_data, sizeof(fstring) * total_entries);
1395 DEBUG(0,("failed to enlarge buffer!\n"));
1396 request_error(state);
1400 /* Pack group list into extra data fields */
1401 for (i = 0; i < groups.num_sam_entries; i++) {
1402 char *group_name = ((struct acct_info *)
1403 groups.sam_entries)[i].acct_name;
1406 fill_domain_username(name, domain->name, group_name, True);
1407 /* Append to extra data */
1408 memcpy(&extra_data[extra_data_len], name,
1410 extra_data_len += strlen(name);
1411 extra_data[extra_data_len++] = ',';
1414 SAFE_FREE(groups.sam_entries);
1417 /* Assign extra_data fields in response structure */
1419 extra_data[extra_data_len - 1] = '\0';
1420 state->response.extra_data.data = extra_data;
1421 state->response.length += extra_data_len;
1424 /* No domains may have responded but that's still OK so don't
1430 /* Get user supplementary groups. This is much quicker than trying to
1431 invert the groups database. We merge the groups from the gids and
1432 other_sids info3 fields as trusted domain, universal group
1433 memberships, and nested groups (win2k native mode only) are not
1434 returned by the getgroups RPC call but are present in the info3. */
1436 struct getgroups_state {
1437 struct winbindd_cli_state *state;
1438 struct winbindd_domain *domain;
1443 const DOM_SID *token_sids;
1444 size_t i, num_token_sids;
1447 size_t num_token_gids;
1450 static void getgroups_usersid_recv(void *private_data, bool success,
1451 const DOM_SID *sid, enum lsa_SidType type);
1452 static void getgroups_tokensids_recv(void *private_data, bool success,
1453 DOM_SID *token_sids, size_t num_token_sids);
1454 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1456 void winbindd_getgroups(struct winbindd_cli_state *state)
1458 struct getgroups_state *s;
1460 /* Ensure null termination */
1461 state->request.data.username
1462 [sizeof(state->request.data.username)-1]='\0';
1464 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1465 state->request.data.username));
1467 /* Parse domain and username */
1469 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1471 DEBUG(0, ("talloc failed\n"));
1472 request_error(state);
1478 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
1480 if (!parse_domain_user_talloc(state->mem_ctx,
1481 state->request.data.username,
1482 &s->domname, &s->username)) {
1483 DEBUG(5, ("Could not parse domain user: %s\n",
1484 state->request.data.username));
1486 /* error out if we do not have nested group support */
1488 if ( !lp_winbind_nested_groups() ) {
1489 request_error(state);
1493 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1494 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1497 /* Get info for the domain */
1499 s->domain = find_domain_from_name_noinit(s->domname);
1501 if (s->domain == NULL) {
1502 DEBUG(7, ("could not find domain entry for domain %s\n",
1504 request_error(state);
1508 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1509 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1510 "getgroups() for %s\\%s.\n", s->domname,
1512 request_error(state);
1516 /* Get rid and name type from name. The following costs 1 packet */
1518 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1519 getgroups_usersid_recv, WINBINDD_GETGROUPS, s);
1522 static void getgroups_usersid_recv(void *private_data, bool success,
1523 const DOM_SID *sid, enum lsa_SidType type)
1525 struct getgroups_state *s =
1526 (struct getgroups_state *)private_data;
1529 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1530 request_error(s->state);
1534 sid_copy(&s->user_sid, sid);
1536 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1537 getgroups_tokensids_recv, s);
1540 static void getgroups_tokensids_recv(void *private_data, bool success,
1541 DOM_SID *token_sids, size_t num_token_sids)
1543 struct getgroups_state *s =
1544 (struct getgroups_state *)private_data;
1546 /* We need at least the user sid and the primary group in the token,
1547 * otherwise it's an error */
1549 if ((!success) || (num_token_sids < 2)) {
1550 request_error(s->state);
1554 s->token_sids = token_sids;
1555 s->num_token_sids = num_token_sids;
1558 s->token_gids = NULL;
1559 s->num_token_gids = 0;
1561 getgroups_sid2gid_recv(s, False, 0);
1564 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
1566 struct getgroups_state *s =
1567 (struct getgroups_state *)private_data;
1570 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1572 &s->num_token_gids)) {
1577 if (s->i < s->num_token_sids) {
1578 const DOM_SID *sid = &s->token_sids[s->i];
1581 if (sid_equal(sid, &s->user_sid)) {
1582 getgroups_sid2gid_recv(s, False, 0);
1586 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1587 getgroups_sid2gid_recv, s);
1591 s->state->response.data.num_entries = s->num_token_gids;
1592 /* s->token_gids are talloced */
1593 s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
1594 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1595 request_ok(s->state);
1598 /* Get user supplementary sids. This is equivalent to the
1599 winbindd_getgroups() function but it involves a SID->SIDs mapping
1600 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1601 idmap. This call is designed to be used with applications that need
1602 to do ACL evaluation themselves. Note that the cached info3 data is
1605 this function assumes that the SID that comes in is a user SID. If
1606 you pass in another type of SID then you may get unpredictable
1610 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1613 void winbindd_getusersids(struct winbindd_cli_state *state)
1617 /* Ensure null termination */
1618 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1620 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1621 if (user_sid == NULL) {
1622 DEBUG(1, ("talloc failed\n"));
1623 request_error(state);
1627 if (!string_to_sid(user_sid, state->request.data.sid)) {
1628 DEBUG(1, ("Could not get convert sid %s from string\n",
1629 state->request.data.sid));
1630 request_error(state);
1634 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1638 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1641 struct winbindd_cli_state *state =
1642 (struct winbindd_cli_state *)private_data;
1644 unsigned ofs, ret_size = 0;
1648 request_error(state);
1652 /* work out the response size */
1653 for (i = 0; i < num_sids; i++) {
1655 sid_to_fstring(s, &sids[i]);
1656 ret_size += strlen(s) + 1;
1659 /* build the reply */
1660 ret = (char *)SMB_MALLOC(ret_size);
1662 DEBUG(0, ("malloc failed\n"));
1663 request_error(state);
1667 for (i = 0; i < num_sids; i++) {
1669 sid_to_fstring(s, &sids[i]);
1670 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1671 ofs += strlen(ret+ofs) + 1;
1674 /* Send data back to client */
1675 state->response.data.num_entries = num_sids;
1676 state->response.extra_data.data = ret;
1677 state->response.length += ret_size;
1681 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1684 struct winbindd_domain *domain;
1686 /* Ensure null termination */
1687 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1689 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1690 DEBUG(1, ("Could not get convert sid %s from string\n",
1691 state->request.data.sid));
1692 request_error(state);
1696 /* Get info for the domain */
1697 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1698 DEBUG(0,("could not find domain entry for sid %s\n",
1699 sid_string_dbg(&user_sid)));
1700 request_error(state);
1704 sendto_domain(state, domain);
1707 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1708 struct winbindd_cli_state *state)
1718 /* Ensure null termination */
1719 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1721 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1722 DEBUG(1, ("Could not get convert sid %s from string\n",
1723 state->request.data.sid));
1724 return WINBINDD_ERROR;
1727 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1728 &user_sid, &num_groups,
1730 if (!NT_STATUS_IS_OK(status))
1731 return WINBINDD_ERROR;
1733 if (num_groups == 0) {
1734 state->response.data.num_entries = 0;
1735 state->response.extra_data.data = NULL;
1739 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1740 DEBUG(0, ("talloc failed\n"));
1741 return WINBINDD_ERROR;
1744 state->response.extra_data.data = SMB_STRDUP(sidstring);
1745 if (!state->response.extra_data.data) {
1746 return WINBINDD_ERROR;
1748 state->response.length += len+1;
1749 state->response.data.num_entries = num_groups;