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_static(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_static(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_static(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_static(&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_static(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_static(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_static(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_static(pquerying_user_sid), domain->name ));
283 status = domain->methods->sid_to_name(domain, mem_ctx,
288 if (!NT_STATUS_IS_OK(status)) {
289 DEBUG(1, ("could not lookup username for user "
290 "sid %s in domain %s (error: %s)\n",
291 sid_string_static(pquerying_user_sid),
296 fill_domain_username(name, domain->name, username, True);
299 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
300 DEBUG(1, ("out of memory\n"));
303 memcpy(buf, name, buf_len);
305 DEBUG(10,("fill_grent_mem_domain_users: user %s in "
306 "'Domain Users' in domain %s\n",
307 name, domain->name ));
309 /* user is the only member */
314 *gr_mem_len = buf_len;
316 DEBUG(10, ("fill_grent_mem_domain_users: num_mem = %u, len = %u, mem = %s\n",
317 (unsigned int)*num_gr_mem,
318 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
323 /***********************************************************************
324 Add names to a list. Assumes a canonical version of the string
326 ***********************************************************************/
328 static int namecmp( const void *a, const void *b )
330 return StrCaseCmp( * (char * const *) a, * (char * const *) b);
333 static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
334 char ***list, uint32 *n_list,
335 char **names, uint32 n_names )
337 char **new_list = NULL;
338 uint32 n_new_list = 0;
341 if ( !names || (n_names == 0) )
344 /* Alloc the maximum size we'll need */
346 if ( *list == NULL ) {
347 if ( (new_list = TALLOC_ARRAY( ctx, char *, n_names )) == NULL )
348 return NT_STATUS_NO_MEMORY;
349 n_new_list = n_names;
351 new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
352 (*n_list) + n_names );
354 return NT_STATUS_NO_MEMORY;
355 n_new_list = (*n_list) + n_names;
360 for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
361 new_list[i] = talloc_strdup( new_list, names[j] );
364 /* search for duplicates for sorting and looking for matching
367 qsort( new_list, n_new_list, sizeof(char*), QSORT_CAST namecmp );
369 for ( i=1; i<n_new_list; i++ ) {
370 if ( strcmp( new_list[i-1], new_list[i] ) == 0 ) {
371 memmove( &new_list[i-1], &new_list[i],
372 sizeof(char*)*(n_new_list-i) );
378 *n_list = n_new_list;
383 /***********************************************************************
384 ***********************************************************************/
386 static NTSTATUS expand_groups( TALLOC_CTX *ctx,
387 struct winbindd_domain *d,
388 DOM_SID *glist, uint32 n_glist,
389 DOM_SID **new_glist, uint32 *n_new_glist,
390 char ***members, uint32 *n_members )
393 NTSTATUS status = NT_STATUS_OK;
394 uint32 num_names = 0;
395 uint32 *name_types = NULL;
397 DOM_SID *sid_mem = NULL;
398 TALLOC_CTX *tmp_ctx = NULL;
399 DOM_SID *new_groups = NULL;
400 size_t new_groups_size = 0;
407 for ( i=0; i<n_glist; i++ ) {
408 tmp_ctx = talloc_new( ctx );
410 /* Lookup the group membership */
412 status = d->methods->lookup_groupmem(d, tmp_ctx,
413 &glist[i], &num_names,
416 if ( !NT_STATUS_IS_OK(status) )
419 /* Separate users and groups into two lists */
421 for ( j=0; j<num_names; j++ ) {
424 if ( name_types[j] == SID_NAME_USER ||
425 name_types[j] == SID_NAME_COMPUTER )
427 status = add_names_to_list( ctx, members,
430 if ( !NT_STATUS_IS_OK(status) )
437 if ( name_types[j] == SID_NAME_DOM_GRP ||
438 name_types[j] == SID_NAME_ALIAS )
442 ret = add_sid_to_array_unique( ctx,
447 status = NT_STATUS_NO_MEMORY;
455 TALLOC_FREE( tmp_ctx );
458 *new_glist = new_groups;
459 *n_new_glist = (uint32)new_groups_size;
462 TALLOC_FREE( tmp_ctx );
467 /***********************************************************************
468 Fill in the group membership field of a NT group given by group_sid
469 ***********************************************************************/
471 static bool fill_grent_mem(struct winbindd_domain *domain,
472 struct winbindd_cli_state *state,
474 enum lsa_SidType group_name_type,
475 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
477 uint32 num_names = 0;
478 unsigned int buf_len = 0, buf_ndx = 0, i;
479 char **names = NULL, *buf = NULL;
483 DOM_SID *glist = NULL;
484 DOM_SID *new_glist = NULL;
485 uint32 n_glist, n_new_glist;
486 int max_depth = lp_winbind_expand_groups();
488 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
491 DEBUG(10, ("group SID %s\n", sid_string_static(group_sid)));
493 /* Initialize with no members */
497 /* HACK ALERT!! This whole routine does not cope with group members
498 * from more than one domain, ie aliases. Thus we have to work it out
499 * ourselves in a special routine. */
501 if (domain->internal) {
502 result = fill_passdb_alias_grmem(domain, group_sid,
508 /* Verify name type */
510 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
511 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
513 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
514 sid_string_static(group_sid), domain->name,
519 /* OPTIMIZATION / HACK. See comment in
520 fill_grent_mem_domusers() */
522 sid_peek_rid( group_sid, &group_rid );
523 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
524 result = fill_grent_mem_domusers( mem_ctx, domain, state,
525 group_sid, group_name_type,
531 /* Real work goes here. Create a list of group names to
532 expand startign with the initial one. Pass that to
533 expand_groups() which returns a list of more group names
534 to expand. Do this up to the max search depth. */
536 if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
538 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
541 sid_copy( &glist[0], group_sid );
544 for ( i=0; i<max_depth && glist; i++ ) {
545 uint32 n_members = 0;
546 char **members = NULL;
549 nt_status = expand_groups( mem_ctx, domain,
551 &new_glist, &n_new_glist,
552 &members, &n_members);
553 if ( !NT_STATUS_IS_OK(nt_status) ) {
558 /* Add new group members to list */
560 nt_status = add_names_to_list( mem_ctx, &names, &num_names,
561 members, n_members );
562 if ( !NT_STATUS_IS_OK(nt_status) ) {
567 TALLOC_FREE( members );
569 /* If we have no more groups to expand, break out
578 n_glist = n_new_glist;
580 TALLOC_FREE( glist );
582 DEBUG(10, ("looked up %d names\n", num_names));
585 /* Add members to list */
587 for (i = 0; i < num_names; i++) {
590 DEBUG(10, ("processing name %s\n", names[i]));
592 len = strlen(names[i]);
594 /* Add to list or calculate buffer length */
597 buf_len += len + 1; /* List is comma separated */
599 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
601 DEBUG(10, ("appending %s at ndx %d\n", names[i], buf_ndx));
602 safe_strcpy(&buf[buf_ndx], names[i], len);
609 /* Allocate buffer */
611 if (!buf && buf_len != 0) {
612 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
613 DEBUG(1, ("out of memory\n"));
617 memset(buf, 0, buf_len);
623 if (buf && buf_ndx > 0) {
624 buf[buf_ndx - 1] = '\0';
628 *gr_mem_len = buf_len;
630 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
631 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
636 talloc_destroy(mem_ctx);
638 DEBUG(10, ("fill_grent_mem returning %d\n", result));
643 static void winbindd_getgrsid( struct winbindd_cli_state *state, DOM_SID group_sid );
645 static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
646 enum lsa_SidType type )
648 struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
651 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
652 request_error(state);
656 if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
657 DEBUG(5,("getgrnam_recv: not a group!\n"));
658 request_error(state);
662 winbindd_getgrsid( state, *sid );
666 /* Return a group structure from a group name */
668 void winbindd_getgrnam(struct winbindd_cli_state *state)
670 struct winbindd_domain *domain;
671 fstring name_domain, name_group;
674 /* Ensure null termination */
675 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
677 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
678 state->request.data.groupname));
680 /* Parse domain and groupname */
682 memset(name_group, 0, sizeof(fstring));
684 tmp = state->request.data.groupname;
686 name_domain[0] = '\0';
687 name_group[0] = '\0';
689 parse_domain_user(tmp, name_domain, name_group);
691 /* if no domain or our local domain and no local tdb group, default to
692 * our local domain for aliases */
694 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
695 fstrcpy(name_domain, get_global_sam_name());
698 /* Get info for the domain */
700 if ((domain = find_domain_from_name(name_domain)) == NULL) {
701 DEBUG(3, ("could not get domain sid for domain %s\n",
703 request_error(state);
706 /* should we deal with users for our domain? */
708 if ( lp_winbind_trusted_domains_only() && domain->primary) {
709 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
710 "getgrnam() for %s\\%s.\n", name_domain, name_group));
711 request_error(state);
715 /* Get rid and name type from name */
717 ws_name_replace( name_group, WB_REPLACE_CHAR );
719 winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
720 getgrnam_recv, WINBINDD_GETGRNAM, state );
723 struct getgrsid_state {
724 struct winbindd_cli_state *state;
725 struct winbindd_domain *domain;
727 enum lsa_SidType group_type;
732 static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
734 struct getgrsid_state *s =
735 (struct getgrsid_state *)private_data;
736 struct winbindd_domain *domain;
740 fstring dom_name, group_name;
743 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
744 request_error(s->state);
750 if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
751 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
752 request_error(s->state);
757 /* Fill in group structure */
759 if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
760 DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
761 request_error(s->state);
765 if (!fill_grent(&s->state->response.data.gr, dom_name, group_name, gid) ||
766 !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
767 &num_gr_mem, &gr_mem, &gr_mem_len))
769 request_error(s->state);
773 s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
775 /* Group membership lives at start of extra data */
777 s->state->response.data.gr.gr_mem_ofs = 0;
779 s->state->response.length += gr_mem_len;
780 s->state->response.extra_data.data = gr_mem;
782 request_ok(s->state);
785 static void getgrsid_lookupsid_recv( void *private_data, bool success,
786 const char *dom_name, const char *name,
787 enum lsa_SidType name_type )
789 struct getgrsid_state *s = (struct getgrsid_state *)private_data;
792 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
793 request_error(s->state);
797 /* either it's a domain group, a domain local group, or a
798 local group in an internal domain */
800 if ( !( (name_type==SID_NAME_DOM_GRP) ||
801 ((name_type==SID_NAME_ALIAS) &&
802 (s->domain->primary || s->domain->internal)) ) )
804 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
805 dom_name, name, name_type));
806 request_error(s->state);
810 if ( (s->group_name = talloc_asprintf( s->state->mem_ctx,
812 dom_name, name )) == NULL )
814 DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n"));
815 request_error(s->state);
819 s->group_type = name_type;
821 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
822 getgrsid_sid2gid_recv, s);
825 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
827 struct getgrsid_state *s;
829 if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
830 DEBUG(0, ("talloc failed\n"));
831 request_error(state);
837 if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
838 DEBUG(3, ("Could not find domain for sid %s\n",
839 sid_string_static(&group_sid)));
840 request_error(state);
844 sid_copy(&s->group_sid, &group_sid);
846 winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
847 getgrsid_lookupsid_recv, s );
851 static void getgrgid_recv(void *private_data, bool success, const char *sid)
853 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
854 enum lsa_SidType name_type;
858 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
859 (unsigned long)(state->request.data.gid), sid));
861 string_to_sid(&group_sid, sid);
862 winbindd_getgrsid(state, group_sid);
866 /* Ok, this might be "ours", i.e. an alias */
867 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
868 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
869 (name_type == SID_NAME_ALIAS)) {
870 /* Hey, got an alias */
871 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
872 (unsigned long)(state->request.data.gid), sid));
873 winbindd_getgrsid(state, group_sid);
877 DEBUG(1, ("could not convert gid %lu to sid\n",
878 (unsigned long)state->request.data.gid));
879 request_error(state);
882 /* Return a group structure from a gid number */
883 void winbindd_getgrgid(struct winbindd_cli_state *state)
885 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
886 (unsigned long)state->request.data.gid));
888 /* always use the async interface */
889 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
893 * set/get/endgrent functions
896 /* "Rewind" file pointer for group database enumeration */
898 static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
900 struct winbindd_domain *domain;
902 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
904 /* Check user has enabled this */
906 if (!lp_winbind_enum_groups()) {
910 /* Free old static data if it exists */
912 if (state->getgrent_state != NULL) {
913 free_getent_state(state->getgrent_state);
914 state->getgrent_state = NULL;
917 /* Create sam pipes for each domain we know about */
919 for (domain = domain_list(); domain != NULL; domain = domain->next) {
920 struct getent_state *domain_state;
922 /* Create a state record for this domain */
924 /* don't add our domaina if we are a PDC or if we
925 are a member of a Samba domain */
927 if ( lp_winbind_trusted_domains_only() && domain->primary )
933 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
934 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
938 ZERO_STRUCTP(domain_state);
940 fstrcpy(domain_state->domain_name, domain->name);
942 /* Add to list of open domains */
944 DLIST_ADD(state->getgrent_state, domain_state);
947 state->getgrent_initialized = True;
951 void winbindd_setgrent(struct winbindd_cli_state *state)
953 if (winbindd_setgrent_internal(state)) {
956 request_error(state);
960 /* Close file pointer to ntdom group database */
962 void winbindd_endgrent(struct winbindd_cli_state *state)
964 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
966 free_getent_state(state->getgrent_state);
967 state->getgrent_initialized = False;
968 state->getgrent_state = NULL;
972 /* Get the list of domain groups and domain aliases for a domain. We fill in
973 the sam_entries and num_sam_entries fields with domain group information.
974 The dispinfo_ndx field is incremented to the index of the next group to
975 fetch. Return True if some groups were returned, False otherwise. */
977 static bool get_sam_group_entries(struct getent_state *ent)
981 struct acct_info *name_list = NULL;
984 struct acct_info *sam_grp_entries = NULL;
985 struct winbindd_domain *domain;
987 if (ent->got_sam_entries)
990 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
991 ent->domain_name))) {
992 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
996 /* Free any existing group info */
998 SAFE_FREE(ent->sam_entries);
999 ent->num_sam_entries = 0;
1000 ent->got_sam_entries = True;
1002 /* Enumerate domain groups */
1006 if (!(domain = find_domain_from_name(ent->domain_name))) {
1007 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
1011 /* always get the domain global groups */
1013 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
1021 /* Copy entries into return buffer */
1024 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
1025 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
1030 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
1033 ent->num_sam_entries = num_entries;
1035 /* get the domain local groups if we are a member of a native win2k domain
1036 and are not using LDAP to get the groups */
1038 if ( ( lp_security() != SEC_ADS && domain->native_mode
1039 && domain->primary) || domain->internal )
1041 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
1042 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
1044 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
1046 if ( !NT_STATUS_IS_OK(status) ) {
1047 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
1051 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
1053 /* Copy entries into return buffer */
1055 if ( num_entries ) {
1056 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
1058 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
1064 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
1065 num_entries * sizeof(struct acct_info) );
1068 ent->num_sam_entries += num_entries;
1072 /* Fill in remaining fields */
1074 ent->sam_entries = name_list;
1075 ent->sam_entry_index = 0;
1077 result = (ent->num_sam_entries > 0);
1080 talloc_destroy(mem_ctx);
1085 /* Fetch next group entry from ntdom database */
1087 #define MAX_GETGRENT_GROUPS 500
1089 void winbindd_getgrent(struct winbindd_cli_state *state)
1091 struct getent_state *ent;
1092 struct winbindd_gr *group_list = NULL;
1093 int num_groups, group_list_ndx, gr_mem_list_len = 0;
1094 char *gr_mem_list = NULL;
1096 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1098 /* Check user has enabled this */
1100 if (!lp_winbind_enum_groups()) {
1101 request_error(state);
1105 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
1107 if (num_groups == 0) {
1108 request_error(state);
1112 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
1113 request_error(state);
1117 memset(state->response.extra_data.data, '\0',
1118 num_groups * sizeof(struct winbindd_gr) );
1120 state->response.data.num_entries = 0;
1122 group_list = (struct winbindd_gr *)state->response.extra_data.data;
1124 if (!state->getgrent_initialized)
1125 winbindd_setgrent_internal(state);
1127 if (!(ent = state->getgrent_state)) {
1128 request_error(state);
1132 /* Start sending back groups */
1134 for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
1135 struct acct_info *name_list = NULL;
1136 fstring domain_group_name;
1142 struct winbindd_domain *domain;
1144 /* Do we need to fetch another chunk of groups? */
1148 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1149 ent->sam_entry_index, ent->num_sam_entries));
1151 if (ent->num_sam_entries == ent->sam_entry_index) {
1153 while(ent && !get_sam_group_entries(ent)) {
1154 struct getent_state *next_ent;
1156 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
1158 /* Free state information for this domain */
1160 SAFE_FREE(ent->sam_entries);
1162 next_ent = ent->next;
1163 DLIST_REMOVE(state->getgrent_state, ent);
1169 /* No more domains */
1175 name_list = (struct acct_info *)ent->sam_entries;
1178 find_domain_from_name(ent->domain_name))) {
1179 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
1184 /* Lookup group info */
1186 sid_copy(&group_sid, &domain->sid);
1187 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1189 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
1191 enum lsa_SidType type;
1193 DEBUG(10, ("SID %s not in idmap\n",
1194 sid_string_static(&group_sid)));
1196 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1197 DEBUG(1, ("could not look up gid for group "
1199 name_list[ent->sam_entry_index].acct_name));
1200 ent->sam_entry_index++;
1204 if ((type != SID_NAME_DOM_GRP) &&
1205 (type != SID_NAME_ALIAS) &&
1206 (type != SID_NAME_WKN_GRP)) {
1207 DEBUG(1, ("Group %s is a %s, not a group\n",
1208 sid_type_lookup(type),
1209 name_list[ent->sam_entry_index].acct_name));
1210 ent->sam_entry_index++;
1216 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1217 (unsigned long)name_list[ent->sam_entry_index].rid));
1219 /* Fill in group entry */
1221 fill_domain_username(domain_group_name, ent->domain_name,
1222 name_list[ent->sam_entry_index].acct_name, True);
1224 result = fill_grent(&group_list[group_list_ndx],
1226 name_list[ent->sam_entry_index].acct_name,
1229 /* Fill in group membership entry */
1232 size_t num_gr_mem = 0;
1234 group_list[group_list_ndx].num_gr_mem = 0;
1238 /* Get group membership */
1239 if (state->request.cmd == WINBINDD_GETGRLST) {
1242 sid_copy(&member_sid, &domain->sid);
1243 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1244 result = fill_grent_mem(
1250 &gr_mem, &gr_mem_len);
1252 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1257 /* Append to group membership list */
1258 gr_mem_list = (char *)SMB_REALLOC(
1259 gr_mem_list, gr_mem_list_len + gr_mem_len);
1261 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
1262 DEBUG(0, ("out of memory\n"));
1263 gr_mem_list_len = 0;
1267 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1268 gr_mem_list_len, (unsigned int)gr_mem_len));
1270 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1275 group_list[group_list_ndx].gr_mem_ofs =
1278 gr_mem_list_len += gr_mem_len;
1281 ent->sam_entry_index++;
1283 /* Add group to return list */
1287 DEBUG(10, ("adding group num_entries = %d\n",
1288 state->response.data.num_entries));
1291 state->response.data.num_entries++;
1293 state->response.length +=
1294 sizeof(struct winbindd_gr);
1297 DEBUG(0, ("could not lookup domain group %s\n",
1298 domain_group_name));
1302 /* Copy the list of group memberships to the end of the extra data */
1304 if (group_list_ndx == 0)
1307 state->response.extra_data.data = SMB_REALLOC(
1308 state->response.extra_data.data,
1309 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1311 if (!state->response.extra_data.data) {
1312 DEBUG(0, ("out of memory\n"));
1314 SAFE_FREE(gr_mem_list);
1315 request_error(state);
1319 memcpy(&((char *)state->response.extra_data.data)
1320 [group_list_ndx * sizeof(struct winbindd_gr)],
1321 gr_mem_list, gr_mem_list_len);
1323 state->response.length += gr_mem_list_len;
1325 DEBUG(10, ("returning %d groups, length = %d\n",
1326 group_list_ndx, gr_mem_list_len));
1328 /* Out of domains */
1332 SAFE_FREE(gr_mem_list);
1334 if (group_list_ndx > 0)
1337 request_error(state);
1340 /* List domain groups without mapping to unix ids */
1342 void winbindd_list_groups(struct winbindd_cli_state *state)
1344 uint32 total_entries = 0;
1345 struct winbindd_domain *domain;
1346 const char *which_domain;
1347 char *extra_data = NULL;
1348 unsigned int extra_data_len = 0, i;
1350 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1352 /* Ensure null termination */
1353 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1354 which_domain = state->request.domain_name;
1356 /* Enumerate over trusted domains */
1358 for (domain = domain_list(); domain; domain = domain->next) {
1359 struct getent_state groups;
1361 /* if we have a domain name restricting the request and this
1362 one in the list doesn't match, then just bypass the remainder
1365 if ( *which_domain && !strequal(which_domain, domain->name) )
1368 ZERO_STRUCT(groups);
1370 /* Get list of sam groups */
1372 fstrcpy(groups.domain_name, domain->name);
1374 get_sam_group_entries(&groups);
1376 if (groups.num_sam_entries == 0) {
1377 /* this domain is empty or in an error state */
1381 /* keep track the of the total number of groups seen so
1382 far over all domains */
1383 total_entries += groups.num_sam_entries;
1385 /* Allocate some memory for extra data. Note that we limit
1386 account names to sizeof(fstring) = 128 characters. */
1387 extra_data = (char *)SMB_REALLOC(
1388 extra_data, sizeof(fstring) * total_entries);
1391 DEBUG(0,("failed to enlarge buffer!\n"));
1392 request_error(state);
1396 /* Pack group list into extra data fields */
1397 for (i = 0; i < groups.num_sam_entries; i++) {
1398 char *group_name = ((struct acct_info *)
1399 groups.sam_entries)[i].acct_name;
1402 fill_domain_username(name, domain->name, group_name, True);
1403 /* Append to extra data */
1404 memcpy(&extra_data[extra_data_len], name,
1406 extra_data_len += strlen(name);
1407 extra_data[extra_data_len++] = ',';
1410 SAFE_FREE(groups.sam_entries);
1413 /* Assign extra_data fields in response structure */
1415 extra_data[extra_data_len - 1] = '\0';
1416 state->response.extra_data.data = extra_data;
1417 state->response.length += extra_data_len;
1420 /* No domains may have responded but that's still OK so don't
1426 /* Get user supplementary groups. This is much quicker than trying to
1427 invert the groups database. We merge the groups from the gids and
1428 other_sids info3 fields as trusted domain, universal group
1429 memberships, and nested groups (win2k native mode only) are not
1430 returned by the getgroups RPC call but are present in the info3. */
1432 struct getgroups_state {
1433 struct winbindd_cli_state *state;
1434 struct winbindd_domain *domain;
1439 const DOM_SID *token_sids;
1440 size_t i, num_token_sids;
1443 size_t num_token_gids;
1446 static void getgroups_usersid_recv(void *private_data, bool success,
1447 const DOM_SID *sid, enum lsa_SidType type);
1448 static void getgroups_tokensids_recv(void *private_data, bool success,
1449 DOM_SID *token_sids, size_t num_token_sids);
1450 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1452 void winbindd_getgroups(struct winbindd_cli_state *state)
1454 struct getgroups_state *s;
1456 /* Ensure null termination */
1457 state->request.data.username
1458 [sizeof(state->request.data.username)-1]='\0';
1460 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1461 state->request.data.username));
1463 /* Parse domain and username */
1465 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1467 DEBUG(0, ("talloc failed\n"));
1468 request_error(state);
1474 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
1476 if (!parse_domain_user_talloc(state->mem_ctx,
1477 state->request.data.username,
1478 &s->domname, &s->username)) {
1479 DEBUG(5, ("Could not parse domain user: %s\n",
1480 state->request.data.username));
1482 /* error out if we do not have nested group support */
1484 if ( !lp_winbind_nested_groups() ) {
1485 request_error(state);
1489 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1490 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1493 /* Get info for the domain */
1495 s->domain = find_domain_from_name_noinit(s->domname);
1497 if (s->domain == NULL) {
1498 DEBUG(7, ("could not find domain entry for domain %s\n",
1500 request_error(state);
1504 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1505 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1506 "getgroups() for %s\\%s.\n", s->domname,
1508 request_error(state);
1512 /* Get rid and name type from name. The following costs 1 packet */
1514 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1515 getgroups_usersid_recv, WINBINDD_GETGROUPS, s);
1518 static void getgroups_usersid_recv(void *private_data, bool success,
1519 const DOM_SID *sid, enum lsa_SidType type)
1521 struct getgroups_state *s =
1522 (struct getgroups_state *)private_data;
1525 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1526 request_error(s->state);
1530 sid_copy(&s->user_sid, sid);
1532 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1533 getgroups_tokensids_recv, s);
1536 static void getgroups_tokensids_recv(void *private_data, bool success,
1537 DOM_SID *token_sids, size_t num_token_sids)
1539 struct getgroups_state *s =
1540 (struct getgroups_state *)private_data;
1542 /* We need at least the user sid and the primary group in the token,
1543 * otherwise it's an error */
1545 if ((!success) || (num_token_sids < 2)) {
1546 request_error(s->state);
1550 s->token_sids = token_sids;
1551 s->num_token_sids = num_token_sids;
1554 s->token_gids = NULL;
1555 s->num_token_gids = 0;
1557 getgroups_sid2gid_recv(s, False, 0);
1560 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
1562 struct getgroups_state *s =
1563 (struct getgroups_state *)private_data;
1566 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1568 &s->num_token_gids)) {
1573 if (s->i < s->num_token_sids) {
1574 const DOM_SID *sid = &s->token_sids[s->i];
1577 if (sid_equal(sid, &s->user_sid)) {
1578 getgroups_sid2gid_recv(s, False, 0);
1582 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1583 getgroups_sid2gid_recv, s);
1587 s->state->response.data.num_entries = s->num_token_gids;
1588 /* s->token_gids are talloced */
1589 s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
1590 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1591 request_ok(s->state);
1594 /* Get user supplementary sids. This is equivalent to the
1595 winbindd_getgroups() function but it involves a SID->SIDs mapping
1596 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1597 idmap. This call is designed to be used with applications that need
1598 to do ACL evaluation themselves. Note that the cached info3 data is
1601 this function assumes that the SID that comes in is a user SID. If
1602 you pass in another type of SID then you may get unpredictable
1606 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1609 void winbindd_getusersids(struct winbindd_cli_state *state)
1613 /* Ensure null termination */
1614 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1616 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1617 if (user_sid == NULL) {
1618 DEBUG(1, ("talloc failed\n"));
1619 request_error(state);
1623 if (!string_to_sid(user_sid, state->request.data.sid)) {
1624 DEBUG(1, ("Could not get convert sid %s from string\n",
1625 state->request.data.sid));
1626 request_error(state);
1630 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1634 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1637 struct winbindd_cli_state *state =
1638 (struct winbindd_cli_state *)private_data;
1640 unsigned ofs, ret_size = 0;
1644 request_error(state);
1648 /* work out the response size */
1649 for (i = 0; i < num_sids; i++) {
1650 const char *s = sid_string_static(&sids[i]);
1651 ret_size += strlen(s) + 1;
1654 /* build the reply */
1655 ret = (char *)SMB_MALLOC(ret_size);
1657 DEBUG(0, ("malloc failed\n"));
1658 request_error(state);
1662 for (i = 0; i < num_sids; i++) {
1663 const char *s = sid_string_static(&sids[i]);
1664 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1665 ofs += strlen(ret+ofs) + 1;
1668 /* Send data back to client */
1669 state->response.data.num_entries = num_sids;
1670 state->response.extra_data.data = ret;
1671 state->response.length += ret_size;
1675 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1678 struct winbindd_domain *domain;
1680 /* Ensure null termination */
1681 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1683 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1684 DEBUG(1, ("Could not get convert sid %s from string\n",
1685 state->request.data.sid));
1686 request_error(state);
1690 /* Get info for the domain */
1691 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1692 DEBUG(0,("could not find domain entry for sid %s\n",
1693 sid_string_static(&user_sid)));
1694 request_error(state);
1698 sendto_domain(state, domain);
1701 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1702 struct winbindd_cli_state *state)
1712 /* Ensure null termination */
1713 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1715 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1716 DEBUG(1, ("Could not get convert sid %s from string\n",
1717 state->request.data.sid));
1718 return WINBINDD_ERROR;
1721 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1722 &user_sid, &num_groups,
1724 if (!NT_STATUS_IS_OK(status))
1725 return WINBINDD_ERROR;
1727 if (num_groups == 0) {
1728 state->response.data.num_entries = 0;
1729 state->response.extra_data.data = NULL;
1733 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1734 DEBUG(0, ("talloc failed\n"));
1735 return WINBINDD_ERROR;
1738 state->response.extra_data.data = SMB_STRDUP(sidstring);
1739 if (!state->response.extra_data.data) {
1740 return WINBINDD_ERROR;
1742 state->response.length += len+1;
1743 state->response.data.num_entries = num_groups;