/* Authors: Jakub Hrozek Copyright (C) 2011 Red Hat 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 "config.h" #include #include #include "db/sysdb.h" #include "db/sysdb_private.h" #include "db/sysdb_sudo.h" #define SUDO_ALL_FILTER "(" SYSDB_OBJECTCLASS "=" SYSDB_SUDO_CACHE_OC ")" #define NULL_CHECK(val, rval, label) do { \ if (!val) { \ rval = ENOMEM; \ goto label; \ } \ } while(0) /* ==================== Utility functions ==================== */ static errno_t sysdb_sudo_convert_time(const char *str, time_t *unix_time) { struct tm tm; char *tret = NULL; /* SUDO requires times to be in generalized time format: * YYYYMMDDHHMMSS[.|,fraction][(+|-HHMM)|Z] * * We need to use more format strings to parse this with strptime(). */ const char **format = NULL; const char *formats[] = {"%Y%m%d%H%M%SZ", /* 201212121300Z */ "%Y%m%d%H%M%S%z", /* 201212121300+-0200 */ "%Y%m%d%H%M%S.0Z", "%Y%m%d%H%M%S.0%z", "%Y%m%d%H%M%S,0Z", "%Y%m%d%H%M%S,0%z", NULL}; for (format = formats; *format != NULL; format++) { /* strptime() may leave some fields uninitialized */ memset(&tm, 0, sizeof(struct tm)); tret = strptime(str, *format, &tm); if (tret != NULL && *tret == '\0') { *unix_time = mktime(&tm); return EOK; } } return EINVAL; } static errno_t sysdb_sudo_check_time(struct sysdb_attrs *rule, time_t now, bool *result) { TALLOC_CTX *tmp_ctx = NULL; const char **values = NULL; const char *name = NULL; time_t notBefore = 0; time_t notAfter = 0; time_t converted; errno_t ret; int i; if (!result) return EINVAL; *result = false; tmp_ctx = talloc_new(NULL); NULL_CHECK(tmp_ctx, ret, done); ret = sysdb_attrs_get_string(rule, SYSDB_SUDO_CACHE_AT_CN, &name); if (ret == ENOENT) { name = ""; } else if(ret != EOK) { goto done; } /* * From man sudoers.ldap: * * If multiple sudoNotBefore entries are present, the *earliest* is used. * If multiple sudoNotAfter entries are present, the *last one* is used. * * From sudo sources, ldap.c: * If either the sudoNotAfter or sudoNotBefore attributes are missing, * no time restriction shall be imposed. */ /* check for sudoNotBefore */ ret = sysdb_attrs_get_string_array(rule, SYSDB_SUDO_CACHE_AT_NOTBEFORE, tmp_ctx, &values); if (ret == EOK) { for (i=0; values[i] ; i++) { ret = sysdb_sudo_convert_time(values[i], &converted); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Invalid time format in rule [%s]!\n", name); goto done; } /* Grab the earliest */ if (!notBefore) { notBefore = converted; } else if (notBefore > converted) { notBefore = converted; } } } else if (ret != ENOENT) { goto done; } /* check for sudoNotAfter */ ret = sysdb_attrs_get_string_array(rule, SYSDB_SUDO_CACHE_AT_NOTAFTER, tmp_ctx, &values); if (ret == EOK) { for (i=0; values[i] ; i++) { ret = sysdb_sudo_convert_time(values[i], &converted); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Invalid time format in rule [%s]!\n", name); goto done; } /* Grab the latest */ if (!notAfter) { notAfter = converted; } else if (notAfter < converted) { notAfter = converted; } } } else if (ret != ENOENT) { goto done; } if ((notBefore == 0 || now >= notBefore) && (notAfter == 0 || now <= notAfter)) { *result = true; } if (*result) { DEBUG(SSSDBG_TRACE_ALL, "Rule [%s] matches time restrictions\n", name); } else { DEBUG(SSSDBG_TRACE_ALL, "Rule [%s] does not match time " "restrictions\n", name); } ret = EOK; done: talloc_free(tmp_ctx); return ret; } errno_t sysdb_sudo_filter_rules_by_time(TALLOC_CTX *mem_ctx, uint32_t in_num_rules, struct sysdb_attrs **in_rules, time_t now, uint32_t *_num_rules, struct sysdb_attrs ***_rules) { uint32_t num_rules = 0; struct sysdb_attrs **rules = NULL; TALLOC_CTX *tmp_ctx = NULL; bool allowed = false; errno_t ret; int i; tmp_ctx = talloc_new(NULL); NULL_CHECK(tmp_ctx, ret, done); if (now == 0) { now = time(NULL); } for (i = 0; i < in_num_rules; i++) { ret = sysdb_sudo_check_time(in_rules[i], now, &allowed); if (ret == EOK && allowed) { num_rules++; rules = talloc_realloc(tmp_ctx, rules, struct sysdb_attrs *, num_rules); NULL_CHECK(rules, ret, done); rules[num_rules - 1] = in_rules[i]; } } *_num_rules = num_rules; *_rules = talloc_steal(mem_ctx, rules); ret = EOK; done: talloc_free(tmp_ctx); return ret; } static char * sysdb_sudo_filter_userinfo(TALLOC_CTX *mem_ctx, const char *username, char **groupnames, uid_t uid) { const char *attr = SYSDB_SUDO_CACHE_AT_USER; TALLOC_CTX *tmp_ctx; char *sanitized_name; char *filter; errno_t ret; int i; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { return NULL; } filter = talloc_asprintf(tmp_ctx, "(%s=ALL)", attr); if (filter == NULL) { ret = ENOMEM; goto done; } ret = sss_filter_sanitize(tmp_ctx, username, &sanitized_name); if (ret != EOK) { goto done; } filter = talloc_asprintf_append(filter, "(%s=%s)", attr, sanitized_name); if (filter == NULL) { ret = ENOMEM; goto done; } if (uid != 0) { filter = talloc_asprintf_append(filter, "(%s=#%"SPRIuid")", attr, uid); if (filter == NULL) { ret = ENOMEM; goto done; } } if (groupnames != NULL) { for (i=0; groupnames[i] != NULL; i++) { ret = sss_filter_sanitize(tmp_ctx, groupnames[i], &sanitized_name); if (ret != EOK) { goto done; } filter = talloc_asprintf_append(filter, "(%s=%%%s)", attr, sanitized_name); if (filter == NULL) { ret = ENOMEM; goto done; } } } talloc_steal(mem_ctx, filter); done: talloc_free(tmp_ctx); if (ret != EOK) { return NULL; } return filter; } char * sysdb_sudo_filter_expired(TALLOC_CTX *mem_ctx, const char *username, char **groupnames, uid_t uid) { char *userfilter; char *filter; time_t now; userfilter = sysdb_sudo_filter_userinfo(mem_ctx, username, groupnames, uid); if (userfilter == NULL) { return NULL; } now = time(NULL); filter = talloc_asprintf(mem_ctx, "(&(%s=%s)(%s<=%lld)(|(%s=defaults)%s(%s=+*)))", SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC, SYSDB_CACHE_EXPIRE, (long long)now, SYSDB_NAME, userfilter, SYSDB_SUDO_CACHE_AT_USER); talloc_free(userfilter); return filter; } char * sysdb_sudo_filter_defaults(TALLOC_CTX *mem_ctx) { return talloc_asprintf(mem_ctx, "(&(%s=%s)(%s=defaults))", SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC, SYSDB_NAME); } char * sysdb_sudo_filter_user(TALLOC_CTX *mem_ctx, const char *username, char **groupnames, uid_t uid) { char *userfilter; char *filter; userfilter = sysdb_sudo_filter_userinfo(mem_ctx, username, groupnames, uid); if (userfilter == NULL) { return NULL; } filter = talloc_asprintf(mem_ctx, "(&(%s=%s)(|%s))", SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC, userfilter); talloc_free(userfilter); return filter; } char * sysdb_sudo_filter_netgroups(TALLOC_CTX *mem_ctx, const char *username, char **groupnames, uid_t uid) { char *userfilter; char *filter; userfilter = sysdb_sudo_filter_userinfo(mem_ctx, username, groupnames, uid); if (userfilter == NULL) { return NULL; } filter = talloc_asprintf(mem_ctx, "(&(%s=%s)(%s=+*)(!(|%s)))", SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC, SYSDB_SUDO_CACHE_AT_USER, userfilter); talloc_free(userfilter); return filter; } errno_t sysdb_get_sudo_user_info(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *username, uid_t *_uid, char ***groupnames) { TALLOC_CTX *tmp_ctx; errno_t ret; struct ldb_message *msg; struct ldb_message *group_msg = NULL; char **sysdb_groupnames = NULL; const char *primary_group = NULL; struct ldb_message_element *groups; uid_t uid = 0; gid_t gid = 0; size_t num_groups = 0; int i; const char *attrs[] = { SYSDB_MEMBEROF, SYSDB_GIDNUM, SYSDB_UIDNUM, NULL }; const char *group_attrs[] = { SYSDB_NAME, NULL }; tmp_ctx = talloc_new(NULL); NULL_CHECK(tmp_ctx, ret, done); ret = sysdb_search_user_by_name(tmp_ctx, domain, username, attrs, &msg); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up user %s\n", username); goto done; } if (_uid != NULL) { uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0); if (!uid) { DEBUG(SSSDBG_CRIT_FAILURE, "A user with no UID?\n"); ret = EIO; goto done; } } /* resolve secondary groups */ if (groupnames != NULL) { groups = ldb_msg_find_element(msg, SYSDB_MEMBEROF); if (!groups || groups->num_values == 0) { /* No groups for this user in sysdb currently */ sysdb_groupnames = NULL; num_groups = 0; } else { num_groups = groups->num_values; sysdb_groupnames = talloc_array(tmp_ctx, char *, num_groups + 1); NULL_CHECK(sysdb_groupnames, ret, done); /* Get a list of the groups by groupname only */ for (i = 0; i < groups->num_values; i++) { ret = sysdb_group_dn_name(domain->sysdb, sysdb_groupnames, (const char *)groups->values[i].data, &sysdb_groupnames[i]); if (ret != EOK) { ret = ENOMEM; goto done; } } sysdb_groupnames[groups->num_values] = NULL; } } /* resolve primary group */ gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0); if (gid != 0) { ret = sysdb_search_group_by_gid(tmp_ctx, domain, gid, group_attrs, &group_msg); if (ret == EOK) { primary_group = ldb_msg_find_attr_as_string(group_msg, SYSDB_NAME, NULL); if (primary_group == NULL) { ret = ENOMEM; goto done; } num_groups++; sysdb_groupnames = talloc_realloc(tmp_ctx, sysdb_groupnames, char *, num_groups + 1); NULL_CHECK(sysdb_groupnames, ret, done); sysdb_groupnames[num_groups - 1] = talloc_strdup(sysdb_groupnames, primary_group); NULL_CHECK(sysdb_groupnames[num_groups - 1], ret, done); sysdb_groupnames[num_groups] = NULL; } else if (ret != ENOENT) { DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up group [%d]: %s\n", ret, strerror(ret)); goto done; } } ret = EOK; if (_uid != NULL) { *_uid = uid; } if (groupnames != NULL) { *groupnames = talloc_steal(mem_ctx, sysdb_groupnames); } done: talloc_free(tmp_ctx); return ret; } static errno_t sysdb_sudo_set_refresh_time(struct sss_domain_info *domain, const char *attr_name, time_t value) { TALLOC_CTX *tmp_ctx; struct ldb_dn *dn; struct ldb_message *msg = NULL; struct ldb_result *res = NULL; errno_t ret; int lret; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { ret = ENOMEM; goto done; } dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE, SUDORULE_SUBDIR, domain->name); if (!dn) { ret = ENOMEM; goto done; } lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL); if (lret != LDB_SUCCESS) { ret = sysdb_error_to_errno(lret); goto done; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { ret = ENOMEM; goto done; } msg->dn = dn; if (res->count == 0) { lret = ldb_msg_add_string(msg, "cn", SUDORULE_SUBDIR); if (lret != LDB_SUCCESS) { ret = sysdb_error_to_errno(lret); goto done; } } else if (res->count != 1) { DEBUG(SSSDBG_CRIT_FAILURE, "Got more than one reply for base search!\n"); ret = EIO; goto done; } else { lret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL); if (lret != LDB_SUCCESS) { ret = sysdb_error_to_errno(lret); goto done; } } lret = ldb_msg_add_fmt(msg, attr_name, "%lld", (long long)value); if (lret != LDB_SUCCESS) { ret = sysdb_error_to_errno(lret); goto done; } if (res->count) { lret = ldb_modify(domain->sysdb->ldb, msg); } else { lret = ldb_add(domain->sysdb->ldb, msg); } if (lret != LDB_SUCCESS) { DEBUG(SSSDBG_MINOR_FAILURE, "ldb operation failed: [%s](%d)[%s]\n", ldb_strerror(lret), lret, ldb_errstring(domain->sysdb->ldb)); } ret = sysdb_error_to_errno(lret); done: talloc_free(tmp_ctx); return ret; } static errno_t sysdb_sudo_get_refresh_time(struct sss_domain_info *domain, const char *attr_name, time_t *value) { TALLOC_CTX *tmp_ctx; struct ldb_dn *dn; struct ldb_result *res; errno_t ret; int lret; const char *attrs[2] = {attr_name, NULL}; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { return ENOMEM; } dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE, SUDORULE_SUBDIR, domain->name); if (!dn) { ret = ENOMEM; goto done; } lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL); if (lret != LDB_SUCCESS) { ret = sysdb_error_to_errno(lret); goto done; } if (res->count == 0) { /* This entry has not been populated in LDB * This is a common case, as unlike LDAP, * LDB does not need to have all of its parent * objects actually exist. */ *value = 0; ret = EOK; goto done; } else if (res->count != 1) { DEBUG(SSSDBG_CRIT_FAILURE, "Got more than one reply for base search!\n"); ret = EIO; goto done; } *value = ldb_msg_find_attr_as_int(res->msgs[0], attr_name, 0); ret = EOK; done: talloc_free(tmp_ctx); return ret; } errno_t sysdb_sudo_set_last_full_refresh(struct sss_domain_info *domain, time_t value) { return sysdb_sudo_set_refresh_time(domain, SYSDB_SUDO_AT_LAST_FULL_REFRESH, value); } errno_t sysdb_sudo_get_last_full_refresh(struct sss_domain_info *domain, time_t *value) { return sysdb_sudo_get_refresh_time(domain, SYSDB_SUDO_AT_LAST_FULL_REFRESH, value); } /* ==================== Purge functions ==================== */ static const char * sysdb_sudo_get_rule_name(struct sysdb_attrs *rule) { const char *name; errno_t ret; ret = sysdb_attrs_get_string(rule, SYSDB_SUDO_CACHE_AT_CN, &name); if (ret == ERANGE) { DEBUG(SSSDBG_MINOR_FAILURE, "Warning: found rule that contains none " "or multiple CN values. It will be skipped.\n"); return NULL; } else if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to obtain rule name [%d]: %s\n", ret, strerror(ret)); return NULL; } return name; } static errno_t sysdb_sudo_purge_all(struct sss_domain_info *domain) { 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(tmp_ctx, domain, SUDORULE_SUBDIR); NULL_CHECK(base_dn, ret, done); DEBUG(SSSDBG_TRACE_FUNC, "Deleting all cached sudo rules\n"); ret = sysdb_delete_recursive(domain->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 ret; } static errno_t sysdb_sudo_purge_byname(struct sss_domain_info *domain, const char *name) { DEBUG(SSSDBG_TRACE_INTERNAL, "Deleting sudo rule %s\n", name); return sysdb_delete_custom(domain, name, SUDORULE_SUBDIR); } static errno_t sysdb_sudo_purge_byrules(struct sss_domain_info *dom, struct sysdb_attrs **rules, size_t num_rules) { const char *name; errno_t ret; size_t i; DEBUG(SSSDBG_TRACE_FUNC, "About to remove rules from sudo cache\n"); if (num_rules == 0 || rules == NULL) { return EOK; } for (i = 0; i < num_rules; i++) { name = sysdb_sudo_get_rule_name(rules[i]); if (name == NULL) { continue; } ret = sysdb_sudo_purge_byname(dom, name); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Failed to delete rule " "%s [%d]: %s\n", name, ret, sss_strerror(ret)); continue; } } return EOK; } static errno_t sysdb_sudo_purge_byfilter(struct sss_domain_info *domain, const char *filter) { TALLOC_CTX *tmp_ctx; struct sysdb_attrs **rules; struct ldb_message **msgs; size_t count; errno_t ret; const char *attrs[] = { SYSDB_OBJECTCLASS, SYSDB_NAME, SYSDB_SUDO_CACHE_AT_CN, NULL }; if (filter == NULL || strcmp(filter, SUDO_ALL_FILTER) == 0) { return sysdb_sudo_purge_all(domain); } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { ret = ENOMEM; goto done; } ret = sysdb_search_custom(tmp_ctx, domain, filter, SUDORULE_SUBDIR, attrs, &count, &msgs); 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\n"); goto done; } ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &rules); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to convert ldb message to " "sysdb attrs [%d]: %s\n", ret, sss_strerror(ret)); goto done; } ret = sysdb_sudo_purge_byrules(domain, rules, count); done: talloc_free(tmp_ctx); return ret; } errno_t sysdb_sudo_purge(struct sss_domain_info *domain, const char *delete_filter, struct sysdb_attrs **rules, size_t num_rules) { bool in_transaction = false; errno_t sret; errno_t ret; ret = sysdb_transaction_start(domain->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); return ret; } in_transaction = true; if (delete_filter) { ret = sysdb_sudo_purge_byfilter(domain, delete_filter); } else { ret = sysdb_sudo_purge_byrules(domain, rules, num_rules); } if (ret != EOK) { goto done; } ret = sysdb_transaction_commit(domain->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; done: if (in_transaction) { sret = sysdb_transaction_cancel(domain->sysdb); if (sret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); } } if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to purge sudo cache [%d]: %s\n", ret, sss_strerror(ret)); } return ret; } static errno_t sysdb_sudo_add_sss_attrs(struct sysdb_attrs *rule, const char *name, int cache_timeout, time_t now) { time_t expire; errno_t ret; ret = sysdb_attrs_add_string(rule, SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to add %s attribute [%d]: %s\n", SYSDB_OBJECTCLASS, ret, strerror(ret)); return ret; } ret = sysdb_attrs_add_string(rule, SYSDB_NAME, name); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to add %s attribute [%d]: %s\n", SYSDB_OBJECTCLASS, ret, strerror(ret)); return ret; } expire = cache_timeout > 0 ? now + cache_timeout : 0; ret = sysdb_attrs_add_time_t(rule, SYSDB_CACHE_EXPIRE, expire); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Unable to add %s attribute [%d]: %s\n", SYSDB_CACHE_EXPIRE, ret, strerror(ret)); return ret; } return EOK; } static errno_t sysdb_sudo_store_rule(struct sss_domain_info *domain, struct sysdb_attrs *rule, int cache_timeout, time_t now) { const char *name; errno_t ret; name = sysdb_sudo_get_rule_name(rule); if (name == NULL) { return EINVAL; } DEBUG(SSSDBG_TRACE_FUNC, "Adding sudo rule %s\n", name); ret = sysdb_sudo_add_sss_attrs(rule, name, cache_timeout, now); if (ret != EOK) { return ret; } ret = sysdb_store_custom(domain, name, SUDORULE_SUBDIR, rule); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to store rule %s [%d]: %s\n", name, ret, strerror(ret)); return ret; } return EOK; } errno_t sysdb_sudo_store(struct sss_domain_info *domain, struct sysdb_attrs **rules, size_t num_rules) { bool in_transaction = false; errno_t sret; errno_t ret; time_t now; size_t i; if (num_rules == 0 || rules == NULL) { return EOK; } ret = sysdb_transaction_start(domain->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); return ret; } in_transaction = true; now = time(NULL); for (i = 0; i < num_rules; i++) { ret = sysdb_sudo_store_rule(domain, rules[i], domain->sudo_timeout, now); if (ret == EINVAL) { /* Multiple CNs are error on server side, we can just ignore this * rule and save the others. Loud debug message is in logs. */ continue; } else if (ret != EOK) { goto done; } } ret = sysdb_transaction_commit(domain->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; done: if (in_transaction) { sret = sysdb_transaction_cancel(domain->sysdb); if (sret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); } } if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to store sudo rules [%d]: %s\n", ret, sss_strerror(ret)); } return ret; } errno_t sysdb_search_sudo_rules(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *sub_filter, const char **attrs, size_t *_msgs_count, struct ldb_message ***_msgs) { TALLOC_CTX *tmp_ctx; size_t msgs_count; struct ldb_message **msgs; struct ldb_dn *dn; char *filter; int ret; tmp_ctx = talloc_new(NULL); NULL_CHECK(tmp_ctx, ret, done); dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE, SUDORULE_SUBDIR, domain->name); if (dn == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n"); ret = ENOMEM; goto done; } if (sub_filter == NULL) { filter = talloc_asprintf(tmp_ctx, "(%s)", SUDO_ALL_FILTER); } else { filter = talloc_asprintf(tmp_ctx, "(&%s%s)", SUDO_ALL_FILTER, sub_filter); } if (filter == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n"); ret = ENOMEM; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "Search sudo rules with filter: %s\n", filter); ret = sysdb_search_entry(tmp_ctx, domain->sysdb, dn, LDB_SCOPE_SUBTREE, filter, attrs, &msgs_count, &msgs); if (ret == ENOENT) { DEBUG(SSSDBG_TRACE_INTERNAL, "No such entry\n"); *_msgs = NULL; *_msgs_count = 0; goto done; } else if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Error: %d (%s)\n", ret, sss_strerror(ret)); goto done; } *_msgs_count = msgs_count; *_msgs = talloc_steal(mem_ctx, msgs); ret = EOK; done: talloc_zfree(tmp_ctx); return ret; } static struct ldb_dn * sysdb_sudo_rule_dn(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *name) { return sysdb_custom_dn(mem_ctx, domain, name, SUDORULE_SUBDIR); } errno_t sysdb_set_sudo_rule_attr(struct sss_domain_info *domain, const char *name, struct sysdb_attrs *attrs, int mod_op) { errno_t ret; struct ldb_dn *dn; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { return ENOMEM; } dn = sysdb_sudo_rule_dn(tmp_ctx, domain, name); NULL_CHECK(dn, ret, done); ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op); done: talloc_free(tmp_ctx); return ret; }