/*
SSSD
System Database
Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
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 "util/util.h"
#include "db/sysdb_private.h"
#include "db/sysdb_services.h"
#include "db/sysdb_autofs.h"
#include "util/crypto/sss_crypto.h"
#include <time.h>
int add_string(struct ldb_message *msg, int flags,
const char *attr, const char *value)
{
int ret;
ret = ldb_msg_add_empty(msg, attr, flags, NULL);
if (ret == LDB_SUCCESS) {
ret = ldb_msg_add_string(msg, attr, value);
if (ret == LDB_SUCCESS) return EOK;
}
return ENOMEM;
}
int add_ulong(struct ldb_message *msg, int flags,
const char *attr, unsigned long value)
{
int ret;
ret = ldb_msg_add_empty(msg, attr, flags, NULL);
if (ret == LDB_SUCCESS) {
ret = ldb_msg_add_fmt(msg, attr, "%lu", value);
if (ret == LDB_SUCCESS) return EOK;
}
return ENOMEM;
}
static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr);
long long int l;
if (!v || !v->data) {
return 0;
}
errno = 0;
l = strtoll((const char *)v->data, NULL, 10);
if (errno) {
return (uint32_t)-1;
}
if (l < 0 || l > ((uint32_t)(-1))) {
return (uint32_t)-1;
}
return l;
}
#define ERROR_OUT(v, r, l) do { v = r; goto l; } while(0)
/* =Remove-Entry-From-Sysdb=============================================== */
int sysdb_delete_entry(struct sysdb_ctx *sysdb,
struct ldb_dn *dn,
bool ignore_not_found)
{
int ret;
ret = ldb_delete(sysdb->ldb, dn);
switch (ret) {
case LDB_SUCCESS:
return EOK;
case LDB_ERR_NO_SUCH_OBJECT:
if (ignore_not_found) {
return EOK;
}
/* fall through */
default:
DEBUG(1, ("LDB Error: %s(%d)\nError Message: [%s]\n",
ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)));
return sysdb_error_to_errno(ret);
}
}
/* =Remove-Subentries-From-Sysdb=========================================== */
int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
struct ldb_dn *dn,
bool ignore_not_found)
{
const char *no_attrs[] = { NULL };
struct ldb_message **msgs;
size_t msgs_count;
int ret;
int i;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
ret = ldb_transaction_start(sysdb->ldb);
if (ret) {
ret = sysdb_error_to_errno(ret);
goto done;
}
ret = sysdb_search_entry(tmp_ctx, sysdb, dn,
LDB_SCOPE_SUBTREE, "(distinguishedName=*)",
no_attrs, &msgs_count, &msgs);
if (ret) {
if (ignore_not_found && ret == ENOENT) {
ret = EOK;
}
if (ret) {
DEBUG(6, ("Search error: %d (%s)\n", ret, strerror(ret)));
}
goto done;
}
DEBUG(9, ("Found [%d] items to delete.\n", msgs_count));
qsort(msgs, msgs_count,
sizeof(struct ldb_message *), compare_ldb_dn_comp_num);
for (i = 0; i < msgs_count; i++) {
DEBUG(9 ,("Trying to delete [%s].\n",
ldb_dn_get_linearized(msgs[i]->dn)));
ret = sysdb_delete_entry(sysdb, msgs[i]->dn, false);
if (ret) {
goto done;
}
}
done:
if (ret == EOK) {
ret = ldb_transaction_commit(sysdb->ldb);
ret = sysdb_error_to_errno(ret);
} else {
ldb_transaction_cancel(sysdb->ldb);
}
talloc_free(tmp_ctx);
return ret;
}
/* =Search-Entry========================================================== */
int sysdb_search_entry(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct ldb_dn *base_dn,
int scope,
const char *filter,
const char **attrs,
size_t *msgs_count,
struct ldb_message ***msgs)
{
struct ldb_result *res;
int ret;
ret = ldb_search(sysdb->ldb, mem_ctx, &res,
base_dn, scope, attrs,
filter?"%s":NULL, filter);
if (ret) {
return sysdb_error_to_errno(ret);
}
*msgs_count = res->count;
*msgs = talloc_steal(mem_ctx, res->msgs);
if (res->count == 0) {
return ENOENT;
}
return EOK;
}
/* =Search-User-by-[UID/NAME]============================================= */
int sysdb_search_user_by_name(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
const char *name,
const char **attrs,
struct ldb_message **msg)
{
TALLOC_CTX *tmp_ctx;
const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL };
struct ldb_message **msgs = NULL;
struct ldb_dn *basedn;
size_t msgs_count = 0;
int ret;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
basedn = sysdb_user_dn(sysdb, tmp_ctx, sysdb->domain->name, name);
if (!basedn) {
ret = ENOMEM;
goto done;
}
ret = sysdb_search_entry(tmp_ctx, sysdb, basedn, LDB_SCOPE_BASE, NULL,
attrs?attrs:def_attrs, &msgs_count, &msgs);
if (ret) {
goto done;
}
*msg = talloc_steal(mem_ctx, msgs[0]);
done:
if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, ("No such entry\n"));
}
else if (ret) {
DEBUG(SSSDBG_TRACE_FUNC, ("Error: %d (%s)\n", ret, strerror(ret)));
}
talloc_zfree(tmp_ctx);
return ret;
}
int sysdb_search_user_by_uid(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
uid_t uid,
const char **attrs,
struct ldb_message **msg)
{
TALLOC_CTX *tmp_ctx;
const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL };
struct ldb_message **msgs = NULL;
struct ldb_dn *basedn;
size_t msgs_count = 0;
char *filter;
int ret;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
basedn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
SYSDB_TMPL_USER_BASE, sysdb->domain->name);
if (!basedn) {
ret = ENOMEM;
goto done;
}
filter = talloc_asprintf(tmp_ctx, SYSDB_PWUID_FILTER, (unsigned long)uid);
if (!filter) {
ret = ENOMEM;
goto done;
}
/* Use SUBTREE scope here, not ONELEVEL
* There is a bug in LDB that makes ONELEVEL searches extremely
* slow (it ignores indexing)
*/
ret = sysdb_search_entry(tmp_ctx, sysdb, basedn, LDB_SCOPE_SUBTREE, filter,
attrs?attrs:def_attrs, &msgs_count, &msgs);
if (ret) {
goto done;
}
*msg = talloc_steal(mem_ctx, msgs[0]);
done:
if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, ("No such entry\n"));
}
else if (ret) {
DEBUG(SSSDBG_TRACE_FUNC, ("Error: %d (%s)\n", ret, strerror(ret)));
}
talloc_zfree(tmp_ctx);
return ret;
}
/* =Search-Group-by-[GID/NAME]============================================ */
int sysdb_search_group_by_name(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
const char *name,
const char **attrs,
struct ldb_message **msg)
{
TALLOC_CTX *tmp_ctx;
static const char *def_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL };
struct ldb_message **msgs = NULL;
struct ldb_dn *basedn;
size_t msgs_count = 0;
int ret;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
basedn = sysdb_group_dn(sysdb, tmp_ctx, sysdb->domain->name, name);
if (!basedn) {
ret = ENOMEM;
goto done;
}
ret = sysdb_search_entry(tmp_ctx, sysdb, basedn, LDB_SCOPE_BASE, NULL,
attrs?attrs:def_attrs, &msgs_count, &msgs);
if (ret) {
goto done;
}
*msg = talloc_steal(mem_ctx, msgs[0]);
done:
if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, ("No such entry\n"));
}
else if (ret) {
DEBUG(SSSDBG_TRACE_FUNC, ("Error: %d (%s)\n", ret, strerror(ret)));
}
talloc_zfree(tmp_ctx);
return ret;
}
int sysdb_search_group_by_gid(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
gid_t gid,
const char **attrs,
struct ldb_message **msg)
{
TALLOC_CTX *tmp_ctx;
const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL };
struct ldb_message **msgs = NULL;
struct ldb_dn *basedn;
size_t msgs_count = 0;
char *filter;
int ret;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
basedn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
SYSDB_TMPL_GROUP_BASE, sysdb->domain->name);
if (!basedn) {
ret = ENOMEM;
goto done;
}
filter = talloc_asprintf(tmp_ctx, SYSDB_GRGID_FILTER, (unsigned long)gid);
if (!filter) {
ret = ENOMEM;
goto done;
}
/* Use SUBTREE scope here, not ONELEVEL
* There is a bug in LDB that makes ONELEVEL searches extremely
* slow (it ignores indexing)
*/
ret = sysdb_search_entry(tmp_ctx, sysdb, basedn, LDB_SCOPE_SUBTREE, filter,
attrs?attrs:def_attrs, &msgs_count, &msgs);
if (ret) {
goto done;
}
*msg = talloc_steal(mem_ctx, msgs[0]);
done:
if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, ("No such entry\n"));
}
else if (ret) {
DEBUG(SSSDBG_TRACE_FUNC, ("Error: %d (%s)\n", ret, strerror(ret)));
}
talloc_zfree(tmp_ctx);
return ret;
}
/* =Search-Group-by-Name============================================ */
int sysdb_search_netgroup_by_name(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
const char *name,
const char **attrs,
struct ldb_message **msg)
{
TALLOC_CTX *tmp_ctx;
static const char *def_attrs[] = { SYSDB_NAME, NULL };
struct ldb_message **msgs = NULL;
struct ldb_dn *basedn;
size_t msgs_count = 0;
int ret;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
basedn = sysdb_netgroup_dn(sysdb, tmp_ctx, sysdb->domain->name, name);
if (!basedn) {
ret = ENOMEM;
goto done;
}
ret = sysdb_search_entry(tmp_ctx, sysdb, basedn, LDB_SCOPE_BASE, NULL,
attrs?attrs:def_attrs, &msgs_count, &msgs);
if (ret) {
goto done;
}
*msg = talloc_steal(mem_ctx, msgs[0]);
done:
if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, ("No such entry\n"));
}
else if (ret) {
DEBUG(SSSDBG_TRACE_FUNC, ("Error: %d (%s)\n", ret, strerror(ret)));
}
talloc_zfree(tmp_ctx);
return ret;
}
/* =Replace-Attributes-On-Entry=========================================== */
int sysdb_set_entry_attr(struct sysdb_ctx *sysdb,
struct ldb_dn *entry_dn,
|