summaryrefslogtreecommitdiffstats
path: root/src/db/sysdb_sudo.c
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2012-02-07 14:08:55 +0100
committerStephen Gallagher <sgallagh@redhat.com>2012-02-17 11:10:07 -0500
commitf5d4b05027acce06e3509ecb68869d1c7ef37180 (patch)
treededc9568ef72c85e3e3ac640854dcd0fa37e67db /src/db/sysdb_sudo.c
parent52ec1ebb88a1335500c4ae1c40bf973dd59d3349 (diff)
downloadsssd-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.c372
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;
}
+