sysdb_gpo.c revision 04d138472cc086fb7961f0d378852b09961b1a33
/*
SSSD
Authors:
Yassir Elley <yelley@redhat.com>
Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
*/
#include "db/sysdb.h"
#include "db/sysdb_private.h"
static struct ldb_dn *
sysdb_gpo_dn(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain,
const char *gpo_guid)
{
errno_t ret;
char *clean_gpo_guid;
struct ldb_dn *dn;
ret = sysdb_dn_sanitize(NULL, gpo_guid, &clean_gpo_guid);
if (ret != EOK) {
return NULL;
}
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);
talloc_free(clean_gpo_guid);
return dn;
}
errno_t
sysdb_gpo_store_gpo(struct sss_domain_info *domain,
const char *gpo_guid,
int gpo_version,
int cache_timeout,
time_t now)
{
errno_t ret, sret;
int lret;
struct ldb_message *update_msg;
struct ldb_message **msgs;
static const char *attrs[] = SYSDB_GPO_ATTRS;
size_t count;
bool in_transaction = 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_dn(update_msg, domain, gpo_guid);
if (!update_msg->dn) {
ret = ENOMEM;
goto done;
}
ret = sysdb_transaction_start(domain->sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
goto done;
}
if (!now) {
now = time(NULL);
}
in_transaction = true;
/* Check for an existing gpo_guid entry */
ret = sysdb_search_entry(tmp_ctx, domain->sysdb, update_msg->dn,
LDB_SCOPE_BASE, NULL, attrs, &count, &msgs);
if (ret == ENOENT) {
/* Create new GPO */
DEBUG(SSSDBG_TRACE_FUNC,
"Adding new GPO [gpo_guid:%s][gpo_version:%d]\n",
gpo_guid, gpo_version);
/* 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_OC);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
/* Add the GPO GUID */
lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_GUID_ATTR,
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_GPO_GUID_ATTR, gpo_guid);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
/* Add the Version */
lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_VERSION_ATTR,
LDB_FLAG_MOD_ADD,
NULL);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
lret = ldb_msg_add_fmt(update_msg, SYSDB_GPO_VERSION_ATTR,
"%d", gpo_version);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
/* Add the Policy File Timeout */
lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_TIMEOUT_ATTR,
LDB_FLAG_MOD_ADD, NULL);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
lret = ldb_msg_add_fmt(update_msg, SYSDB_GPO_TIMEOUT_ATTR, "%lu",
((cache_timeout) ? (now + cache_timeout) : 0));
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: [%s]\n",
ldb_strerror(lret));
ret = sysdb_error_to_errno(lret);
goto done;
}
} else if (ret == EOK && count == 1) {
/* Update the existing GPO */
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,
LDB_FLAG_MOD_REPLACE,
NULL);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
lret = ldb_msg_add_fmt(update_msg, SYSDB_GPO_VERSION_ATTR,
"%d", gpo_version);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
/* Add the Policy File Timeout */
lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_TIMEOUT_ATTR,
LDB_FLAG_MOD_REPLACE, NULL);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
lret = ldb_msg_add_fmt(update_msg, SYSDB_GPO_TIMEOUT_ATTR, "%lu",
((cache_timeout) ? (now + cache_timeout) : 0));
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: [%s](%d)[%s]\n",
ldb_strerror(lret), lret, ldb_errstring(domain->sysdb->ldb));
ret = sysdb_error_to_errno(lret);
goto done;
}
} else {
ret = EIO;
goto done;
}
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_by_guid(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *gpo_guid,
struct ldb_result **_result)
{
errno_t ret;
int lret;
struct ldb_dn *base_dn;
TALLOC_CTX *tmp_ctx;
struct ldb_result *res;
const char *attrs[] = SYSDB_GPO_ATTRS;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
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,
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_GUID_FILTER, gpo_guid);
if (lret) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not locate GPO: [%s]\n",
ldb_strerror(lret));
ret = sysdb_error_to_errno(lret);
goto done;
}
if (res->count > 1) {
DEBUG(SSSDBG_CRIT_FAILURE, "Search for GUID [%s] returned more than " \
"one object.\n", gpo_guid);
ret = EINVAL;
goto done;
} else 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 such entry.\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_get_gpos(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;
const char *attrs[] = SYSDB_GPO_ATTRS;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
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,
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_FILTER);
if (lret) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not locate GPOs: [%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 entries.\n");
} else if (ret) {
DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
}
talloc_free(tmp_ctx);
return ret;
}
/* GPO Result */
static struct ldb_dn *
sysdb_gpo_result_dn(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *result_name)
{
errno_t ret;
char *clean_result_name;
struct ldb_dn *dn;
ret = sysdb_dn_sanitize(NULL, result_name, &clean_result_name);
if (ret != EOK) {
return NULL;
}
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_store_gpo_result_setting(struct sss_domain_info *domain,
const char *ini_key,
const char *ini_value)
{
errno_t ret, sret;
int lret;
struct ldb_message *update_msg;
struct ldb_message **msgs;
size_t count;
bool in_transaction = 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) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
goto done;
}
in_transaction = true;
/* 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;
}
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](%d)[%s]\n",
ldb_strerror(lret), lret, ldb_errstring(domain->sysdb->ldb));
ret = sysdb_error_to_errno(lret);
goto done;
}
} else {
ret = EIO;
goto done;
}
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;
}
static errno_t
sysdb_gpo_get_gpo_result_object(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char **attrs,
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, attrs, 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_get_gpo_result_setting(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *ini_key,
const char **_ini_value)
{
errno_t ret;
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;
ret = sysdb_gpo_get_gpo_result_object(tmp_ctx, domain, attrs, &res);
if (ret != EOK) {
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_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, NULL, &res);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE,
"Could not delete GPO result object: %d\n", ret);
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);
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");
}
}
return ret;
}