From 4611802d41d8954a3040f39403590adb920ca521 Mon Sep 17 00:00:00 2001 From: Yassir Elley Date: Tue, 9 Sep 2014 15:37:05 -0400 Subject: AD-GPO resolve conflicting policy settings correctly Resolves: https://fedorahosted.org/sssd/ticket/2437 Reviewed-by: Stephen Gallagher --- src/db/sysdb.h | 29 ++++- src/db/sysdb_gpo.c | 357 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 331 insertions(+), 55 deletions(-) (limited to 'src/db') diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 901b6129b..81b39252c 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -876,6 +876,8 @@ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx, #define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom" +/* === Functions related to GPO entries === */ + #define SYSDB_GPO_OC "gpo" #define SYSDB_GPO_FILTER "(objectClass="SYSDB_GPO_OC")" #define SYSDB_GPO_GUID_FILTER "(&(objectClass="SYSDB_GPO_OC")("SYSDB_GPO_GUID_ATTR"=%s))" @@ -908,9 +910,28 @@ errno_t sysdb_gpo_get_gpos(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, struct ldb_result **_result); -errno_t sysdb_gpo_delete_stale_gpos(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char **gpo_guid_list, - int num_gpos); +/* === Functions related to GPO Result object === */ + +#define SYSDB_GPO_RESULT_OC "gpo_result" +#define SYSDB_GPO_RESULT_FILTER "(objectClass="SYSDB_GPO_RESULT_OC")" + +#define SYSDB_TMPL_GPO_RESULT_BASE SYSDB_GPO_CONTAINER","SYSDB_DOM_BASE +#define SYSDB_TMPL_GPO_RESULT "cn=%s,"SYSDB_TMPL_GPO_RESULT_BASE + +errno_t sysdb_gpo_get_gpo_result_object(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_result **_result); + +errno_t sysdb_gpo_delete_gpo_result_object(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain); + +errno_t sysdb_gpo_store_gpo_result_setting(struct sss_domain_info *domain, + const char *policy_setting_key, + const char *policy_setting_value); + +errno_t sysdb_gpo_get_gpo_result_setting(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *policy_setting_key, + const char **policy_setting_value); #endif /* __SYS_DB_H__ */ diff --git a/src/db/sysdb_gpo.c b/src/db/sysdb_gpo.c index e0b9bb9f0..92559d41e 100644 --- a/src/db/sysdb_gpo.c +++ b/src/db/sysdb_gpo.c @@ -37,7 +37,7 @@ sysdb_gpo_dn(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, return NULL; } - DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO"\n", clean_gpo_guid, domain->name); + DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO"\n", clean_gpo_guid, domain->name); dn = ldb_dn_new_fmt(mem_ctx, domain->sysdb->ldb, SYSDB_TMPL_GPO, clean_gpo_guid, domain->name); @@ -172,8 +172,7 @@ sysdb_gpo_store_gpo(struct sss_domain_info *domain, } else if (ret == EOK && count == 1) { /* Update the existing GPO */ - DEBUG(SSSDBG_TRACE_FUNC, - "Updating new GPO [%s][%s]\n", domain->name, gpo_guid); + DEBUG(SSSDBG_TRACE_ALL, "Updating new GPO [%s][%s]\n", domain->name, gpo_guid); /* Add the Version */ lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_VERSION_ATTR, @@ -254,7 +253,7 @@ sysdb_gpo_get_gpo_by_guid(TALLOC_CTX *mem_ctx, tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return ENOMEM; - DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO_BASE"\n", domain->name); + DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_BASE"\n", domain->name); base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_TMPL_GPO_BASE, @@ -313,7 +312,7 @@ sysdb_gpo_get_gpos(TALLOC_CTX *mem_ctx, tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return ENOMEM; - DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO_BASE"\n", domain->name); + DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_BASE"\n", domain->name); base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_TMPL_GPO_BASE, @@ -353,32 +352,59 @@ done: return ret; } -static inline bool -sysdb_gpo_guid_in_list(const char **gpo_guid_list, int num_gpos, const char *gpo_guid) +/* GPO Result */ + +static struct ldb_dn * +sysdb_gpo_result_dn(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *result_name) { - size_t i; + errno_t ret; + char *clean_result_name; + struct ldb_dn *dn; - for (i = 0; i < num_gpos; i++) { - if (strcasecmp(gpo_guid_list[i], gpo_guid) == 0) { - break; - } + ret = sysdb_dn_sanitize(NULL, result_name, &clean_result_name); + if (ret != EOK) { + return NULL; } - return (i < num_gpos) ? true : false; + DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_RESULT"\n", + clean_result_name, domain->name); + + dn = ldb_dn_new_fmt(mem_ctx, domain->sysdb->ldb, SYSDB_TMPL_GPO_RESULT, + clean_result_name, domain->name); + talloc_free(clean_result_name); + + return dn; } errno_t -sysdb_gpo_delete_stale_gpos(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char **gpo_guid_list, - int num_gpos) +sysdb_gpo_store_gpo_result_setting(struct sss_domain_info *domain, + const char *ini_key, + const char *ini_value) { - struct ldb_result *res; errno_t ret, sret; - int i; + int lret; + struct ldb_message *update_msg; + struct ldb_message **msgs; + size_t count; bool in_transaction = false; - const char *cached_gpo_guid; - bool stale_gpo_found = false; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + update_msg = ldb_msg_new(tmp_ctx); + if (!update_msg) { + ret = ENOMEM; + goto done; + } + + update_msg->dn = sysdb_gpo_result_dn(update_msg, domain, "gpo_result"); + if (!update_msg->dn) { + ret = ENOMEM; + goto done; + } ret = sysdb_transaction_start(domain->sysdb); if (ret != EOK) { @@ -388,43 +414,272 @@ sysdb_gpo_delete_stale_gpos(TALLOC_CTX *mem_ctx, in_transaction = true; - ret = sysdb_gpo_get_gpos(mem_ctx, domain, &res); - if (ret != EOK && ret != ENOENT) { - goto done; - } else if (ret != ENOENT) { - for (i = 0; i < res->count; i++) { - cached_gpo_guid = ldb_msg_find_attr_as_string(res->msgs[i], - SYSDB_GPO_GUID_ATTR, - NULL); - if (cached_gpo_guid == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "No gpo_guid attribute found in gpo cache entry\n"); - ret = EFAULT; + /* Check for an existing GPO Result object */ + ret = sysdb_search_entry(tmp_ctx, domain->sysdb, update_msg->dn, + LDB_SCOPE_BASE, NULL, NULL, &count, &msgs); + + if (ret == ENOENT) { + /* Create new GPO Result object */ + DEBUG(SSSDBG_TRACE_FUNC, "Storing setting: key [%s] value [%s]\n", + ini_key, ini_value); + + /* Add the objectClass */ + lret = ldb_msg_add_empty(update_msg, SYSDB_OBJECTCLASS, + LDB_FLAG_MOD_ADD, + NULL); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; + } + + lret = ldb_msg_add_string(update_msg, SYSDB_OBJECTCLASS, + SYSDB_GPO_RESULT_OC); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; + } + + /* Store the policy_setting if it is non-NULL */ + if (ini_value) { + lret = ldb_msg_add_empty(update_msg, ini_key, + LDB_FLAG_MOD_ADD, + NULL); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; + } + + lret = ldb_msg_add_string(update_msg, ini_key, ini_value); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; + } + } + + lret = ldb_add(domain->sysdb->ldb, update_msg); + if (lret != LDB_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to add GPO Result: [%s]\n", + ldb_strerror(lret)); + ret = sysdb_error_to_errno(lret); + goto done; + } + } else if (ret == EOK && count == 1) { + /* Update existing GPO Result object*/ + if (ini_value) { + DEBUG(SSSDBG_TRACE_FUNC, "Updating setting: key [%s] value [%s]\n", + ini_key, ini_value); + /* Update the policy setting */ + lret = ldb_msg_add_empty(update_msg, ini_key, + LDB_FLAG_MOD_REPLACE, + NULL); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); goto done; } - if (sysdb_gpo_guid_in_list(gpo_guid_list, num_gpos, cached_gpo_guid)) { - /* the cached_gpo_guid is still applicable, skip it */ - continue; - } else { - stale_gpo_found = true; - /* the cached_gpo_guid is no longer applicable, delete it */ - DEBUG(SSSDBG_TRACE_FUNC, "Deleting stale GPO [gpo_guid:%s]\n", - cached_gpo_guid); - - ret = sysdb_delete_entry(domain->sysdb, res->msgs[i]->dn, true); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Could not delete GPO cache entry [gpo_guid:%s]\n", - cached_gpo_guid); - goto done; - } + lret = ldb_msg_add_fmt(update_msg, ini_key, "%s", ini_value); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; } + } else { + /* If the value is NULL, we need to remove it from the cache */ + DEBUG(SSSDBG_TRACE_FUNC, "Removing setting: key [%s]\n", ini_key); + + /* Update the policy setting */ + lret = ldb_msg_add_empty(update_msg, ini_key, + LDB_FLAG_MOD_DELETE, + NULL); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; + } + } + + lret = ldb_modify(domain->sysdb->ldb, update_msg); + if (lret != LDB_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to modify GPO Result: [%s]\n", ldb_strerror(lret)); + ret = sysdb_error_to_errno(lret); + goto done; } + } else { + ret = EIO; + goto done; } - if (!stale_gpo_found) { - DEBUG(SSSDBG_TRACE_FUNC, "No stale GPOs found\n"); + ret = sysdb_transaction_commit(domain->sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not commit transaction: [%s]\n", strerror(ret)); + goto done; + } + in_transaction = false; + +done: + if (in_transaction) { + sret = sysdb_transaction_cancel(domain->sysdb); + if (sret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n"); + } + } + talloc_free(tmp_ctx); + return ret; +} + +errno_t +sysdb_gpo_get_gpo_result_setting(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *ini_key, + const char **_ini_value) +{ + errno_t ret; + int lret; + struct ldb_dn *base_dn; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + const char *ini_value; + + const char *attrs[] = {ini_key, NULL}; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_RESULT_BASE"\n", domain->name); + + base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, + SYSDB_TMPL_GPO_RESULT_BASE, + domain->name); + if (!base_dn) { + ret = ENOMEM; + goto done; + } + + lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn, + LDB_SCOPE_SUBTREE, attrs, SYSDB_GPO_RESULT_FILTER); + if (lret) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not locate GPO Result: [%s]\n", + ldb_strerror(lret)); + ret = sysdb_error_to_errno(lret); + goto done; + } + + if (res->count == 0) { + ret = ENOENT; + goto done; + } + + ini_value = ldb_msg_find_attr_as_string(res->msgs[0], + ini_key, + NULL); + DEBUG(SSSDBG_TRACE_FUNC, "key [%s] value [%s]\n", ini_key, ini_value); + + *_ini_value = talloc_strdup(mem_ctx, ini_value); + if (!*_ini_value && ini_value) { + /* If ini_value was NULL, this is expected to also be NULL */ + ret = ENOMEM; + goto done; + } + + ret = EOK; + +done: + + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_ALL, "No setting for key [%s].\n", ini_key); + } else if (ret) { + DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret)); + } + + talloc_free(tmp_ctx); + return ret; +} + + +errno_t +sysdb_gpo_get_gpo_result_object(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_result **_result) +{ + errno_t ret; + int lret; + struct ldb_dn *base_dn; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_RESULT_BASE"\n", domain->name); + + base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, + SYSDB_TMPL_GPO_RESULT_BASE, + domain->name); + if (!base_dn) { + ret = ENOMEM; + goto done; + } + + lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn, + LDB_SCOPE_SUBTREE, NULL, SYSDB_GPO_RESULT_FILTER); + if (lret) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not locate GPO Result object: [%s]\n", + ldb_strerror(lret)); + ret = sysdb_error_to_errno(lret); + goto done; + } + + if (res->count == 0) { + ret = ENOENT; + goto done; + } + + *_result = talloc_steal(mem_ctx, res); + ret = EOK; + +done: + + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_ALL, "No GPO Result object.\n"); + } else if (ret) { + DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret)); + } + + talloc_free(tmp_ctx); + return ret; +} + + +errno_t sysdb_gpo_delete_gpo_result_object(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain) +{ + struct ldb_result *res; + errno_t ret, sret; + bool in_transaction = false; + + ret = sysdb_transaction_start(domain->sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); + goto done; + } + + in_transaction = true; + + ret = sysdb_gpo_get_gpo_result_object(mem_ctx, domain, &res); + if (ret != EOK && ret != ENOENT) { + goto done; + } else if (ret != ENOENT) { + DEBUG(SSSDBG_TRACE_FUNC, "Deleting GPO Result object\n"); + + ret = sysdb_delete_entry(domain->sysdb, res->msgs[0]->dn, true); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not delete GPO Result cache entry\n"); + goto done; + } } ret = sysdb_transaction_commit(domain->sysdb); -- cgit