This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
-/***************************************************************
- Empty static struct for negative caching.
-****************************************************************/
+static void add_member(const char *domain, const char *user,
+ char **pp_members, size_t *p_num_members)
+{
+ fstring name;
+
+ fill_domain_username(name, domain, user, True);
+ safe_strcat(name, ",", sizeof(name)-1);
+ string_append(pp_members, name);
+ *p_num_members += 1;
+}
+
+/**********************************************************************
+ Add member users resulting from sid. Expand if it is a domain group.
+**********************************************************************/
+
+static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+ struct winbindd_domain *domain;
+ size_t i;
+
+ char *domain_name = NULL;
+ char *name = NULL;
+ enum lsa_SidType type;
+
+ uint32 num_names;
+ DOM_SID *sid_mem;
+ char **names;
+ uint32 *types;
+
+ NTSTATUS result;
+
+ TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
+
+ if (mem_ctx == NULL) {
+ DEBUG(1, ("talloc_init failed\n"));
+ return;
+ }
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ domain = find_lookup_domain_from_sid(sid);
+
+ if (domain == NULL) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_static(sid)));
+ goto done;
+ }
+
+ result = domain->methods->sid_to_name(domain, mem_ctx, sid,
+ &domain_name, &name, &type);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("sid_to_name failed for sid %s\n",
+ sid_string_static(sid)));
+ goto done;
+ }
+
+ DEBUG(10, ("Found name %s, type %d\n", name, type));
+
+ if (type == SID_NAME_USER) {
+ add_member(domain_name, name, pp_members, p_num_members);
+ goto done;
+ }
+
+ if (type != SID_NAME_DOM_GRP) {
+ DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
+ name));
+ goto done;
+ }
+
+ /* Expand the domain group, this must be done via the target domain */
+
+ domain = find_domain_from_sid(sid);
+
+ if (domain == NULL) {
+ DEBUG(3, ("Could not find domain from SID %s\n",
+ sid_string_static(sid)));
+ goto done;
+ }
+
+ result = domain->methods->lookup_groupmem(domain, mem_ctx,
+ sid, &num_names,
+ &sid_mem, &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("Could not lookup group members for %s: %s\n",
+ name, nt_errstr(result)));
+ goto done;
+ }
+
+ for (i=0; i<num_names; i++) {
+ DEBUG(10, ("Adding group member SID %s\n",
+ sid_string_static(&sid_mem[i])));
+
+ if (types[i] != SID_NAME_USER) {
+ DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
+ "Ignoring.\n", names[i], name));
+ continue;
+ }
+
+ add_member(domain->name, names[i], pp_members, p_num_members);
+ }
+
+ done:
+ talloc_destroy(mem_ctx);
+ return;
+}
+
+static BOOL fill_passdb_alias_grmem(struct winbindd_domain *domain,
+ DOM_SID *group_sid,
+ size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
+{
+ DOM_SID *members;
+ size_t i, num_members;
+
+ *num_gr_mem = 0;
+ *gr_mem = NULL;
+ *gr_mem_len = 0;
+
+ if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
+ &num_members)))
+ return True;
+
+ for (i=0; i<num_members; i++) {
+ add_expanded_sid(&members[i], gr_mem, num_gr_mem);
+ }
+
+ TALLOC_FREE(members);
+
+ if (*gr_mem != NULL) {
+ size_t len;
+
+ /* We have at least one member, strip off the last "," */
+ len = strlen(*gr_mem);
+ (*gr_mem)[len-1] = '\0';
+ *gr_mem_len = len;
+ }
+
+ return True;
+}
/* Fill a grent structure from various other information */
return True;
}
-/* Fill in the group membership field of a NT group given by group_sid */
+/***********************************************************************
+ If "enum users" is set to false, and the group being looked
+ up is the Domain Users SID: S-1-5-domain-513, then for the
+ list of members check if the querying user is in that group,
+ and if so only return that user as the gr_mem array.
+ We can change this to a different parameter than "enum users"
+ if neccessaey, or parameterize the group list we do this for.
+***********************************************************************/
+
+static BOOL fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ DOM_SID *group_sid,
+ enum lsa_SidType group_name_type,
+ size_t *num_gr_mem, char **gr_mem,
+ size_t *gr_mem_len)
+{
+ DOM_SID querying_user_sid;
+ DOM_SID *pquerying_user_sid = NULL;
+ uint32 num_groups = 0;
+ DOM_SID *user_sids = NULL;
+ BOOL u_in_group = False;
+ NTSTATUS status;
+ int i;
+ unsigned int buf_len = 0;
+ char *buf = NULL;
+
+ DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
+ domain->name ));
+
+ if (state) {
+ uid_t ret_uid = (uid_t)-1;
+ if (sys_getpeereid(state->sock, &ret_uid)==0) {
+ /* We know who's asking - look up their SID if
+ it's one we've mapped before. */
+ status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
+ if (NT_STATUS_IS_OK(status)) {
+ pquerying_user_sid = &querying_user_sid;
+ DEBUG(10,("fill_grent_mem_domain_users: querying uid %u -> %s\n",
+ (unsigned int)ret_uid,
+ sid_string_static(pquerying_user_sid) ));
+ }
+ }
+ }
+
+ /* Only look up if it was a winbindd user in this domain. */
+ if (pquerying_user_sid &&
+ (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
+
+ DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
+ sid_string_static(pquerying_user_sid) ));
+
+ status = domain->methods->lookup_usergroups(domain,
+ mem_ctx,
+ pquerying_user_sid,
+ &num_groups,
+ &user_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("fill_grent_mem_domain_users: lookup_usergroups failed "
+ "for sid %s in domain %s (error: %s)\n",
+ sid_string_static(pquerying_user_sid),
+ domain->name,
+ nt_errstr(status)));
+ return False;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ if (sid_equal(group_sid, &user_sids[i])) {
+ /* User is in Domain Users, add their name
+ as the only group member. */
+ u_in_group = True;
+ break;
+ }
+ }
+ }
+
+ if (u_in_group) {
+ size_t len = 0;
+ char *domainname = NULL;
+ char *username = NULL;
+ fstring name;
+ enum lsa_SidType type;
+
+ DEBUG(10,("fill_grent_mem_domain_users: sid %s in 'Domain Users' in domain %s\n",
+ sid_string_static(pquerying_user_sid), domain->name ));
+
+ status = domain->methods->sid_to_name(domain, mem_ctx,
+ pquerying_user_sid,
+ &domainname,
+ &username,
+ &type);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("could not lookup username for user "
+ "sid %s in domain %s (error: %s)\n",
+ sid_string_static(pquerying_user_sid),
+ domain->name,
+ nt_errstr(status)));
+ return False;
+ }
+ fill_domain_username(name, domain->name, username, True);
+ len = strlen(name);
+ buf_len = len + 1;
+ if (!(buf = (char *)SMB_MALLOC(buf_len))) {
+ DEBUG(1, ("out of memory\n"));
+ return False;
+ }
+ memcpy(buf, name, buf_len);
+
+ DEBUG(10,("fill_grent_mem_domain_users: user %s in "
+ "'Domain Users' in domain %s\n",
+ name, domain->name ));
+
+ /* user is the only member */
+ *num_gr_mem = 1;
+ }
+
+ *gr_mem = buf;
+ *gr_mem_len = buf_len;
+
+ DEBUG(10, ("fill_grent_mem_domain_users: num_mem = %u, len = %u, mem = %s\n",
+ (unsigned int)*num_gr_mem,
+ (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
+
+ return True;
+}
+
+/***********************************************************************
+ Add names to a list. Assumes a canonical version of the string
+ in DOMAIN\user
+***********************************************************************/
+
+static int namecmp( const void *a, const void *b )
+{
+ return StrCaseCmp( * (char * const *) a, * (char * const *) b);
+}
+
+static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
+ char ***list, uint32 *n_list,
+ char **names, uint32 n_names )
+{
+ char **new_list = NULL;
+ uint32 n_new_list = 0;
+ int i, j;
+
+ if ( !names || (n_names == 0) )
+ return NT_STATUS_OK;
+
+ /* Alloc the maximum size we'll need */
+
+ if ( *list == NULL ) {
+ if ( (new_list = TALLOC_ARRAY( ctx, char *, n_names )) == NULL )
+ return NT_STATUS_NO_MEMORY;
+ n_new_list = n_names;
+ } else {
+ new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
+ (*n_list) + n_names );
+ if ( !new_list )
+ return NT_STATUS_NO_MEMORY;
+ n_new_list = (*n_list) + n_names;
+ }
+
+ /* Add all names */
+
+ for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
+ new_list[i] = talloc_strdup( new_list, names[j] );
+ }
+
+ /* search for duplicates for sorting and looking for matching
+ neighbors */
+
+ qsort( new_list, n_new_list, sizeof(char*), QSORT_CAST namecmp );
+
+ for ( i=1; i<n_new_list; i++ ) {
+ if ( strcmp( new_list[i-1], new_list[i] ) == 0 ) {
+ memmove( &new_list[i-1], &new_list[i],
+ sizeof(char*)*(n_new_list-i) );
+ n_new_list--;
+ }
+ }
+
+ *list = new_list;
+ *n_list = n_new_list;
+
+ return NT_STATUS_OK;
+}
+
+/***********************************************************************
+***********************************************************************/
+
+static NTSTATUS expand_groups( TALLOC_CTX *ctx,
+ struct winbindd_domain *d,
+ DOM_SID *glist, uint32 n_glist,
+ DOM_SID **new_glist, uint32 *n_new_glist,
+ char ***members, uint32 *n_members )
+{
+ int i, j;
+ NTSTATUS status = NT_STATUS_OK;
+ uint32 num_names = 0;
+ uint32 *name_types = NULL;
+ char **names = NULL;
+ DOM_SID *sid_mem = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+ DOM_SID *new_groups = NULL;
+ size_t new_groups_size = 0;
+
+ *members = NULL;
+ *n_members = 0;
+ *new_glist = NULL;
+ *n_new_glist = 0;
+
+ for ( i=0; i<n_glist; i++ ) {
+ tmp_ctx = talloc_new( ctx );
+
+ /* Lookup the group membership */
+
+ status = d->methods->lookup_groupmem(d, tmp_ctx,
+ &glist[i], &num_names,
+ &sid_mem, &names,
+ &name_types);
+ if ( !NT_STATUS_IS_OK(status) )
+ goto out;
+
+ /* Separate users and groups into two lists */
+
+ for ( j=0; j<num_names; j++ ) {
+
+ /* Users */
+ if ( name_types[j] == SID_NAME_USER ||
+ name_types[j] == SID_NAME_COMPUTER )
+ {
+ status = add_names_to_list( ctx, members,
+ n_members,
+ names+j, 1 );
+ if ( !NT_STATUS_IS_OK(status) )
+ goto out;
+
+ continue;
+ }
+
+ /* Groups */
+ if ( name_types[j] == SID_NAME_DOM_GRP ||
+ name_types[j] == SID_NAME_ALIAS )
+ {
+ BOOL ret;
+
+ ret = add_sid_to_array_unique( ctx,
+ &sid_mem[j],
+ &new_groups,
+ &new_groups_size );
+ if ( !ret ) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ continue;
+ }
+ }
+
+ TALLOC_FREE( tmp_ctx );
+ }
+
+ *new_glist = new_groups;
+ *n_new_glist = (uint32)new_groups_size;
+
+ out:
+ TALLOC_FREE( tmp_ctx );
+
+ return status;
+}
+
+/***********************************************************************
+ Fill in the group membership field of a NT group given by group_sid
+***********************************************************************/
static BOOL fill_grent_mem(struct winbindd_domain *domain,
struct winbindd_cli_state *state,
enum lsa_SidType group_name_type,
size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
{
- DOM_SID *sid_mem = NULL;
uint32 num_names = 0;
- uint32 *name_types = NULL;
unsigned int buf_len = 0, buf_ndx = 0, i;
char **names = NULL, *buf = NULL;
BOOL result = False;
TALLOC_CTX *mem_ctx;
- NTSTATUS status;
uint32 group_rid;
- fstring sid_string;
+ DOM_SID *glist = NULL;
+ DOM_SID *new_glist = NULL;
+ uint32 n_glist, n_new_glist;
+ int max_depth = lp_winbind_expand_groups();
if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
return False;
- /* Initialise group membership information */
-
- DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
+ DEBUG(10, ("group SID %s\n", sid_string_static(group_sid)));
+
+ /* Initialize with no members */
*num_gr_mem = 0;
* from more than one domain, ie aliases. Thus we have to work it out
* ourselves in a special routine. */
- if (domain->internal)
- return fill_passdb_alias_grmem(domain, group_sid,
+ if (domain->internal) {
+ result = fill_passdb_alias_grmem(domain, group_sid,
num_gr_mem,
gr_mem, gr_mem_len);
-
+ goto done;
+ }
+
+ /* Verify name type */
+
if ( !((group_name_type==SID_NAME_DOM_GRP) ||
- ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
+ ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
{
DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
- sid_to_string(sid_string, group_sid), domain->name,
+ sid_string_static(group_sid), domain->name,
group_name_type));
goto done;
}
- /* OPTIMIZATION / HACK. */
- /* If "enum users" is set to false, and the group being looked
- up is the Domain Users SID: S-1-5-domain-513, then for the
- list of members check if the querying user is in that group,
- and if so only return that user as the gr_mem array.
- We can change this to a different parameter than "enum users"
- if neccessaey, or parameterize the group list we do this for. */
+ /* OPTIMIZATION / HACK. See comment in
+ fill_grent_mem_domusers() */
sid_peek_rid( group_sid, &group_rid );
if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
- DOM_SID querying_user_sid;
- DOM_SID *pquerying_user_sid = NULL;
- uint32 num_groups = 0;
- DOM_SID *user_sids = NULL;
- BOOL u_in_group = False;
-
- DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
- sid_to_string(sid_string, group_sid), domain->name ));
-
- if (state) {
- uid_t ret_uid = (uid_t)-1;
- if (sys_getpeereid(state->sock, &ret_uid)==0) {
- /* We know who's asking - look up their SID if
- it's one we've mapped before. */
- status = idmap_uid_to_sid(&querying_user_sid,
- ret_uid,
- IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
- if (NT_STATUS_IS_OK(status)) {
- pquerying_user_sid = &querying_user_sid;
- DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
- (unsigned int)ret_uid,
- sid_to_string(sid_string, pquerying_user_sid) ));
- }
- }
- }
-
- /* Only look up if it was a winbindd user in this domain. */
- if (pquerying_user_sid &&
- (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
-
- DEBUG(10,("fill_grent_mem: querying user = %s\n",
- sid_to_string(sid_string, pquerying_user_sid) ));
-
- status = domain->methods->lookup_usergroups(domain,
- mem_ctx,
- pquerying_user_sid,
- &num_groups,
- &user_sids);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
- "for sid %s in domain %s (error: %s)\n",
- sid_to_string(sid_string, pquerying_user_sid),
- domain->name,
- nt_errstr(status)));
- goto done;
- }
-
- for (i = 0; i < num_groups; i++) {
- if (sid_equal(group_sid, &user_sids[i])) {
- /* User is in Domain Users, add their name
- as the only group member. */
- u_in_group = True;
- break;
- }
- }
- }
+ result = fill_grent_mem_domusers( mem_ctx, domain, state,
+ group_sid, group_name_type,
+ num_gr_mem, gr_mem,
+ gr_mem_len );
+ goto done;
+ }
- if (u_in_group) {
- size_t len = 0;
- char *domainname = NULL;
- char *username = NULL;
- fstring name;
- enum lsa_SidType type;
+ /* Real work goes here. Create a list of group names to
+ expand startign with the initial one. Pass that to
+ expand_groups() which returns a list of more group names
+ to expand. Do this up to the max search depth. */
- DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
- sid_to_string(sid_string, pquerying_user_sid), domain->name ));
-
- status = domain->methods->sid_to_name(domain, mem_ctx,
- pquerying_user_sid,
- &domainname,
- &username,
- &type);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("could not lookup username for user "
- "sid %s in domain %s (error: %s)\n",
- sid_to_string(sid_string, pquerying_user_sid),
- domain->name,
- nt_errstr(status)));
- goto done;
- }
- fill_domain_username(name, domain->name, username, True);
- len = strlen(name);
- buf_len = len + 1;
- if (!(buf = (char *)SMB_MALLOC(buf_len))) {
- DEBUG(1, ("out of memory\n"));
- goto done;
- }
- memcpy(buf, name, buf_len);
+ if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
+ result = False;
+ DEBUG(0,("fill_grent_mem: talloc failure!\n"));
+ goto done;
+ }
+ sid_copy( &glist[0], group_sid );
+ n_glist = 1;
+
+ for ( i=0; i<max_depth && glist; i++ ) {
+ uint32 n_members = 0;
+ char **members = NULL;
+ NTSTATUS nt_status;
+
+ nt_status = expand_groups( mem_ctx, domain,
+ glist, n_glist,
+ &new_glist, &n_new_glist,
+ &members, &n_members);
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ result = False;
+ goto done;
+ }
+
+ /* Add new group members to list */
- DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
- name, domain->name ));
+ nt_status = add_names_to_list( mem_ctx, &names, &num_names,
+ members, n_members );
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ result = False;
+ goto done;
}
- *gr_mem = buf;
- *gr_mem_len = buf_len;
- *num_gr_mem = 1;
-
- DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
- (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
- result = True;
- goto done;
- }
+ TALLOC_FREE( members );
- /* Lookup group members */
- status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
- &sid_mem, &names, &name_types);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
- sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
- goto done;
- }
+ /* If we have no more groups to expand, break out
+ early */
- DEBUG(10, ("looked up %d names\n", num_names));
+ if ( !&new_glist )
+ break;
- if (DEBUGLEVEL >= 10) {
- for (i = 0; i < num_names; i++)
- DEBUG(10, ("\t%20s %s %d\n", names[i],
- sid_string_static(&sid_mem[i]),
- name_types[i]));
+ /* One more round */
+ TALLOC_FREE(glist);
+ glist = new_glist;
+ n_glist = n_new_glist;
}
-
- /* Add members to list */
+ TALLOC_FREE( glist );
+
+ DEBUG(10, ("looked up %d names\n", num_names));
again:
+ /* Add members to list */
for (i = 0; i < num_names; i++) {
- char *the_name;
- fstring name;
int len;
- the_name = names[i];
-
- DEBUG(10, ("processing name %s\n", the_name));
-
- /* FIXME: need to cope with groups within groups. These
- occur in Universal groups on a Windows 2000 native mode
- server. */
+ DEBUG(10, ("processing name %s\n", names[i]));
- /* make sure to allow machine accounts */
-
- if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
- DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
- continue;
- }
-
- /* Append domain name */
-
- fill_domain_username(name, domain->name, the_name, True);
-
- len = strlen(name);
+ len = strlen(names[i]);
/* Add to list or calculate buffer length */
(*num_gr_mem)++;
DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
} else {
- DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
- safe_strcpy(&buf[buf_ndx], name, len);
+ DEBUG(10, ("appending %s at ndx %d\n", names[i], buf_ndx));
+ safe_strcpy(&buf[buf_ndx], names[i], len);
buf_ndx += len;
buf[buf_ndx] = ',';
buf_ndx++;
goto again;
}
+ /* Now we're done */
+
if (buf && buf_ndx > 0) {
buf[buf_ndx - 1] = '\0';
}
return result;
}
+static void winbindd_getgrsid( struct winbindd_cli_state *state, DOM_SID group_sid );
+
+static void getgrnam_recv( void *private_data, BOOL success, const DOM_SID *sid,
+ enum lsa_SidType type )
+{
+ struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
+
+ if (!success) {
+ DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
+ request_error(state);
+ return;
+ }
+
+ if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
+ DEBUG(5,("getgrnam_recv: not a group!\n"));
+ request_error(state);
+ return;
+ }
+
+ winbindd_getgrsid( state, *sid );
+}
+
+
/* Return a group structure from a group name */
void winbindd_getgrnam(struct winbindd_cli_state *state)
{
- DOM_SID group_sid, tmp_sid;
- uint32 grp_rid;
struct winbindd_domain *domain;
- enum lsa_SidType name_type;
fstring name_domain, name_group;
- char *tmp, *gr_mem;
- size_t gr_mem_len;
- size_t num_gr_mem;
- gid_t gid;
- union unid_t id;
- NTSTATUS status;
+ char *tmp;
/* Ensure null termination */
state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
memset(name_group, 0, sizeof(fstring));
tmp = state->request.data.groupname;
+
+ name_domain[0] = '\0';
+ name_group[0] = '\0';
parse_domain_user(tmp, name_domain, name_group);
}
/* Get rid and name type from name */
+
+ ws_name_replace( name_group, WB_REPLACE_CHAR );
- if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
- name_group, &group_sid, &name_type)) {
- DEBUG(1, ("group %s in domain %s does not exist\n",
- name_group, name_domain));
- request_error(state);
- return;
- }
+ winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
+ getgrnam_recv, WINBINDD_GETGRNAM, state );
+}
+
+struct getgrsid_state {
+ struct winbindd_cli_state *state;
+ struct winbindd_domain *domain;
+ char *group_name;
+ enum lsa_SidType group_type;
+ uid_t gid;
+ DOM_SID group_sid;
+};
- if ( !((name_type==SID_NAME_DOM_GRP) ||
- ((name_type==SID_NAME_ALIAS) && domain->primary) ||
- ((name_type==SID_NAME_ALIAS) && domain->internal) ||
- ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
+static void getgrsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
{
- DEBUG(1, ("name '%s' is not a local, domain or builtin "
- "group: %d\n", name_group, name_type));
- request_error(state);
+ struct getgrsid_state *s =
+ (struct getgrsid_state *)private_data;
+ struct winbindd_domain *domain;
+ size_t gr_mem_len;
+ size_t num_gr_mem;
+ char *gr_mem;
+ fstring dom_name, group_name;
+
+ if (!success) {
+ DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
+ request_error(s->state);
return;
}
- /* Make sure that the group SID is within the domain of the
- original domain */
+ s->gid = gid;
- sid_copy( &tmp_sid, &group_sid );
- sid_split_rid( &tmp_sid, &grp_rid );
- if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
- DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
- state->request.data.groupname, sid_string_static(&group_sid)));
- request_error(state);
+ if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
+ DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
+ request_error(s->state);
return;
}
+ /* Fill in group structure */
- /* Try to get the GID */
-
- status = idmap_sid_to_gid(&group_sid, &gid, 0);
+ if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
+ DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
+ request_error(s->state);
+ return;
+ }
- if (NT_STATUS_IS_OK(status)) {
- goto got_gid;
+ if (!fill_grent(&s->state->response.data.gr, dom_name, group_name, gid) ||
+ !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
+ &num_gr_mem, &gr_mem, &gr_mem_len))
+ {
+ request_error(s->state);
+ return;
}
- /* Maybe it's one of our aliases in passdb */
+ s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
- if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
- ((name_type == SID_NAME_ALIAS) ||
- (name_type == SID_NAME_WKN_GRP))) {
- gid = id.gid;
- goto got_gid;
- }
+ /* Group membership lives at start of extra data */
- DEBUG(1, ("error converting unix gid to sid\n"));
- request_error(state);
- return;
+ s->state->response.data.gr.gr_mem_ofs = 0;
- got_gid:
+ s->state->response.length += gr_mem_len;
+ s->state->response.extra_data.data = gr_mem;
- if (!fill_grent(&state->response.data.gr, name_domain,
- name_group, gid) ||
- !fill_grent_mem(domain, state, &group_sid, name_type,
- &num_gr_mem,
- &gr_mem, &gr_mem_len)) {
- request_error(state);
- return;
+ request_ok(s->state);
}
- state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
+static void getgrsid_lookupsid_recv( void *private_data, BOOL success,
+ const char *dom_name, const char *name,
+ enum lsa_SidType name_type )
+{
+ struct getgrsid_state *s = (struct getgrsid_state *)private_data;
- /* Group membership lives at start of extra data */
+ if (!success) {
+ DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
+ request_error(s->state);
+ return;
+ }
- state->response.data.gr.gr_mem_ofs = 0;
+ /* either it's a domain group, a domain local group, or a
+ local group in an internal domain */
- state->response.length += gr_mem_len;
- state->response.extra_data.data = gr_mem;
- request_ok(state);
+ if ( !( (name_type==SID_NAME_DOM_GRP) ||
+ ((name_type==SID_NAME_ALIAS) &&
+ (s->domain->primary || s->domain->internal)) ) )
+ {
+ DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
+ dom_name, name, name_type));
+ request_error(s->state);
+ return;
}
-static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
+ if ( (s->group_name = talloc_asprintf( s->state->mem_ctx,
+ "%s\\%s",
+ dom_name, name )) == NULL )
{
- struct winbindd_domain *domain;
- enum lsa_SidType name_type;
- fstring dom_name;
- fstring group_name;
- size_t gr_mem_len;
- size_t num_gr_mem;
- char *gr_mem;
-
- /* Get name from sid */
-
- if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
- group_name, &name_type)) {
- DEBUG(1, ("could not lookup sid\n"));
- request_error(state);
+ DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n"));
+ request_error(s->state);
return;
}
- /* Fill in group structure */
-
- domain = find_domain_from_sid_noinit(&group_sid);
+ s->group_type = name_type;
- if (!domain) {
- DEBUG(1,("Can't find domain from sid\n"));
- request_error(state);
- return;
+ winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
+ getgrsid_sid2gid_recv, s);
}
- if ( !((name_type==SID_NAME_DOM_GRP) ||
- ((name_type==SID_NAME_ALIAS) && domain->primary) ||
- ((name_type==SID_NAME_ALIAS) && domain->internal)) )
+static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
{
- DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
- group_name, name_type));
+ struct getgrsid_state *s;
+
+ if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
+ DEBUG(0, ("talloc failed\n"));
request_error(state);
return;
}
- if (!fill_grent(&state->response.data.gr, dom_name, group_name,
- state->request.data.gid) ||
- !fill_grent_mem(domain, state, &group_sid, name_type,
- &num_gr_mem,
- &gr_mem, &gr_mem_len)) {
+ s->state = state;
+
+ if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_static(&group_sid)));
request_error(state);
return;
}
- state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
-
- /* Group membership lives at start of extra data */
-
- state->response.data.gr.gr_mem_ofs = 0;
+ sid_copy(&s->group_sid, &group_sid);
- state->response.length += gr_mem_len;
- state->response.extra_data.data = gr_mem;
-
- request_ok(state);
+ winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
+ getgrsid_lookupsid_recv, s );
}
+
static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
{
struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
(unsigned long)(state->request.data.gid), sid));
string_to_sid(&group_sid, sid);
- getgrgid_got_sid(state, group_sid);
+ winbindd_getgrsid(state, group_sid);
return;
}
/* Hey, got an alias */
DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
(unsigned long)(state->request.data.gid), sid));
- getgrgid_got_sid(state, group_sid);
+ winbindd_getgrsid(state, group_sid);
return;
}
/* Return a group structure from a gid number */
void winbindd_getgrgid(struct winbindd_cli_state *state)
{
- DOM_SID group_sid;
- NTSTATUS status;
-
DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.gid));
- /* Bug out if the gid isn't in the winbind range */
-
- if ((state->request.data.gid < server_state.gid_low) ||
- (state->request.data.gid > server_state.gid_high)) {
- request_error(state);
- return;
- }
-
- /* Get sid from gid */
-
- status = idmap_gid_to_sid(&group_sid, state->request.data.gid, IDMAP_FLAG_NONE);
- if (NT_STATUS_IS_OK(status)) {
- /* This is a remote one */
- getgrgid_got_sid(state, group_sid);
- return;
- }
-
- DEBUG(10,("winbindd_getgrgid: gid %lu not found in cache, try with the async interface\n",
- (unsigned long)state->request.data.gid));
-
+ /* always use the async interface */
winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
}
{
struct getent_state *ent;
struct winbindd_gr *group_list = NULL;
- int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
+ int num_groups, group_list_ndx, gr_mem_list_len = 0;
char *gr_mem_list = NULL;
DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
+ if (num_groups == 0) {
+ request_error(state);
+ return;
+ }
+
if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
request_error(state);
return;
/* Start sending back groups */
- for (i = 0; i < num_groups; i++) {
+ for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
struct acct_info *name_list = NULL;
fstring domain_group_name;
uint32 result;
sid_copy(&group_sid, &domain->sid);
sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
- if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid,
- &group_gid, 0))) {
+ if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
union unid_t id;
enum lsa_SidType type;
DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
state->request.data.username));
- /* when using "winbind use default domain" we need to avoid that
- * initgroups() requests from NSS hit our DC too badly for accounts
- * that will never be on the remote DC */
-
- if (lp_winbind_use_default_domain()) {
-
- const char **list = lp_winbind_initgroups_blacklist();
- int i;
-
- if (!list || !list[0]) {
- goto parse;
- }
-
- for (i=0; list[i] != NULL; i++) {
-
- if (strequal(state->request.data.username, list[i])) {
- DEBUG(3,("ignoring blacklisted user [%s] for getgroups\n",
- state->request.data.username));
- request_ok(state);
- return;
- }
- }
- }
- parse:
/* Parse domain and username */
s = TALLOC_P(state->mem_ctx, struct getgroups_state);
s->state = state;
+ ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
+
if (!parse_domain_user_talloc(state->mem_ctx,
state->request.data.username,
&s->domname, &s->username)) {
}
if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
- DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
+ DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
"getgroups() for %s\\%s.\n", s->domname,
s->username));
request_error(state);
/* Get rid and name type from name. The following costs 1 packet */
winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
- getgroups_usersid_recv, s);
+ getgroups_usersid_recv, WINBINDD_GETGROUPS, s);
}
static void getgroups_usersid_recv(void *private_data, BOOL success,
struct getgroups_state *s =
(struct getgroups_state *)private_data;
- if (success)
- add_gid_to_array_unique(NULL, gid,
+ if (success) {
+ if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
&s->token_gids,
- &s->num_token_gids);
+ &s->num_token_gids)) {
+ return;
+ }
+ }
if (s->i < s->num_token_sids) {
const DOM_SID *sid = &s->token_sids[s->i];
}
s->state->response.data.num_entries = s->num_token_gids;
- s->state->response.extra_data.data = s->token_gids;
+ /* s->token_gids are talloced */
+ s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
s->state->response.length += s->num_token_gids * sizeof(gid_t);
request_ok(s->state);
}
return WINBINDD_OK;
}
- if (!print_sidlist(NULL, groups, num_groups, &sidstring, &len)) {
- DEBUG(0, ("malloc failed\n"));
+ if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
+ DEBUG(0, ("talloc failed\n"));
return WINBINDD_ERROR;
}
- state->response.extra_data.data = sidstring;
+ state->response.extra_data.data = SMB_STRDUP(sidstring);
+ if (!state->response.extra_data.data) {
+ return WINBINDD_ERROR;
+ }
state->response.length += len+1;
state->response.data.num_entries = num_groups;