From f3f2744e9cf9fde94a75ba3c6c6ffd02434375d1 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Tue, 9 Oct 2001 22:55:00 +0000 Subject: [PATCH] Implemented sam group handle stuff. getent group now works. (This used to be commit 63731d4a00e7a70b48d0c25677c76ec6b2e04ce1) --- source3/nsswitch/winbindd.c | 11 ++- source3/nsswitch/winbindd_cm.c | 69 +++++++++++++++++-- source3/nsswitch/winbindd_group.c | 109 +++++++++++++---------------- source3/nsswitch/winbindd_proto.h | 5 +- source3/nsswitch/winbindd_user.c | 14 ++-- source3/nsswitch/winbindd_util.c | 110 +++++++++++++++++++++--------- 6 files changed, 208 insertions(+), 110 deletions(-) diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index 21dda58aae1..4a01b06ea92 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -1,6 +1,6 @@ /* Unix SMB/Netbios implementation. - Version 2.0 + Version 3.0 Winbind daemon for ntdom nss module @@ -234,18 +234,20 @@ static struct dispatch_table dispatch_table[] = { { WINBINDD_ENDPWENT, winbindd_endpwent }, { WINBINDD_GETPWENT, winbindd_getpwent }, -#if 0 - { WINBINDD_GETGROUPS, winbindd_getgroups }, /* Group functions */ +#if 0 { WINBINDD_GETGRNAM_FROM_GROUP, winbindd_getgrnam_from_group }, { WINBINDD_GETGRNAM_FROM_GID, winbindd_getgrnam_from_gid }, +#endif { WINBINDD_SETGRENT, winbindd_setgrent }, { WINBINDD_ENDGRENT, winbindd_endgrent }, { WINBINDD_GETGRENT, winbindd_getgrent }, +#if 0 + /* PAM auth functions */ { WINBINDD_PAM_AUTH, winbindd_pam_auth }, @@ -254,10 +256,13 @@ static struct dispatch_table dispatch_table[] = { /* Enumeration functions */ +#endif + { WINBINDD_LIST_USERS, winbindd_list_users }, { WINBINDD_LIST_GROUPS, winbindd_list_groups }, { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains }, +#if 0 /* SID related functions */ { WINBINDD_LOOKUPSID, winbindd_lookupsid }, diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index df9c553b0b6..b6c72e8b8e2 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -85,7 +85,7 @@ struct winbindd_cm_conn { /* Specific pipe stuff - move into a union? */ enum sam_pipe_type sam_pipe_type; /* Domain, user, group etc */ - uint32 user_rid; + uint32 user_rid, group_rid; }; /* Global list of connections. Initially a DLIST but can become a hash @@ -414,8 +414,69 @@ CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid, /* Return a SAM policy handle on a domain group */ -CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, char *group) +CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid, + uint32 group_rid) { - DEBUG(0, ("get_sam_group_handle(): not implemented\n")); - return NULL; + struct winbindd_cm_conn *conn, *basic_conn = NULL; + static CLI_POLICY_HND hnd; + NTSTATUS result; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + + /* Look for existing connections */ + + for (conn = cm_conns; conn; conn = conn->next) { + if (strequal(conn->domain, domain) && + strequal(conn->pipe_name, PIPE_SAMR) && + conn->sam_pipe_type == SAM_PIPE_GROUP && + conn->group_rid == group_rid) + goto ok; + } + + /* Create a domain handle to open a user handle from */ + + if (!cm_get_sam_dom_handle(domain, domain_sid)) + return NULL; + + for (conn = cm_conns; conn; conn = conn->next) { + if (strequal(conn->domain, domain) && + strequal(conn->pipe_name, PIPE_SAMR) && + conn->sam_pipe_type == SAM_PIPE_DOM) + basic_conn = conn; + } + + if (!basic_conn) { + DEBUG(0, ("No domain sam handle was created!\n")); + return NULL; + } + + if (!(conn = (struct winbindd_cm_conn *) + malloc(sizeof(struct winbindd_cm_conn)))) + return NULL; + + ZERO_STRUCTP(conn); + + fstrcpy(conn->domain, basic_conn->domain); + fstrcpy(conn->controller, basic_conn->controller); + fstrcpy(conn->pipe_name, basic_conn->pipe_name); + + conn->sam_pipe_type = SAM_PIPE_GROUP; + conn->cli = basic_conn->cli; + conn->group_rid = group_rid; + + result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx, + &basic_conn->pol, des_access, group_rid, + &conn->pol); + + if (!NT_STATUS_IS_OK(result)) + return NULL; + + /* Add to list */ + + DLIST_ADD(cm_conns, conn); + + ok: + hnd.pol = conn->pol; + hnd.cli = conn->cli; + + return &hnd; } diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index 40ad100fc5b..f13f44b8cf0 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -23,8 +23,6 @@ #include "winbindd.h" -#if 0 - /* Fill a grent structure from various other information */ static BOOL fill_grent(struct winbindd_gr *gr, char *gr_name, @@ -185,6 +183,8 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, return result; } +#if 0 + /* Return a group structure from a group name */ enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state @@ -385,6 +385,8 @@ enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state return WINBINDD_OK; } +#endif + /* * set/get/endgrent functions */ @@ -397,13 +399,10 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state) DEBUG(3, ("[%5d]: setgrent\n", state->pid)); - if (state == NULL) return WINBINDD_ERROR; - /* Check user has enabled this */ - if (!lp_winbind_enum_groups()) { + if (!lp_winbind_enum_groups()) return WINBINDD_ERROR; - } /* Free old static data if it exists */ @@ -421,17 +420,14 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state) variable */ if ((strcmp(state->request.domain, "") != 0) && - !check_domain_env(state->request.domain, tmp->name)) { + !check_domain_env(state->request.domain, tmp->name)) continue; - } /* Create a state record for this domain */ if ((domain_state = (struct getent_state *) - malloc(sizeof(struct getent_state))) == NULL) { - + malloc(sizeof(struct getent_state))) == NULL) return WINBINDD_ERROR; - } ZERO_STRUCTP(domain_state); @@ -471,24 +467,16 @@ static BOOL get_sam_group_entries(struct getent_state *ent) uint32 num_entries; struct acct_info *name_list = NULL, *tnl; - if (ent->got_all_sam_entries) { + if (ent->got_all_sam_entries) return False; - } #if 0 if (winbindd_fetch_group_cache(ent->domain->name, &ent->sam_entries, - &ent->num_sam_entries)) { + &ent->num_sam_entries)) return True; - } #endif - /* Fetch group entries */ - - if (!domain_handles_open(ent->domain)) { - return False; - } - /* Free any existing group info */ SAFE_FREE(ent->sam_entries); @@ -502,11 +490,12 @@ static BOOL get_sam_group_entries(struct getent_state *ent) num_entries = 0; - if (!(hnd = cm_get_sam_dom_handle(ent->domain->name))) + if (!(hnd = cm_get_sam_dom_handle(ent->domain->name, + &ent->domain->sid))) break; status = cli_samr_enum_dom_groups( - hnd->cli, hnd->cli->mem_ctx, hnd->pol, + hnd->cli, hnd->cli->mem_ctx, &hnd->pol, &ent->grp_query_start_ndx, 0x8000, /* buffer size? */ (struct acct_info **) &sam_grp_entries, &num_entries); @@ -519,13 +508,15 @@ static BOOL get_sam_group_entries(struct getent_state *ent) sizeof(struct acct_info) * (ent->num_sam_entries + num_entries)); - if(tnl == NULL) - { - DEBUG(0,("get_sam_group_entries: unable ro realloc a structure!\n")); + + if (tnl == NULL) { + DEBUG(0,("get_sam_group_entries: unable to " + "realloc a structure!\n")); SAFE_FREE(name_list); - return False; - } - else name_list = tnl; + + return False; + } else + name_list = tnl; memcpy(&name_list[ent->num_sam_entries], sam_grp_entries, @@ -552,7 +543,8 @@ static BOOL get_sam_group_entries(struct getent_state *ent) ent->sam_entries = name_list; ent->sam_entry_index = 0; - ent->got_all_sam_entries = (NT_STATUS_V(status) != NT_STATUS_V(STATUS_MORE_ENTRIES)); + ent->got_all_sam_entries = (NT_STATUS_V(status) != + NT_STATUS_V(STATUS_MORE_ENTRIES)); return ent->num_sam_entries > 0; } @@ -570,29 +562,24 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) DEBUG(3, ("[%5d]: getgrent\n", state->pid)); - if (state == NULL) return WINBINDD_ERROR; - /* Check user has enabled this */ - if (!lp_winbind_enum_groups()) { + if (!lp_winbind_enum_groups()) return WINBINDD_ERROR; - } num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries); if ((state->response.extra_data = - malloc(num_groups * sizeof(struct winbindd_gr))) == NULL) { + malloc(num_groups * sizeof(struct winbindd_gr))) == NULL) return WINBINDD_ERROR; - } state->response.data.num_entries = 0; group_list = (struct winbindd_gr *)state->response.extra_data; sep = lp_winbind_separator(); - if (!(ent = state->getgrent_state)) { + if (!(ent = state->getgrent_state)) return WINBINDD_ERROR; - } /* Start sending back groups */ @@ -631,7 +618,8 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) /* No more domains */ - if (!ent) break; + if (!ent) + break; } name_list = ent->sam_entries; @@ -729,9 +717,8 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) /* Copy the list of group memberships to the end of the extra data */ - if (group_list_ndx == 0) { + if (group_list_ndx == 0) goto done; - } new_extra_data = Realloc( state->response.extra_data, @@ -781,16 +768,17 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) DEBUG(3, ("[%5d]: list groups\n", state->pid)); /* Enumerate over trusted domains */ + ZERO_STRUCT(groups); + for (domain = domain_list; domain; domain = domain->next) { /* Skip domains other than WINBINDD_DOMAIN environment variable */ if ((strcmp(state->request.domain, "") != 0) && - !check_domain_env(state->request.domain, domain->name)) { + !check_domain_env(state->request.domain, domain->name)) continue; - } /* Get list of sam groups */ @@ -799,13 +787,13 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) /* * iterate through all groups - * total_entries : maintains a total count over **all domains** - * num_domain_entries : is the running count for this domain + * total_entries: maintains a total count over **all domains** + * num_domain_entries: is the running count for this domain */ num_domain_entries = 0; - while (get_sam_group_entries(&groups)) - { + + while (get_sam_group_entries(&groups)) { int new_size; int offset; @@ -818,8 +806,10 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) return WINBINDD_ERROR; num_domain_entries += groups.num_sam_entries; - memcpy (((char *)sam_entries)+offset, groups.sam_entries, - sizeof(struct acct_info) * groups.num_sam_entries); + memcpy (((char *)sam_entries)+offset, + groups.sam_entries, + sizeof(struct acct_info) * + groups.num_sam_entries); groups.sam_entries = NULL; groups.num_sam_entries = 0; @@ -847,7 +837,8 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) ted = Realloc(extra_data, sizeof(fstring) * total_entries); if (!ted) { - DEBUG(0,("winbindd_list_groups: failed to enlarge buffer!\n")); + DEBUG(0,("winbindd_list_groups: failed to enlarge " + "buffer!\n")); SAFE_FREE(extra_data); return WINBINDD_ERROR; } else @@ -867,7 +858,9 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) /* Append to extra data */ - memcpy(&extra_data[extra_data_len], name, strlen(name)); + memcpy(&extra_data[extra_data_len], name, + strlen(name)); + extra_data_len += strlen(name); extra_data[extra_data_len++] = ','; @@ -906,8 +899,6 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) DEBUG(3, ("[%5d]: getgroups %s\n", state->pid, state->request.data.username)); - if (state == NULL) return WINBINDD_ERROR; - /* Parse domain and username */ parse_domain_user(state->request.data.username, name_domain, @@ -916,9 +907,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) /* Reject names that don't have a domain - i.e name_domain contains the entire name. */ - if (strequal(name_domain, "")) { + if (strequal(name_domain, "")) return WINBINDD_ERROR; - } /* Get info for the domain */ @@ -928,10 +918,6 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) return WINBINDD_ERROR; } - if (!domain_handles_open(domain)) { - return WINBINDD_ERROR; - } - slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user); /* Get rid and name type from name. The following costs 1 packet */ @@ -950,9 +936,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) sid_split_rid(&user_sid, &user_rid); if (!winbindd_lookup_usergroups(domain, user_rid, &num_groups, - &user_groups)) { + &user_groups)) return WINBINDD_ERROR; - } /* Copy data back to client */ @@ -988,5 +973,3 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) return result; } - -#endif diff --git a/source3/nsswitch/winbindd_proto.h b/source3/nsswitch/winbindd_proto.h index 3c44b632345..b32ca114246 100644 --- a/source3/nsswitch/winbindd_proto.h +++ b/source3/nsswitch/winbindd_proto.h @@ -53,7 +53,8 @@ CLI_POLICY_HND *cm_get_sam_handle(char *domain); CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid); CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid, uint32 user_rid); -CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, char *group); +CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid, + uint32 group_rid); /* The following definitions come from nsswitch/winbindd_group.c */ @@ -125,7 +126,7 @@ BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid, enum SID_NAME_USE *type); BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name, enum SID_NAME_USE *type); -BOOL winbindd_lookup_userinfo(char *domain, uint32 user_rid, +BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain, uint32 user_rid, SAM_USERINFO_CTR **user_info); BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain, uint32 user_rid, uint32 *num_groups, diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 25ab38dd8c2..fe134c4e66c 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -99,6 +99,7 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state DOM_SID user_sid; fstring name_domain, name_user, name, gecos_name; enum SID_NAME_USE name_type; + struct winbindd_domain *domain; DEBUG(3, ("[%5d]: getpwnam %s\n", state->pid, state->request.data.username)); @@ -115,6 +116,11 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state return WINBINDD_ERROR; } + if ((domain = find_domain_from_name(name_domain)) == NULL) { + DEBUG(5, ("No such domain: %s\n", name_domain)); + return WINBINDD_ERROR; + } + /* Check for cached user entry */ if (winbindd_fetch_user_cache_entry(name_domain, name_user, @@ -124,7 +130,7 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user); - /* Get rid and name type from name. The following costs 1 packet */ + /* Get rid and name type from name */ if (!winbindd_lookup_sid_by_name(name, &user_sid, &name_type)) { DEBUG(1, ("user '%s' does not exist\n", name_user)); @@ -143,9 +149,7 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state sid_split_rid(&user_sid, &user_rid); - /* The following costs 3 packets */ - - if (!winbindd_lookup_userinfo(name_domain, user_rid, &user_info)) { + if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) { DEBUG(1, ("pwnam_from_user(): error getting user info for " "user '%s'\n", name_user)); return WINBINDD_ERROR; @@ -229,7 +233,7 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state /* Get some user info */ - if (!winbindd_lookup_userinfo(domain->name, user_rid, &user_info)) { + if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) { DEBUG(1, ("pwnam_from_uid(): error getting user info for " "user '%s'\n", user_name)); return WINBINDD_ERROR; diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index c257719be15..a5e558f6586 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -531,18 +531,14 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name, /* Lookup user information from a rid */ -BOOL winbindd_lookup_userinfo(char *domain_name, uint32 user_rid, +BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain, uint32 user_rid, SAM_USERINFO_CTR **user_info) { CLI_POLICY_HND *hnd; uint16 info_level = 0x15; NTSTATUS result; - struct winbindd_domain *domain; - if (!(domain = find_domain_from_name(domain_name))) - return False; - - if (!(hnd = cm_get_sam_user_handle(domain_name, &domain->sid, + if (!(hnd = cm_get_sam_user_handle(domain->name, &domain->sid, user_rid))) return False; @@ -552,51 +548,99 @@ BOOL winbindd_lookup_userinfo(char *domain_name, uint32 user_rid, return NT_STATUS_IS_OK(result); } -#if 0 - /* Lookup groups a user is a member of. I wish Unix had a call like this! */ BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain, uint32 user_rid, uint32 *num_groups, DOM_GID **user_groups) { - POLICY_HND user_pol; - BOOL result; + CLI_POLICY_HND *hnd; + NTSTATUS result; - if (!wb_samr_open_user(&domain->sam_dom_handle, - SEC_RIGHTS_MAXIMUM_ALLOWED, - user_rid, &user_pol)) { - return False; - } - - if (!NT_STATUS_IS_OK(cli_samr_query_usergroups(domain->sam_dom_handle.cli, - domain->sam_dom_handle.mem_ctx, - &user_pol, num_groups, user_groups))) { - result = False; - goto done; - } - - result = True; + if (!(hnd = cm_get_sam_user_handle(domain->name, &domain->sid, + user_rid))) + return False; -done: - cli_samr_close(domain->sam_dom_handle.cli, - domain->sam_dom_handle.mem_ctx, &user_pol); + result = cli_samr_query_usergroups(hnd->cli, hnd->cli->mem_ctx, + &hnd->pol, num_groups, + user_groups); - return True; + return NT_STATUS_IS_OK(result); } -/* Lookup group membership given a rid */ +/* Lookup group membership given a rid. */ BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain, uint32 group_rid, uint32 *num_names, uint32 **rid_mem, char ***names, uint32 **name_types) { - return wb_sam_query_groupmem(&domain->sam_dom_handle, group_rid, - num_names, rid_mem, names, name_types); -} + CLI_POLICY_HND *group_hnd, *dom_hnd; + NTSTATUS result; + uint32 i, total_names = 0; -#endif + if (!(group_hnd = cm_get_sam_group_handle(domain->name, &domain->sid, + group_rid))) + return False; + + /* Get group membership. This is a list of rids. */ + + result = cli_samr_query_groupmem(group_hnd->cli, + group_hnd->cli->mem_ctx, + &group_hnd->pol, num_names, rid_mem, + name_types); + + if (!NT_STATUS_IS_OK(result)) + return NT_STATUS_IS_OK(result); + + /* Convert list of rids into list of names. Do this in bunches of + ~1000 to avoid crashing NT4. It looks like there is a buffer + overflow or something like that lurking around somewhere. */ + + if (!(dom_hnd = cm_get_sam_dom_handle(domain->name, &domain->sid))) + return False; + +#define MAX_LOOKUP_RIDS 900 + + *names = talloc(dom_hnd->cli->mem_ctx, *num_names * sizeof(char *)); + *name_types = talloc(dom_hnd->cli->mem_ctx, *num_names * + sizeof(uint32)); + + for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) { + int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS); + uint32 tmp_num_names = 0; + char **tmp_names = NULL; + uint32 *tmp_types = NULL; + + /* Lookup a chunk of rids */ + + result = cli_samr_lookup_rids(dom_hnd->cli, + dom_hnd->cli->mem_ctx, + &dom_hnd->pol, 1000, /* flags */ + num_lookup_rids, + &(*rid_mem)[i], + &tmp_num_names, + &tmp_names, &tmp_types); + + if (!NT_STATUS_IS_OK(result)) + return False; + + /* Copy result into array. The talloc system will take + care of freeing the temporary arrays later on. */ + + memcpy(&(*names)[i], tmp_names, sizeof(char *) * + tmp_num_names); + + memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) * + tmp_num_names); + + total_names += tmp_num_names; + } + + *num_names = total_names; + + return NT_STATUS_IS_OK(result); +} /* Globals for domain list stuff */ -- 2.34.1