From d7b5e929adea72d8e26eb3c0a2f295f9f0295e9a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 14:52:49 +0100 Subject: [PATCH 1/9] Revert "winbind: Remove rpc_lookup_usergroups" This reverts commit 91b73b1e93bb8fb38e2f1cea6c1cbd012c952542. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 8fafdada52f76ccc5e56ce1a736d4ca9815b387b) --- source3/winbindd/winbindd_rpc.c | 74 +++++++++++++++++++++++++++++++++++++++++ source3/winbindd/winbindd_rpc.h | 9 +++++ 2 files changed, 83 insertions(+) diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c index fcc6366..528d360 100644 --- a/source3/winbindd/winbindd_rpc.c +++ b/source3/winbindd/winbindd_rpc.c @@ -437,6 +437,80 @@ NTSTATUS rpc_rids_to_names(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } +/* Lookup groups a user is a member of. */ +NTSTATUS rpc_lookup_usergroups(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *samr_pipe, + struct policy_handle *samr_policy, + const struct dom_sid *domain_sid, + const struct dom_sid *user_sid, + uint32_t *pnum_groups, + struct dom_sid **puser_grpsids) +{ + struct policy_handle user_policy; + struct samr_RidWithAttributeArray *rid_array = NULL; + struct dom_sid *user_grpsids = NULL; + uint32_t num_groups = 0, i; + uint32_t user_rid; + NTSTATUS status, result; + struct dcerpc_binding_handle *b = samr_pipe->binding_handle; + + if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* Get user handle */ + status = dcerpc_samr_OpenUser(b, + mem_ctx, + samr_policy, + SEC_FLAG_MAXIMUM_ALLOWED, + user_rid, + &user_policy, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + /* Query user rids */ + status = dcerpc_samr_GetGroupsForUser(b, + mem_ctx, + &user_policy, + &rid_array, + &result); + { + NTSTATUS _result; + dcerpc_samr_Close(b, mem_ctx, &user_policy, &_result); + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + num_groups = rid_array->count; + + user_grpsids = talloc_array(mem_ctx, struct dom_sid, num_groups); + if (user_grpsids == NULL) { + status = NT_STATUS_NO_MEMORY; + return status; + } + + for (i = 0; i < num_groups; i++) { + sid_compose(&(user_grpsids[i]), domain_sid, + rid_array->rids[i].rid); + } + + *pnum_groups = num_groups; + + *puser_grpsids = user_grpsids; + + return NT_STATUS_OK; +} + NTSTATUS rpc_lookup_useraliases(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *samr_pipe, struct policy_handle *samr_policy, diff --git a/source3/winbindd/winbindd_rpc.h b/source3/winbindd/winbindd_rpc.h index ee4b210..162f1ef 100644 --- a/source3/winbindd/winbindd_rpc.h +++ b/source3/winbindd/winbindd_rpc.h @@ -78,6 +78,15 @@ NTSTATUS rpc_rids_to_names(TALLOC_CTX *mem_ctx, char ***pnames, enum lsa_SidType **ptypes); +/* Lookup groups a user is a member of. */ +NTSTATUS rpc_lookup_usergroups(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *samr_pipe, + struct policy_handle *samr_policy, + const struct dom_sid *domain_sid, + const struct dom_sid *user_sid, + uint32_t *pnum_groups, + struct dom_sid **puser_grpsids); + NTSTATUS rpc_lookup_useraliases(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *samr_pipe, struct policy_handle *samr_policy, -- 1.9.1 From f4d5d1628f5752c283dc6afdfd7d937d6fd73736 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 14:53:47 +0100 Subject: [PATCH 2/9] Revert "winbind: Remove "lookup_usergroups" winbind method" This reverts commit b231814c6b0ad17255139bc8934f269610348b2b. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 3f5fa7c458dbc673b35827bb588e424cd14332c7) --- source3/winbindd/winbindd.h | 8 + source3/winbindd/winbindd_ads.c | 377 ++++++++++++++++++++++++++++++ source3/winbindd/winbindd_msrpc.c | 72 ++++++ source3/winbindd/winbindd_reconnect.c | 21 ++ source3/winbindd/winbindd_reconnect_ads.c | 22 ++ source3/winbindd/winbindd_samr.c | 65 ++++++ 6 files changed, 565 insertions(+) diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 0f95703..c220573 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -262,6 +262,14 @@ struct winbindd_methods { char ***names, enum lsa_SidType **types); + /* lookup all groups that a user is a member of. The backend + can also choose to lookup by username or rid for this + function */ + NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *num_groups, struct dom_sid **user_gids); + /* Lookup all aliases that the sids delivered are member of. This is * to implement 'domain local groups' correctly */ NTSTATUS (*lookup_useraliases)(struct winbindd_domain *domain, diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index cde9099..d2e1ac4 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -574,6 +574,382 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, domain_name, names, types); } +/* Lookup groups a user is a member of - alternate method, for when + tokenGroups are not available. */ +static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_dn, + struct dom_sid *primary_group, + uint32_t *p_num_groups, struct dom_sid **user_sids) +{ + ADS_STATUS rc; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + int count; + LDAPMessage *res = NULL; + LDAPMessage *msg = NULL; + char *ldap_exp; + ADS_STRUCT *ads; + const char *group_attrs[] = {"objectSid", NULL}; + char *escaped_dn; + uint32_t num_groups = 0; + + DEBUG(3,("ads: lookup_usergroups_member\n")); + + if ( !winbindd_can_contact_domain( domain ) ) { + DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n", + domain->name)); + return NT_STATUS_OK; + } + + ads = ads_cached_connection(domain); + + if (!ads) { + domain->last_status = NT_STATUS_SERVER_DISABLED; + goto done; + } + + if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + ldap_exp = talloc_asprintf(mem_ctx, + "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))", + escaped_dn, + ADS_LDAP_MATCHING_RULE_BIT_AND, + GROUP_TYPE_SECURITY_ENABLED); + if (!ldap_exp) { + DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn)); + TALLOC_FREE(escaped_dn); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + TALLOC_FREE(escaped_dn); + + rc = ads_search_retry(ads, &res, ldap_exp, group_attrs); + + if (!ADS_ERR_OK(rc)) { + DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc))); + return ads_ntstatus(rc); + } else if (!res) { + DEBUG(1,("lookup_usergroups ads_search returned NULL res\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + + count = ads_count_replies(ads, res); + + *user_sids = NULL; + num_groups = 0; + + /* always add the primary group to the sid array */ + status = add_sid_to_array(mem_ctx, primary_group, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (count > 0) { + for (msg = ads_first_entry(ads, res); msg; + msg = ads_next_entry(ads, msg)) { + struct dom_sid group_sid; + + if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) { + DEBUG(1,("No sid for this group ?!?\n")); + continue; + } + + /* ignore Builtin groups from ADS - Guenther */ + if (sid_check_is_in_builtin(&group_sid)) { + continue; + } + + status = add_sid_to_array(mem_ctx, &group_sid, + user_sids, &num_groups); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + } + + } + + *p_num_groups = num_groups; + status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; + + DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn)); +done: + if (res) + ads_msgfree(ads, res); + + return status; +} + +/* Lookup groups a user is a member of - alternate method, for when + tokenGroups are not available. */ +static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_dn, + struct dom_sid *primary_group, + uint32_t *p_num_groups, + struct dom_sid **user_sids) +{ + ADS_STATUS rc; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + ADS_STRUCT *ads; + const char *attrs[] = {"memberOf", NULL}; + uint32_t num_groups = 0; + struct dom_sid *group_sids = NULL; + int i; + char **strings = NULL; + size_t num_strings = 0, num_sids = 0; + + + DEBUG(3,("ads: lookup_usergroups_memberof\n")); + + if ( !winbindd_can_contact_domain( domain ) ) { + DEBUG(10,("lookup_usergroups_memberof: No incoming trust for " + "domain %s\n", domain->name)); + return NT_STATUS_OK; + } + + ads = ads_cached_connection(domain); + + if (!ads) { + domain->last_status = NT_STATUS_SERVER_DISABLED; + return NT_STATUS_UNSUCCESSFUL; + } + + rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs, + ADS_EXTENDED_DN_HEX_STRING, + &strings, &num_strings); + + if (!ADS_ERR_OK(rc)) { + DEBUG(1,("lookup_usergroups_memberof ads_search " + "member=%s: %s\n", user_dn, ads_errstr(rc))); + return ads_ntstatus(rc); + } + + *user_sids = NULL; + num_groups = 0; + + /* always add the primary group to the sid array */ + status = add_sid_to_array(mem_ctx, primary_group, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1); + if (!group_sids) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i=0; iname)); + + /* Tell the cache manager not to remember this one */ + + return NT_STATUS_SYNCHRONIZATION_REQUIRED; + } + + ads = ads_cached_connection(domain); + + if (!ads) { + domain->last_status = NT_STATUS_SERVER_DISABLED; + status = NT_STATUS_SERVER_DISABLED; + goto done; + } + + rc = ads_search_retry_sid(ads, &msg, sid, attrs); + + if (!ADS_ERR_OK(rc)) { + status = ads_ntstatus(rc); + DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: " + "%s\n", sid_string_dbg(sid), ads_errstr(rc))); + goto done; + } + + count = ads_count_replies(ads, msg); + if (count != 1) { + status = NT_STATUS_UNSUCCESSFUL; + DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: " + "invalid number of results (count=%d)\n", + sid_string_dbg(sid), count)); + goto done; + } + + if (!msg) { + DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", + sid_string_dbg(sid))); + status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + user_dn = ads_get_dn(ads, mem_ctx, msg); + if (user_dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) { + DEBUG(1,("%s: No primary group for sid=%s !?\n", + domain->name, sid_string_dbg(sid))); + goto done; + } + + sid_compose(&primary_group, &domain->sid, primary_group_rid); + + count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids); + + /* there must always be at least one group in the token, + unless we are talking to a buggy Win2k server */ + + /* actually this only happens when the machine account has no read + * permissions on the tokenGroup attribute - gd */ + + if (count == 0) { + + /* no tokenGroups */ + + /* lookup what groups this user is a member of by DN search on + * "memberOf" */ + + status = lookup_usergroups_memberof(domain, mem_ctx, user_dn, + &primary_group, + &num_groups, user_sids); + *p_num_groups = num_groups; + if (NT_STATUS_IS_OK(status)) { + goto done; + } + + /* lookup what groups this user is a member of by DN search on + * "member" */ + + status = lookup_usergroups_member(domain, mem_ctx, user_dn, + &primary_group, + &num_groups, user_sids); + *p_num_groups = num_groups; + goto done; + } + + *user_sids = NULL; + num_groups = 0; + + status = add_sid_to_array(mem_ctx, &primary_group, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + for (i=0;iname)); + + /* Tell the cache manager not to remember this one */ + status = NT_STATUS_SYNCHRONIZATION_REQUIRED; + goto done; + } + + /* no cache; hit the wire */ + status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = rpc_lookup_usergroups(tmp_ctx, + samr_pipe, + &dom_pol, + &domain->sid, + user_sid, + &num_groups, + &user_grpsids); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + +cached: + *pnum_groups = num_groups; + + if (puser_grpsids) { + *puser_grpsids = talloc_move(mem_ctx, &user_grpsids); + } + +done: + TALLOC_FREE(tmp_ctx); + return status; + return NT_STATUS_OK; +} + #define MAX_SAM_ENTRIES_W2K 0x400 /* 1024 */ static NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain, @@ -1090,6 +1161,7 @@ struct winbindd_methods msrpc_methods = { msrpc_name_to_sid, msrpc_sid_to_name, msrpc_rids_to_names, + msrpc_lookup_usergroups, msrpc_lookup_useraliases, msrpc_lookup_groupmem, msrpc_sequence_number, diff --git a/source3/winbindd/winbindd_reconnect.c b/source3/winbindd/winbindd_reconnect.c index d23ffcf..bbb5a37 100644 --- a/source3/winbindd/winbindd_reconnect.c +++ b/source3/winbindd/winbindd_reconnect.c @@ -199,6 +199,26 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, return result; } +/* Lookup groups a user is a member of. I wish Unix had a call like this! */ +static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *num_groups, struct dom_sid **user_gids) +{ + NTSTATUS result; + + result = msrpc_methods.lookup_usergroups(domain, mem_ctx, + user_sid, num_groups, + user_gids); + + if (reconnect_need_retry(result, domain)) + result = msrpc_methods.lookup_usergroups(domain, mem_ctx, + user_sid, num_groups, + user_gids); + + return result; +} + static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t num_sids, const struct dom_sid *sids, @@ -314,6 +334,7 @@ struct winbindd_methods reconnect_methods = { name_to_sid, sid_to_name, rids_to_names, + lookup_usergroups, lookup_useraliases, lookup_groupmem, sequence_number, diff --git a/source3/winbindd/winbindd_reconnect_ads.c b/source3/winbindd/winbindd_reconnect_ads.c index 17ea9d2..3bb8b5e 100644 --- a/source3/winbindd/winbindd_reconnect_ads.c +++ b/source3/winbindd/winbindd_reconnect_ads.c @@ -153,6 +153,27 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, return result; } +/* Lookup groups a user is a member of. I wish Unix had a call like this! */ +static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *num_groups, + struct dom_sid **user_gids) +{ + NTSTATUS result; + + result = ads_methods.lookup_usergroups(domain, mem_ctx, user_sid, + num_groups, user_gids); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.lookup_usergroups(domain, mem_ctx, + user_sid, num_groups, + user_gids); + } + + return result; +} + static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t num_sids, @@ -269,6 +290,7 @@ struct winbindd_methods reconnect_ads_methods = { name_to_sid, sid_to_name, rids_to_names, + lookup_usergroups, lookup_useraliases, lookup_groupmem, sequence_number, diff --git a/source3/winbindd/winbindd_samr.c b/source3/winbindd/winbindd_samr.c index 1a73fc4..aedb77b 100644 --- a/source3/winbindd/winbindd_samr.c +++ b/source3/winbindd/winbindd_samr.c @@ -758,6 +758,69 @@ error: return status; } +/* Lookup groups a user is a member of. */ +static NTSTATUS sam_lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *pnum_groups, + struct dom_sid **puser_grpsids) +{ + struct rpc_pipe_client *samr_pipe; + struct policy_handle dom_pol; + struct dom_sid *user_grpsids = NULL; + uint32_t num_groups = 0; + TALLOC_CTX *tmp_ctx; + NTSTATUS status, result; + struct dcerpc_binding_handle *b = NULL; + + DEBUG(3,("sam_lookup_usergroups\n")); + + ZERO_STRUCT(dom_pol); + + if (pnum_groups) { + *pnum_groups = 0; + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = open_internal_samr_conn(tmp_ctx, domain, &samr_pipe, &dom_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + b = samr_pipe->binding_handle; + + status = rpc_lookup_usergroups(tmp_ctx, + samr_pipe, + &dom_pol, + &domain->sid, + user_sid, + &num_groups, + &user_grpsids); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (pnum_groups) { + *pnum_groups = num_groups; + } + + if (puser_grpsids) { + *puser_grpsids = talloc_move(mem_ctx, &user_grpsids); + } + +done: + if (b && is_valid_policy_hnd(&dom_pol)) { + dcerpc_samr_Close(b, mem_ctx, &dom_pol, &result); + } + + TALLOC_FREE(tmp_ctx); + return status; +} + static NTSTATUS sam_lookup_useraliases(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t num_sids, @@ -879,6 +942,7 @@ struct winbindd_methods builtin_passdb_methods = { .name_to_sid = sam_name_to_sid, .sid_to_name = sam_sid_to_name, .rids_to_names = sam_rids_to_names, + .lookup_usergroups = sam_lookup_usergroups, .lookup_useraliases = sam_lookup_useraliases, .lookup_groupmem = sam_lookup_groupmem, .sequence_number = sam_sequence_number, @@ -897,6 +961,7 @@ struct winbindd_methods sam_passdb_methods = { .name_to_sid = sam_name_to_sid, .sid_to_name = sam_sid_to_name, .rids_to_names = sam_rids_to_names, + .lookup_usergroups = sam_lookup_usergroups, .lookup_useraliases = sam_lookup_useraliases, .lookup_groupmem = sam_lookup_groupmem, .sequence_number = sam_sequence_number, -- 1.9.1 From 3e6f1d591ec4a492c823b519196dbacfd6dffc37 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 14:54:09 +0100 Subject: [PATCH 3/9] Revert "winbind: Remove validate_ug" This reverts commit 3f58a8cabab75a594cff9088d5dd8ea439b36178. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 174b14b5aa8fbff4732a2213494a870aee1c7569) --- source3/winbindd/winbindd_cache.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index 4431cb5..a343ad1 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -2917,6 +2917,11 @@ void wcache_invalidate_samlogon(struct winbindd_domain *domain, DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str)); tdb_delete(cache->tdb, string_tdb_data(key_str)); + /* Clear UG/SID cache entry */ + fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid)); + DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str)); + tdb_delete(cache->tdb, string_tdb_data(key_str)); + /* Samba/winbindd never needs this. */ netsamlogon_clear_cached_user(sid); } @@ -3679,6 +3684,32 @@ static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, return 0; } +static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, + struct tdb_validation_status *state) +{ + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); + int32_t num_groups, i; + + if (!centry) { + return 1; + } + + num_groups = centry_uint32(centry); + + for (i=0; i< num_groups; i++) { + struct dom_sid sid; + centry_sid(centry, &sid); + } + + centry_free(centry); + + if (!(state->success)) { + return 1; + } + DEBUG(10,("validate_ug: %s ok\n", keystr)); + return 0; +} + static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status *state) { @@ -3881,6 +3912,7 @@ struct key_val_struct { {"CRED/", validate_cred}, {"UL/", validate_ul}, {"GL/", validate_gl}, + {"UG/", validate_ug}, {"UA", validate_ua}, {"GM/", validate_gm}, {"DR/", validate_dr}, -- 1.9.1 From 06f5398c9a6e9c5990c0ee1c5bc731462f83386e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 14:54:23 +0100 Subject: [PATCH 4/9] Revert "winbind: Remove wcache_lookup_usergroups" This reverts commit 876dc28b9cf13343a2962b1a1b035fe78c1858a6. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 52105ebaa82a4a4e0a48dd93c9419c5fd91561a4) --- source3/winbindd/winbindd_cache.c | 59 +++++++++++++++++++++++++++++++++++++++ source3/winbindd/winbindd_proto.h | 5 ++++ 2 files changed, 64 insertions(+) diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index a343ad1..e05e048 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -2320,6 +2320,65 @@ NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain, return NT_STATUS_OK; } +NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *pnum_sids, + struct dom_sid **psids) +{ + struct winbind_cache *cache = get_cache(domain); + struct cache_entry *centry = NULL; + NTSTATUS status; + uint32_t i, num_sids; + struct dom_sid *sids; + fstring sid_string; + + if (cache->tdb == NULL) { + return NT_STATUS_NOT_FOUND; + } + + centry = wcache_fetch(cache, domain, "UG/%s", + sid_to_fstring(sid_string, user_sid)); + if (centry == NULL) { + return NT_STATUS_NOT_FOUND; + } + + /* If we have an access denied cache entry and a cached info3 in the + samlogon cache then do a query. This will force the rpc back end + to return the info3 data. */ + + if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) + && netsamlogon_cache_have(user_sid)) { + DEBUG(10, ("lookup_usergroups: cached access denied and have " + "cached info3\n")); + domain->last_status = NT_STATUS_OK; + centry_free(centry); + return NT_STATUS_NOT_FOUND; + } + + num_sids = centry_uint32(centry); + sids = talloc_array(mem_ctx, struct dom_sid, num_sids); + if (sids == NULL) { + centry_free(centry); + return NT_STATUS_NO_MEMORY; + } + + for (i=0; istatus; + + DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s " + "status: %s\n", domain->name, nt_errstr(status))); + + centry_free(centry); + + *pnum_sids = num_sids; + *psids = sids; + return status; +} + static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids, const struct dom_sid *sids) { diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index d7dec3a..e1ded99 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -169,6 +169,11 @@ NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t num_sids, const struct dom_sid *sids, uint32_t *pnum_aliases, uint32_t **paliases); +NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *pnum_sids, + struct dom_sid **psids); void wcache_flush_cache(void); NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count); -- 1.9.1 From 0c68d7367d5430ce217e983d6e81c8f80890a346 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 14:54:46 +0100 Subject: [PATCH 5/9] Revert "winbind: Remove wb_cache_lookup_usergroups" This reverts commit f83863b4d1510a9519d15934c960fd1675235812. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 55321a39bbb481eac82d4439a3874567bfb0b229) --- source3/winbindd/winbindd_cache.c | 71 +++++++++++++++++++++++++++++++++++++++ source3/winbindd/winbindd_proto.h | 5 +++ 2 files changed, 76 insertions(+) diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index e05e048..5787441 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -2379,6 +2379,77 @@ NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain, return status; } +/* Lookup groups a user is a member of. */ +NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *num_groups, + struct dom_sid **user_gids) +{ + struct cache_entry *centry = NULL; + NTSTATUS status; + unsigned int i; + fstring sid_string; + bool old_status; + + old_status = domain->online; + status = wcache_lookup_usergroups(domain, mem_ctx, user_sid, + num_groups, user_gids); + if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + return status; + } + + (*num_groups) = 0; + (*user_gids) = NULL; + + /* Return status value returned by seq number check */ + + if (!NT_STATUS_IS_OK(domain->last_status)) + return domain->last_status; + + DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n", + domain->name )); + + status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids); + + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) || + NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) { + if (!domain->internal && old_status) { + set_domain_offline(domain); + } + if (!domain->internal && + !domain->online && + old_status) { + NTSTATUS cache_status; + cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid, + num_groups, user_gids); + return cache_status; + } + } + if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) ) + goto skip_save; + + /* and save it */ + refresh_sequence_number(domain); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + centry = centry_start(domain, status); + if (!centry) + goto skip_save; + + centry_put_uint32(centry, *num_groups); + for (i=0; i<(*num_groups); i++) { + centry_put_sid(centry, &(*user_gids)[i]); + } + + centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid)); + centry_free(centry); + +skip_save: + return status; +} + static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids, const struct dom_sid *sids) { diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index e1ded99..ca9897a 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -89,6 +89,11 @@ NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain, char **domain_name, char ***names, enum lsa_SidType **types); +NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *pnum_sids, + struct dom_sid **psids); NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t num_sids, -- 1.9.1 From 86c025f64b6694f256778453458a681a5d7adca7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 14:55:15 +0100 Subject: [PATCH 6/9] Revert "winbind: Remove wbint_LookupUserGroups" This reverts commit 256632ed3cc724bab0fc22132ca6b52faf680ab2. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit a34c0a8638556ddcb8fa30cb5a311330e3f0bbc0) --- librpc/idl/winbind.idl | 5 +++++ source3/winbindd/winbindd_dual_srv.c | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/librpc/idl/winbind.idl b/librpc/idl/winbind.idl index 6245e13..05db6b9 100644 --- a/librpc/idl/winbind.idl +++ b/librpc/idl/winbind.idl @@ -103,6 +103,11 @@ interface winbind [out] wbint_RidArray *rids ); + NTSTATUS wbint_LookupUserGroups( + [in] dom_sid *sid, + [out] wbint_SidArray *sids + ); + NTSTATUS wbint_QuerySequenceNumber( [out] uint32 *sequence ); diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 49236cd..52e8629 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -301,6 +301,23 @@ NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p, return status; } +NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p, + struct wbint_LookupUserGroups *r) +{ + struct winbindd_domain *domain = wb_child_domain(); + NTSTATUS status; + + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid, + &r->out.sids->num_sids, + &r->out.sids->sids); + reset_cm_connection_on_error(domain, status); + return status; +} + NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p, struct wbint_QuerySequenceNumber *r) { -- 1.9.1 From d08929edb30024eedd8eb2e545f5c3d2569656e1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 14:56:09 +0100 Subject: [PATCH 7/9] Revert "winbind: Remove wb_lookupusergroups" This reverts commit c0570e6ae8f8f0057ece48d764580897ff2b6f62. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 1a12cfbf1fbcb3542d9799236ed1a9290550ccc1) --- source3/winbindd/wb_lookupusergroups.c | 97 ++++++++++++++++++++++++++++++++++ source3/winbindd/winbindd_proto.h | 6 +++ source3/winbindd/wscript_build | 1 + 3 files changed, 104 insertions(+) create mode 100644 source3/winbindd/wb_lookupusergroups.c diff --git a/source3/winbindd/wb_lookupusergroups.c b/source3/winbindd/wb_lookupusergroups.c new file mode 100644 index 0000000..2d39692 --- /dev/null +++ b/source3/winbindd/wb_lookupusergroups.c @@ -0,0 +1,97 @@ +/* + Unix SMB/CIFS implementation. + async lookupusergroups + Copyright (C) Volker Lendecke 2009 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/ndr_winbind_c.h" +#include "../libcli/security/security.h" + +struct wb_lookupusergroups_state { + struct tevent_context *ev; + struct dom_sid sid; + struct wbint_SidArray sids; +}; + +static void wb_lookupusergroups_done(struct tevent_req *subreq); + +struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_domain *domain, + const struct dom_sid *sid) +{ + struct tevent_req *req, *subreq; + struct wb_lookupusergroups_state *state; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct wb_lookupusergroups_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->sid, sid); + + status = lookup_usergroups_cached(state, + &state->sid, + &state->sids.num_sids, + &state->sids.sids); + if (NT_STATUS_IS_OK(status)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = dcerpc_wbint_LookupUserGroups_send( + state, ev, dom_child_handle(domain), &state->sid, &state->sids); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_lookupusergroups_done, req); + return req; +} + +static void wb_lookupusergroups_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_lookupusergroups_state *state = tevent_req_data( + req, struct wb_lookupusergroups_state); + NTSTATUS status, result; + + status = dcerpc_wbint_LookupUserGroups_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (any_nt_status_not_ok(status, result, &status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_lookupusergroups_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + int *num_sids, struct dom_sid **sids) +{ + struct wb_lookupusergroups_state *state = tevent_req_data( + req, struct wb_lookupusergroups_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *num_sids = state->sids.num_sids; + *sids = talloc_move(mem_ctx, &state->sids.sids); + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index ca9897a..0faf0c6 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -663,6 +663,12 @@ struct tevent_req *winbindd_getsidaliases_send(TALLOC_CTX *mem_ctx, struct winbindd_request *request); NTSTATUS winbindd_getsidaliases_recv(struct tevent_req *req, struct winbindd_response *response); +struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_domain *domain, + const struct dom_sid *sid); +NTSTATUS wb_lookupusergroups_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + int *num_sids, struct dom_sid **sids); struct tevent_req *winbindd_getuserdomgroups_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/source3/winbindd/wscript_build b/source3/winbindd/wscript_build index a5d0dd6..51264e9 100644 --- a/source3/winbindd/wscript_build +++ b/source3/winbindd/wscript_build @@ -206,6 +206,7 @@ bld.SAMBA3_BINARY('winbindd', wb_xids2sids.c wb_queryuser.c wb_lookupuseraliases.c + wb_lookupusergroups.c wb_getpwsid.c wb_gettoken.c wb_seqnum.c -- 1.9.1 From 501d5d9167b470d60d5e2be20c968ce6dac330ec Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 6 Mar 2017 10:30:52 +0100 Subject: [PATCH 8/9] winbindd: find the domain based on the sid within wb_lookupusergroups_send() That simplifies the potential caller. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke Reviewed-by: Ralph Boehme (cherry picked from commit 76d94838049b77555cdf7dad2d15692cb18b4dab) --- source3/winbindd/wb_lookupusergroups.c | 11 ++++++++++- source3/winbindd/winbindd_proto.h | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/wb_lookupusergroups.c b/source3/winbindd/wb_lookupusergroups.c index 2d39692..7647fbd 100644 --- a/source3/winbindd/wb_lookupusergroups.c +++ b/source3/winbindd/wb_lookupusergroups.c @@ -32,11 +32,11 @@ static void wb_lookupusergroups_done(struct tevent_req *subreq); struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct winbindd_domain *domain, const struct dom_sid *sid) { struct tevent_req *req, *subreq; struct wb_lookupusergroups_state *state; + struct winbindd_domain *domain; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, @@ -55,6 +55,15 @@ struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } + domain = find_domain_from_sid_noinit(&state->sid); + if (domain == NULL) { + char buf[DOM_SID_STR_BUFLEN]; + dom_sid_string_buf(&state->sid, buf, sizeof(buf)); + DEBUG(1,("could not find domain entry for sid %s\n", buf)); + tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN); + return tevent_req_post(req, ev); + } + subreq = dcerpc_wbint_LookupUserGroups_send( state, ev, dom_child_handle(domain), &state->sid, &state->sids); if (tevent_req_nomem(subreq, req)) { diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 0faf0c6..46fb600 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -665,7 +665,6 @@ NTSTATUS winbindd_getsidaliases_recv(struct tevent_req *req, struct winbindd_response *response); struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct winbindd_domain *domain, const struct dom_sid *sid); NTSTATUS wb_lookupusergroups_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, int *num_sids, struct dom_sid **sids); -- 1.9.1 From 5fe0984ba92a8670ca33474232b213b30d387a65 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 15:14:51 +0100 Subject: [PATCH 9/9] Re-enable token groups fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG: https://bugzilla.samba.org/show_bug.cgi?id=12612 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Mon Mar 6 19:18:31 CET 2017 on sn-devel-144 (cherry picked from commit 6296c32668af60118ae7059772d2f70e58e1f0d1) Autobuild-User(v4-6-test): Stefan Metzmacher Autobuild-Date(v4-6-test): Mon Mar 6 23:31:52 CET 2017 on sn-devel-144 --- source3/winbindd/wb_gettoken.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/source3/winbindd/wb_gettoken.c b/source3/winbindd/wb_gettoken.c index 07c7fc7..a393b0f 100644 --- a/source3/winbindd/wb_gettoken.c +++ b/source3/winbindd/wb_gettoken.c @@ -38,6 +38,7 @@ static NTSTATUS wb_add_rids_to_sids(TALLOC_CTX *mem_ctx, int num_rids, uint32_t *rids); static void wb_gettoken_gotuser(struct tevent_req *subreq); +static void wb_gettoken_gotgroups(struct tevent_req *subreq); static void wb_gettoken_gotlocalgroups(struct tevent_req *subreq); static void wb_gettoken_gotbuiltins(struct tevent_req *subreq); @@ -71,10 +72,7 @@ static void wb_gettoken_gotuser(struct tevent_req *subreq) subreq, struct tevent_req); struct wb_gettoken_state *state = tevent_req_data( req, struct wb_gettoken_state); - struct winbindd_domain *domain; struct wbint_userinfo *info; - uint32_t i, num_groups; - struct dom_sid *groups; NTSTATUS status; status = wb_queryuser_recv(subreq, state, &info); @@ -92,11 +90,27 @@ static void wb_gettoken_gotuser(struct tevent_req *subreq) sid_copy(&state->sids[0], &info->user_sid); sid_copy(&state->sids[1], &info->group_sid); - status = lookup_usergroups_cached( - state, &info->user_sid, &num_groups, &groups); + subreq = wb_lookupusergroups_send(state, state->ev, &info->user_sid); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_gettoken_gotgroups, req); +} + +static void wb_gettoken_gotgroups(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_gettoken_state *state = tevent_req_data( + req, struct wb_gettoken_state); + int i, num_groups; + struct dom_sid *groups; + struct winbindd_domain *domain; + NTSTATUS status; + + status = wb_lookupusergroups_recv(subreq, state, &num_groups, &groups); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - DBG_DEBUG("lookup_usergroups_cached failed (%s), not doing " - "supplementary group lookups\n", nt_errstr(status)); tevent_req_done(req); return; } -- 1.9.1