From 3f98cdc011bb4e8cd22c088f288b0bcdb6452492 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 8 Dec 2011 12:20:28 +0100 Subject: SUDO Integration - sysdb interface --- src/db/sysdb_sudo.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 src/db/sysdb_sudo.c (limited to 'src/db/sysdb_sudo.c') diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c new file mode 100644 index 000000000..1703e78e9 --- /dev/null +++ b/src/db/sysdb_sudo.c @@ -0,0 +1,333 @@ +/* + 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 + +#include "db/sysdb.h" +#include "db/sysdb_sudo.h" + +#define NULL_CHECK(val, rval, label) do { \ + if (!val) { \ + rval = ENOMEM; \ + goto label; \ + } \ +} while(0) + +/* ==================== Utility functions ==================== */ +static char * +get_sudo_time_filter(TALLOC_CTX *mem_ctx) +{ + time_t now; + struct tm *tp; + char timebuffer[64]; + + /* Make sure we have a formatted timestamp for __now__. */ + time(&now); + if ((tp = gmtime(&now)) == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("unable to get GMT time\n")); + return NULL; + } + + /* Format the timestamp according to the RFC. */ + if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%M%SZ", tp) == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, ("unable to format timestamp\n")); + return NULL; + } + + return talloc_asprintf(mem_ctx, "(&(|(!(%s=*))(%s>=%s))" + "(|(!(%s=*))(%s<=%s)))", + SYSDB_SUDO_CACHE_AT_NOTAFTER, + SYSDB_SUDO_CACHE_AT_NOTAFTER, + timebuffer, + SYSDB_SUDO_CACHE_AT_NOTBEFORE, + SYSDB_SUDO_CACHE_AT_NOTBEFORE, + timebuffer); +} + +errno_t +sysdb_get_sudo_filter(TALLOC_CTX *mem_ctx, const char *username, + uid_t uid, char **groupnames, unsigned int flags, + char **_filter) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + char *filter; + char *t; + int i; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) return ENOMEM; + + /* AND with objectclass */ + filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)", + SYSDB_OBJECTCLASS, + SYSDB_SUDO_CACHE_AT_OC); + NULL_CHECK(filter, ret, done); + + /* And with the timed rules if requested */ + if (flags & SYSDB_SUDO_FILTER_TIMED) { + t = get_sudo_time_filter(filter); + filter = talloc_asprintf_append(filter, "%s", t); + talloc_free(t); + NULL_CHECK(filter, ret, done); + } + + /* Add global OR and the username */ + filter = talloc_asprintf_append(filter, "(|(%s=%s)", + SYSDB_SUDO_CACHE_AT_USER, + username); + NULL_CHECK(filter, ret, done); + + if (uid) { + filter = talloc_asprintf_append(filter, "(%s=#%llu)", + SYSDB_SUDO_CACHE_AT_USER, + (unsigned long long) uid); + NULL_CHECK(filter, ret, done); + } + + if (groupnames) { + for (i=0; groupnames[i]; i++) { + filter = talloc_asprintf_append(filter, "(%s=%%%s)", + SYSDB_SUDO_CACHE_AT_USER, + groupnames[i]); + NULL_CHECK(filter, ret, done); + } + } + + if (flags & SYSDB_SUDO_FILTER_NGRS) { + filter = talloc_asprintf_append(filter, "(%s=+*)", + SYSDB_SUDO_CACHE_AT_USER); + NULL_CHECK(filter, ret, done); + } + + if (flags & SYSDB_SUDO_FILTER_INCLUDE_ALL) { + filter = talloc_asprintf_append(filter, "(%s=ALL)", + SYSDB_SUDO_CACHE_AT_USER); + NULL_CHECK(filter, ret, done); + } + + if (flags & SYSDB_SUDO_FILTER_INCLUDE_DFL) { + filter = talloc_asprintf_append(filter, "(%s=defaults)", + SYSDB_NAME); + NULL_CHECK(filter, ret, done); + } + + /* end the global AND and OR filters */ + filter = talloc_asprintf_append(filter, "))"); + NULL_CHECK(filter, ret, done); + + + ret = EOK; + *_filter = talloc_steal(mem_ctx, filter); +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t +sysdb_get_sudo_user_info(TALLOC_CTX *mem_ctx, const char *username, + struct sysdb_ctx *sysdb, uid_t *_uid, + char ***groupnames) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + const char *attrs[3]; + struct ldb_message *msg; + char **sysdb_groupnames = NULL; + struct ldb_message_element *groups; + uid_t uid; + int i; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) return ENOMEM; + + attrs[0] = SYSDB_MEMBEROF; + attrs[1] = SYSDB_UIDNUM; + attrs[2] = NULL; + ret = sysdb_search_user_by_name(tmp_ctx, sysdb, username, + attrs, &msg); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up user %s\n", username)); + goto done; + } + + 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; + } + + 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; + } else { + sysdb_groupnames = talloc_array(tmp_ctx, char *, groups->num_values+1); + if (!sysdb_groupnames) { + ret = ENOMEM; + goto done; + } + + /* Get a list of the groups by groupname only */ + for (i=0; i < groups->num_values; i++) { + ret = sysdb_group_dn_name(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; + } + + ret = EOK; + *_uid = uid; + *groupnames = talloc_steal(mem_ctx, sysdb_groupnames); +done: + talloc_free(tmp_ctx); + 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); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + ret = ENOMEM; + goto done; + } + + base_dn = sysdb_custom_subtree_dn(sysdb, tmp_ctx, domain->name, subdir); + if (base_dn == NULL) { + ret = ENOMEM; + goto 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, + struct sysdb_attrs *attrs) +{ + errno_t ret; + + DEBUG(SSSDBG_TRACE_FUNC, ("Adding sudo rule %s\n", rule_name)); + + ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, + SYSDB_SUDO_CACHE_AT_OC); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not set rule object class [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + + ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, rule_name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not set name attribute [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + + ret = sysdb_store_custom(sysdb_ctx, rule_name, SUDORULE_SUBDIR, attrs); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_store_custom failed [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + + return EOK; +} + +errno_t +sysdb_purge_sudorule_subtree(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *filter) +{ + TALLOC_CTX *tmp_ctx; + size_t count; + struct ldb_message **msgs; + const char *name; + int i; + errno_t ret; + const char *attrs[] = { SYSDB_OBJECTCLASS + SYSDB_SUDO_CACHE_AT_OC, + SYSDB_SUDO_CACHE_AT_CN }; + + /* just purge all if there's no filter */ + if (!filter) { + return sysdb_sudo_purge_subdir(sysdb, domain, SUDORULE_SUBDIR); + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) return ENOMEM; + + /* match entries based on the filter and remove them one by one */ + 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) { + DEBUG(SSSDBG_TRACE_FUNC, ("No rules matched\n")); + ret = EOK; + goto done; + } + + for (i = 0; i < count; i++) { + name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); + if (name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("A rule without a name?\n")); + goto done; + } + + ret = sysdb_delete_custom(sysdb, name, SUDORULE_SUBDIR); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not delete rule %s\n", name)); + goto done; + } + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} -- cgit