diff options
author | Pavel Březina <pbrezina@redhat.com> | 2012-02-07 14:08:55 +0100 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2012-02-17 11:10:07 -0500 |
commit | f5d4b05027acce06e3509ecb68869d1c7ef37180 (patch) | |
tree | dedc9568ef72c85e3e3ac640854dcd0fa37e67db /src/db/sysdb_sudo.c | |
parent | 52ec1ebb88a1335500c4ae1c40bf973dd59d3349 (diff) | |
download | sssd-f5d4b05027acce06e3509ecb68869d1c7ef37180.tar.gz sssd-f5d4b05027acce06e3509ecb68869d1c7ef37180.tar.xz sssd-f5d4b05027acce06e3509ecb68869d1c7ef37180.zip |
Redesign purging of the sudo cache
https://fedorahosted.org/sssd/ticket/1173
Diffstat (limited to 'src/db/sysdb_sudo.c')
-rw-r--r-- | src/db/sysdb_sudo.c | 372 |
1 files changed, 301 insertions, 71 deletions
diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c index 84245d53..f579ba8b 100644 --- a/src/db/sysdb_sudo.c +++ b/src/db/sysdb_sudo.c @@ -339,33 +339,6 @@ done: return EOK; } -static errno_t -sysdb_sudo_purge_subdir(struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *subdir) -{ - struct ldb_dn *base_dn = NULL; - TALLOC_CTX *tmp_ctx = NULL; - errno_t ret; - - tmp_ctx = talloc_new(NULL); - NULL_CHECK(tmp_ctx, ret, done); - - base_dn = sysdb_custom_subtree_dn(sysdb, tmp_ctx, domain->name, subdir); - NULL_CHECK(base_dn, ret, done); - - ret = sysdb_delete_recursive(sysdb, base_dn, true); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("sysdb_delete_recursive failed.\n")); - goto done; - } - - ret = EOK; -done: - talloc_free(tmp_ctx); - return EOK; -} - errno_t sysdb_save_sudorule(struct sysdb_ctx *sysdb_ctx, const char *rule_name, @@ -400,10 +373,150 @@ sysdb_save_sudorule(struct sysdb_ctx *sysdb_ctx, return EOK; } -errno_t -sysdb_purge_sudorule_subtree(struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *filter) +errno_t sysdb_sudo_set_refreshed(struct sysdb_ctx *sysdb, + bool refreshed) +{ + errno_t ret; + struct ldb_dn *dn; + TALLOC_CTX *tmp_ctx; + + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + ret = ENOMEM; + goto done; + } + + dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE, + SUDORULE_SUBDIR, sysdb->domain->name); + if (!dn) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_set_bool(sysdb, dn, SUDORULE_SUBDIR, + SYSDB_SUDO_AT_REFRESHED, refreshed); + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t sysdb_sudo_get_refreshed(struct sysdb_ctx *sysdb, + bool *refreshed) +{ + errno_t ret; + struct ldb_dn *dn; + TALLOC_CTX *tmp_ctx; + + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + ret = ENOMEM; + goto done; + } + + dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE, + SUDORULE_SUBDIR, sysdb->domain->name); + if (!dn) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_get_bool(sysdb, dn, SYSDB_SUDO_AT_REFRESHED, refreshed); + +done: + talloc_free(tmp_ctx); + return ret; +} + +char **sysdb_sudo_build_sudouser(TALLOC_CTX *mem_ctx, const char *username, + uid_t uid, char **groupnames, bool include_all) +{ + char **sudouser = NULL; + int count = 0; + errno_t ret; + int i; + + if (username == NULL || uid == 0) { + return NULL; + } + + count = include_all ? 3 : 2; + sudouser = talloc_array(NULL, char*, count + 1); + NULL_CHECK(sudouser, ret, done); + + sudouser[0] = talloc_strdup(sudouser, username); + NULL_CHECK(sudouser[0], ret, done); + + sudouser[1] = talloc_asprintf(sudouser, "#%llu", (unsigned long long)uid); + NULL_CHECK(sudouser[1], ret, done); + + if (include_all) { + sudouser[2] = talloc_strdup(sudouser, "ALL"); + NULL_CHECK(sudouser[2], ret, done); + } + + if (groupnames != NULL) { + for (i = 0; groupnames[i] != NULL; i++) { + count++; + sudouser = talloc_realloc(NULL, sudouser, char*, count + 1); + NULL_CHECK(sudouser, ret, done); + + sudouser[count - 1] = talloc_asprintf(sudouser, "%s", groupnames[i]); + NULL_CHECK(sudouser[count - 1], ret, done); + } + } + + sudouser[count] = NULL; + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(sudouser); + return NULL; + } + + return talloc_steal(mem_ctx, sudouser); +} + +/* ==================== Purge functions ==================== */ + +errno_t sysdb_sudo_purge_all(struct sysdb_ctx *sysdb) +{ + struct ldb_dn *base_dn = NULL; + TALLOC_CTX *tmp_ctx = NULL; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + NULL_CHECK(tmp_ctx, ret, done); + + base_dn = sysdb_custom_subtree_dn(sysdb, tmp_ctx, sysdb->domain->name, + SUDORULE_SUBDIR); + NULL_CHECK(base_dn, ret, done); + + ret = sysdb_delete_recursive(sysdb, base_dn, true); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_delete_recursive failed.\n")); + goto done; + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + return EOK; +} + +errno_t sysdb_sudo_purge_byname(struct sysdb_ctx *sysdb, + const char *name) +{ + DEBUG(SSSDBG_TRACE_INTERNAL, ("Deleting sudo rule %s\n", name)); + return sysdb_delete_custom(sysdb, name, SUDORULE_SUBDIR); +} + +errno_t sysdb_sudo_purge_byfilter(struct sysdb_ctx *sysdb, + const char *filter) { TALLOC_CTX *tmp_ctx; size_t count; @@ -411,6 +524,8 @@ sysdb_purge_sudorule_subtree(struct sysdb_ctx *sysdb, const char *name; int i; errno_t ret; + errno_t sret; + bool in_transaction = false; const char *attrs[] = { SYSDB_OBJECTCLASS, SYSDB_NAME, SYSDB_SUDO_CACHE_AT_OC, @@ -419,7 +534,7 @@ sysdb_purge_sudorule_subtree(struct sysdb_ctx *sysdb, /* just purge all if there's no filter */ if (!filter) { - return sysdb_sudo_purge_subdir(sysdb, domain, SUDORULE_SUBDIR); + return sysdb_sudo_purge_all(sysdb); } tmp_ctx = talloc_new(NULL); @@ -429,15 +544,21 @@ sysdb_purge_sudorule_subtree(struct sysdb_ctx *sysdb, ret = sysdb_search_custom(tmp_ctx, sysdb, filter, SUDORULE_SUBDIR, attrs, &count, &msgs); - if (ret != EOK && ret != ENOENT) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up SUDO rules")); - goto done; - } if (ret == ENOENT) { + if (ret == ENOENT) { DEBUG(SSSDBG_TRACE_FUNC, ("No rules matched\n")); ret = EOK; goto done; + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up SUDO rules")); + goto done; } + ret = sysdb_transaction_start(sysdb); + if (ret != EOK) { + goto done; + } + in_transaction = true; + for (i = 0; i < count; i++) { name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); if (name == NULL) { @@ -446,72 +567,181 @@ sysdb_purge_sudorule_subtree(struct sysdb_ctx *sysdb, continue; } - ret = sysdb_delete_custom(sysdb, name, SUDORULE_SUBDIR); + ret = sysdb_sudo_purge_byname(sysdb, name); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not delete rule %s\n", name)); goto done; } } - ret = EOK; + ret = sysdb_transaction_commit(sysdb); + if (ret == EOK) { + in_transaction = false; + } + done: + if (in_transaction) { + sret = sysdb_transaction_cancel(sysdb); + if (sret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n")); + } + } + talloc_free(tmp_ctx); return ret; } -errno_t sysdb_sudo_set_refreshed(struct sysdb_ctx *sysdb, - bool refreshed) +errno_t sysdb_sudo_purge_bysudouser(struct sysdb_ctx *sysdb, + char **sudouser) { + TALLOC_CTX *tmp_ctx = NULL; + char *filter = NULL; + char *value = NULL; + const char *rule_name = NULL; + struct ldb_message_element *attr = NULL; + struct ldb_message *msg = NULL; + struct ldb_message **rules = NULL; + size_t num_rules; errno_t ret; - struct ldb_dn *dn; - TALLOC_CTX *tmp_ctx; + errno_t sret; + int lret; + int i, j, k; + bool in_transaction = false; + const char *attrs[] = { SYSDB_OBJECTCLASS, + SYSDB_NAME, + SYSDB_SUDO_CACHE_AT_USER, + NULL }; + if (sudouser == NULL || sudouser[0] == NULL) { + return EOK; + } tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - ret = ENOMEM; + NULL_CHECK(tmp_ctx, ret, done); + + /* create search filter */ + filter = talloc_strdup(tmp_ctx, "(|"); + NULL_CHECK(filter, ret, done); + for (i = 0; sudouser[i] != NULL; i++) { + filter = talloc_asprintf_append(filter, "(%s=%s)", + SYSDB_SUDO_CACHE_AT_USER, sudouser[i]); + NULL_CHECK(filter, ret, done); + } + filter = talloc_strdup_append(filter, ")"); + NULL_CHECK(filter, ret, done); + + /* search the rules */ + ret = sysdb_search_custom(tmp_ctx, sysdb, filter, SUDORULE_SUBDIR, attrs, + &num_rules, &rules); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up SUDO rules")); + goto done; + } if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_FUNC, ("No rules matched\n")); + ret = EOK; goto done; } - dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE, - SUDORULE_SUBDIR, sysdb->domain->name); - if (!dn) { - ret = ENOMEM; + ret = sysdb_transaction_start(sysdb); + if (ret != EOK) { goto done; } + in_transaction = true; - ret = sysdb_set_bool(sysdb, dn, SUDORULE_SUBDIR, - SYSDB_SUDO_AT_REFRESHED, refreshed); + /* + * remove values from sudoUser and delete the rule + * if the attribute is empty afterwards + */ -done: - talloc_free(tmp_ctx); - return ret; -} + for (i = 0; i < num_rules; i++) { + /* find name */ + rule_name = ldb_msg_find_attr_as_string(rules[i], SYSDB_NAME, NULL); + if (rule_name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("A rule without a name?\n")); + /* skip this one but still delete other entries */ + continue; + } -errno_t sysdb_sudo_get_refreshed(struct sysdb_ctx *sysdb, - bool *refreshed) -{ - errno_t ret; - struct ldb_dn *dn; - TALLOC_CTX *tmp_ctx; + /* find sudoUser */ + attr = ldb_msg_find_element(rules[i], SYSDB_SUDO_CACHE_AT_USER); + if (attr == NULL) { + /* this should never happen because we search by this attribute */ + DEBUG(SSSDBG_CRIT_FAILURE, ("BUG: sudoUser attribute is missing\n")); + continue; + } + /* create message */ + msg = ldb_msg_new(tmp_ctx); + NULL_CHECK(msg, ret, done); - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - ret = ENOMEM; - goto done; - } + msg->dn = ldb_dn_new_fmt(msg, sysdb->ldb, SYSDB_TMPL_CUSTOM, rule_name, + SUDORULE_SUBDIR, sysdb->domain->name); + NULL_CHECK(msg->dn, ret, done); - dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE, - SUDORULE_SUBDIR, sysdb->domain->name); - if (!dn) { - ret = ENOMEM; - goto done; + /* create empty sudoUser */ + lret = ldb_msg_add_empty(msg, SYSDB_SUDO_CACHE_AT_USER, + LDB_FLAG_MOD_DELETE, NULL); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; + } + + /* filter values */ + for (j = 0; j < attr->num_values; j++) { + value = (char*)(attr->values[j].data); + for (k = 0; sudouser[k] != NULL; k++) { + if (strcmp(value, sudouser[k]) == 0) { + /* delete value from cache */ + lret = ldb_msg_add_string(msg, SYSDB_SUDO_CACHE_AT_USER, + sudouser[k]); + if (lret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(lret); + goto done; + } + break; + } + } + } + + /* update the cache */ + if (msg->elements[0].num_values == attr->num_values) { + /* sudoUser would remain empty, delete the rule */ + ret = sysdb_sudo_purge_byname(sysdb, rule_name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not delete rule %s\n", + rule_name)); + goto done; + } + } else { + /* sudoUser will not be empty, modify the rule */ + DEBUG(SSSDBG_TRACE_INTERNAL, ("Modifying sudoUser of rule %s\n", + rule_name)); + lret = ldb_modify(sysdb->ldb, msg); + if (lret != LDB_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not modify rule %s\n", + rule_name)); + ret = sysdb_error_to_errno(lret); + goto done; + } + } + + talloc_free(msg); } - ret = sysdb_get_bool(sysdb, dn, SYSDB_SUDO_AT_REFRESHED, refreshed); + ret = sysdb_transaction_commit(sysdb); + if (ret == EOK) { + in_transaction = false; + } done: + if (in_transaction) { + sret = sysdb_transaction_cancel(sysdb); + if (sret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n")); + } + } + talloc_free(tmp_ctx); return ret; } + |