summaryrefslogtreecommitdiff
path: root/src/confdb
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2010-02-18 07:49:04 -0500
committerStephen Gallagher <sgallagh@redhat.com>2010-02-18 13:48:45 -0500
commit1c48b5a62f73234ed26bb20f0ab345ab61cda0ab (patch)
tree0b6cddd567a862e1a7b5df23764869782a62ca78 /src/confdb
parent8c56df3176f528fe0260974b3bf934173c4651ea (diff)
downloadsssd-1c48b5a62f73234ed26bb20f0ab345ab61cda0ab.tar.gz
sssd-1c48b5a62f73234ed26bb20f0ab345ab61cda0ab.tar.bz2
sssd-1c48b5a62f73234ed26bb20f0ab345ab61cda0ab.zip
Rename server/ directory to src/
Also update BUILD.txt
Diffstat (limited to 'src/confdb')
-rw-r--r--src/confdb/confdb.c908
-rw-r--r--src/confdb/confdb.h364
-rw-r--r--src/confdb/confdb_private.h35
-rw-r--r--src/confdb/confdb_setup.c423
-rw-r--r--src/confdb/confdb_setup.h52
5 files changed, 1782 insertions, 0 deletions
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
new file mode 100644
index 00000000..6981baa5
--- /dev/null
+++ b/src/confdb/confdb.c
@@ -0,0 +1,908 @@
+/*
+ SSSD
+
+ NSS Configuratoin DB
+
+ 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/>.
+*/
+
+#define _GNU_SOURCE
+
+#include <ctype.h>
+#include "config.h"
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "confdb/confdb_private.h"
+#include "util/strtonum.h"
+#include "db/sysdb.h"
+
+#define CONFDB_ZERO_CHECK_OR_JUMP(var, ret, err, label) do { \
+ if (!var) { \
+ ret = err; \
+ goto label; \
+ } \
+} while(0)
+
+static char *prepend_cn(char *str, int *slen, const char *comp, int clen)
+{
+ char *ret;
+
+ ret = talloc_realloc(NULL, str, char, *slen + 4 + clen + 1);
+ if (!ret)
+ return NULL;
+
+ /* move current string to the end */
+ memmove(&ret[clen +4], ret, *slen+1); /* includes termination */
+ memcpy(ret, "cn=", 3);
+ memcpy(&ret[3], comp, clen);
+ ret[clen+3] = ',';
+
+ *slen = *slen + 4 + clen;
+
+ return ret;
+}
+
+int parse_section(TALLOC_CTX *mem_ctx, const char *section,
+ char **sec_dn, const char **rdn_name)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *dn = NULL;
+ char *p;
+ const char *s;
+ int l, ret;
+
+ /* section must be a non null string and must not start with '/' */
+ if (!section || !*section || *section == '/') return EINVAL;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) return ENOMEM;
+
+ s = section;
+ l = 0;
+ while ((p = strchrnul(s, '/'))) {
+ if (l == 0) {
+ dn = talloc_asprintf(tmp_ctx, "cn=%s", s);
+ l = 3 + (p-s);
+ dn[l] = '\0';
+ } else {
+ dn = prepend_cn(dn, &l, s, p-s);
+ }
+ if (!dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+ if (*p == '\0') {
+ if (rdn_name) *rdn_name = s;
+ break; /* reached end */
+ }
+ s = p+1;
+ if (*s == '\0') { /* a section cannot end in '.' */
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ *sec_dn = talloc_steal(mem_ctx, dn);
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_add_param(struct confdb_ctx *cdb,
+ bool replace,
+ const char *section,
+ const char *attribute,
+ const char **values)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_result *res;
+ struct ldb_dn *dn;
+ char *secdn;
+ const char *rdn_name;
+ int ret, i;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = parse_section(tmp_ctx, section, &secdn, &rdn_name);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, cdb->ldb, secdn);
+ CONFDB_ZERO_CHECK_OR_JUMP(dn, ret, EIO, done);
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res,
+ dn, LDB_SCOPE_BASE, NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ CONFDB_ZERO_CHECK_OR_JUMP(msg, ret, ENOMEM, done);
+
+ msg->dn = talloc_steal(msg, dn);
+ CONFDB_ZERO_CHECK_OR_JUMP(msg->dn, ret, ENOMEM, done);
+
+ if (res->count == 0) { /* add a new message */
+ errno = 0;
+
+ /* cn first */
+ ret = ldb_msg_add_string(msg, "cn", rdn_name);
+ if (ret != LDB_SUCCESS) {
+ if (errno) ret = errno;
+ else ret = EIO;
+ goto done;
+ }
+
+ /* now the requested attribute */
+ for (i = 0; values[i]; i++) {
+ ret = ldb_msg_add_string(msg, attribute, values[i]);
+ if (ret != LDB_SUCCESS) {
+ if (errno) ret = errno;
+ else ret = EIO;
+ goto done;
+ }
+ }
+
+ ret = ldb_add(cdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ } else {
+ int optype;
+ errno = 0;
+
+ /* mark this as a replacement */
+ if (replace) optype = LDB_FLAG_MOD_REPLACE;
+ else optype = LDB_FLAG_MOD_ADD;
+ ret = ldb_msg_add_empty(msg, attribute, optype, NULL);
+ if (ret != LDB_SUCCESS) {
+ if (errno) ret = errno;
+ else ret = EIO;
+ goto done;
+ }
+
+ /* now the requested attribute */
+ for (i = 0; values[i]; i++) {
+ ret = ldb_msg_add_string(msg, attribute, values[i]);
+ if (ret != LDB_SUCCESS) {
+ if (errno) ret = errno;
+ else ret = EIO;
+ goto done;
+ }
+ }
+
+ ret = ldb_modify(cdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to add [%s] to [%s], error [%d] (%s)",
+ attribute, section, ret, strerror(ret)));
+ }
+ return ret;
+}
+
+int confdb_get_param(struct confdb_ctx *cdb,
+ TALLOC_CTX *mem_ctx,
+ const char *section,
+ const char *attribute,
+ char ***values)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ struct ldb_dn *dn;
+ char *secdn;
+ const char *attrs[] = { attribute, NULL };
+ char **vals;
+ struct ldb_message_element *el;
+ int ret, i;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx)
+ return ENOMEM;
+
+ ret = parse_section(tmp_ctx, section, &secdn, NULL);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, cdb->ldb, secdn);
+ if (!dn) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res,
+ dn, LDB_SCOPE_BASE, attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+ if (res->count > 1) {
+ ret = EIO;
+ goto done;
+ }
+
+ vals = talloc_zero(mem_ctx, char *);
+ ret = EOK;
+
+ if (res->count > 0) {
+ el = ldb_msg_find_element(res->msgs[0], attribute);
+ if (el && el->num_values > 0) {
+ vals = talloc_realloc(mem_ctx, vals, char *, el->num_values +1);
+ if (!vals) {
+ ret = ENOMEM;
+ goto done;
+ }
+ /* should always be strings so this should be safe */
+ for (i = 0; i < el->num_values; i++) {
+ struct ldb_val v = el->values[i];
+ vals[i] = talloc_strndup(vals, (char *)v.data, v.length);
+ if (!vals[i]) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ vals[i] = NULL;
+ }
+ }
+
+ *values = vals;
+
+done:
+ talloc_free(tmp_ctx);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to get [%s] from [%s], error [%d] (%s)",
+ attribute, section, ret, strerror(ret)));
+ }
+ return ret;
+}
+
+int confdb_get_string(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ const char *defstr, char **result)
+{
+ char **values = NULL;
+ char *restr;
+ int ret;
+
+ ret = confdb_get_param(cdb, ctx, section, attribute, &values);
+ if (ret != EOK) {
+ goto failed;
+ }
+
+ if (values[0]) {
+ if (values[1] != NULL) {
+ /* too many values */
+ ret = EINVAL;
+ goto failed;
+ }
+ restr = talloc_steal(ctx, values[0]);
+ } else {
+ /* Did not return a value, so use the default */
+
+ if (defstr == NULL) { /* No default given */
+ *result = NULL;
+ talloc_free(values);
+ return EOK;
+ }
+
+ /* Copy the default string */
+ restr = talloc_strdup(ctx, defstr);
+ }
+ if (!restr) {
+ ret = ENOMEM;
+ goto failed;
+ }
+
+ talloc_free(values);
+
+ *result = restr;
+ return EOK;
+
+failed:
+ talloc_free(values);
+ DEBUG(1, ("Failed to get [%s] from [%s], error [%d] (%s)",
+ attribute, section, ret, strerror(ret)));
+ return ret;
+}
+
+int confdb_get_int(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ int defval, int *result)
+{
+ char **values = NULL;
+ long val;
+ int ret;
+
+ ret = confdb_get_param(cdb, ctx, section, attribute, &values);
+ if (ret != EOK) {
+ goto failed;
+ }
+
+ if (values[0]) {
+ if (values[1] != NULL) {
+ /* too many values */
+ ret = EINVAL;
+ goto failed;
+ }
+
+ errno = 0;
+ val = strtol(values[0], NULL, 0);
+ if (errno) {
+ ret = errno;
+ goto failed;
+ }
+
+ if (val < INT_MIN || val > INT_MAX) {
+ ret = ERANGE;
+ goto failed;
+ }
+
+ } else {
+ val = defval;
+ }
+
+ talloc_free(values);
+
+ *result = (int)val;
+ return EOK;
+
+failed:
+ talloc_free(values);
+ DEBUG(1, ("Failed to read [%s] from [%s], error [%d] (%s)",
+ attribute, section, ret, strerror(ret)));
+ return ret;
+}
+
+long confdb_get_long(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ long defval, long *result)
+{
+ char **values = NULL;
+ long val;
+ int ret;
+
+ ret = confdb_get_param(cdb, ctx, section, attribute, &values);
+ if (ret != EOK) {
+ goto failed;
+ }
+
+ if (values[0]) {
+ if (values[1] != NULL) {
+ /* too many values */
+ ret = EINVAL;
+ goto failed;
+ }
+
+ errno = 0;
+ val = strtol(values[0], NULL, 0);
+ if (errno) {
+ ret = errno;
+ goto failed;
+ }
+
+ } else {
+ val = defval;
+ }
+
+ talloc_free(values);
+
+ *result = val;
+ return EOK;
+
+failed:
+ talloc_free(values);
+ DEBUG(1, ("Failed to read [%s] from [%s], error [%d] (%s)",
+ attribute, section, ret, strerror(ret)));
+ return ret;
+}
+
+int confdb_get_bool(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ bool defval, bool *result)
+{
+ char **values = NULL;
+ bool val;
+ int ret;
+
+ ret = confdb_get_param(cdb, ctx, section, attribute, &values);
+ if (ret != EOK) {
+ goto failed;
+ }
+
+ if (values[0]) {
+ if (values[1] != NULL) {
+ /* too many values */
+ ret = EINVAL;
+ goto failed;
+ }
+
+ if (strcasecmp(values[0], "FALSE") == 0) {
+ val = false;
+
+ } else if (strcasecmp(values[0], "TRUE") == 0) {
+ val = true;
+
+ } else {
+
+ DEBUG(2, ("Value is not a boolean!\n"));
+ ret = EINVAL;
+ goto failed;
+ }
+
+ } else {
+ val = defval;
+ }
+
+ talloc_free(values);
+
+ *result = val;
+ return EOK;
+
+failed:
+ talloc_free(values);
+ DEBUG(1, ("Failed to read [%s] from [%s], error [%d] (%s)",
+ attribute, section, ret, strerror(ret)));
+ return ret;
+}
+
+/* WARNING: Unlike other similar functions, this one does NOT take a default,
+ * and returns ENOENT if the attribute was not found ! */
+int confdb_get_string_as_list(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ char ***result)
+{
+ char **values = NULL;
+ int ret;
+
+ ret = confdb_get_param(cdb, ctx, section, attribute, &values);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ if (values && values[0]) {
+ if (values[1] != NULL) {
+ /* too many values */
+ ret = EINVAL;
+ goto done;
+ }
+ } else {
+ /* Did not return a value */
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = split_on_separator(ctx, values[0], ',', true, result, NULL);
+
+done:
+ talloc_free(values);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(2, ("Failed to get [%s] from [%s], error [%d] (%s)",
+ attribute, section, ret, strerror(ret)));
+ }
+ return ret;
+}
+
+int confdb_init(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx **cdb_ctx,
+ char *confdb_location)
+{
+ struct confdb_ctx *cdb;
+ int ret = EOK;
+
+ cdb = talloc_zero(mem_ctx, struct confdb_ctx);
+ if (!cdb)
+ return ENOMEM;
+
+ /* Because confdb calls use sync ldb calls, we create a separate event
+ * context here. This will prevent the ldb sync calls to start nested
+ * events.
+ * NOTE: this means that we *cannot* do async calls and return in confdb
+ * unless we convert all calls and hook back to the main event context.
+ */
+
+ cdb->pev = tevent_context_init(cdb);
+ if (!cdb->pev) {
+ talloc_free(cdb);
+ return EIO;
+ }
+
+ cdb->ldb = ldb_init(cdb, cdb->pev);
+ if (!cdb->ldb) {
+ talloc_free(cdb);
+ return EIO;
+ }
+
+ ret = ldb_set_debug(cdb->ldb, ldb_debug_messages, NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("Could not set up debug fn.\n"));
+ talloc_free(cdb);
+ return EIO;
+ }
+
+ ret = ldb_connect(cdb->ldb, confdb_location, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("Unable to open config database [%s]\n",
+ confdb_location));
+ talloc_free(cdb);
+ return EIO;
+ }
+
+ *cdb_ctx = cdb;
+
+ return EOK;
+}
+
+static errno_t get_entry_as_uint32(struct ldb_message *msg,
+ uint32_t *return_value,
+ const char *entry,
+ uint32_t default_value)
+{
+ const char *tmp = NULL;
+ char *endptr;
+ uint32_t u32ret = 0;
+
+ *return_value = 0;
+
+ if (!msg || !entry) {
+ return EFAULT;
+ }
+
+ tmp = ldb_msg_find_attr_as_string(msg, entry, NULL);
+ if (tmp == NULL) {
+ *return_value = default_value;
+ return EOK;
+ }
+
+ if ((*tmp == '-') || (*tmp == '\0')) {
+ return EINVAL;
+ }
+
+ u32ret = strtouint32 (tmp, &endptr, 10);
+ if (errno) {
+ return errno;
+ }
+
+ if (*endptr != '\0') {
+ /* Not all of the string was a valid number */
+ return EINVAL;
+ }
+
+ *return_value = u32ret;
+ return EOK;
+}
+
+static errno_t get_entry_as_bool(struct ldb_message *msg,
+ bool *return_value,
+ const char *entry,
+ bool default_value)
+{
+ const char *tmp = NULL;
+
+ *return_value = 0;
+
+ if (!msg || !entry) {
+ return EFAULT;
+ }
+
+ tmp = ldb_msg_find_attr_as_string(msg, entry, NULL);
+ if (tmp == NULL || *tmp == '\0') {
+ *return_value = default_value;
+ return EOK;
+ }
+
+ if (strcasecmp(tmp, "FALSE") == 0) {
+ *return_value = 0;
+ }
+ else if (strcasecmp(tmp, "TRUE") == 0) {
+ *return_value = 1;
+ }
+ else {
+ return EINVAL;
+ }
+
+ return EOK;
+}
+
+static int confdb_get_domain_internal(struct confdb_ctx *cdb,
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct sss_domain_info **_domain)
+{
+ struct sss_domain_info *domain;
+ struct ldb_result *res;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn;
+ const char *tmp;
+ int ret, val;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) return ENOMEM;
+
+ dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb,
+ "cn=%s,%s", name, CONFDB_DOMAIN_BASEDN);
+ if (!dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ if (res->count != 1) {
+ DEBUG(0, ("Unknown domain [%s]\n", name));
+ ret = ENOENT;
+ goto done;
+ }
+
+ domain = talloc_zero(mem_ctx, struct sss_domain_info);
+ if (!domain) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], "cn", NULL);
+ if (!tmp) {
+ DEBUG(0, ("Invalid configuration entry, fatal error!\n"));
+ ret = EINVAL;
+ goto done;
+ }
+ domain->name = talloc_strdup(domain, tmp);
+ if (!domain->name) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_ID_PROVIDER,
+ NULL);
+ if (tmp) {
+ domain->provider = talloc_strdup(domain, tmp);
+ if (!domain->provider) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ else {
+ DEBUG(0, ("Domain [%s] does not specify an ID provider, disabling!\n",
+ domain->name));
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (strcasecmp(domain->provider, "files") == 0) {
+ /* The files provider is not valid anymore */
+ DEBUG(0, ("The \"files\" provider is invalid\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (strcasecmp(domain->provider, "local") == 0) {
+ /* If this is the local provider, we need to ensure that
+ * no other provider was specified for other types, since
+ * the local provider cannot load them.
+ */
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_AUTH_PROVIDER,
+ NULL);
+ if (tmp && strcasecmp(tmp, "local") != 0) {
+ DEBUG(0, ("Local ID provider does not support [%s] as an AUTH provider.\n", tmp));
+ ret = EINVAL;
+ goto done;
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_ACCESS_PROVIDER,
+ NULL);
+ if (tmp && strcasecmp(tmp, "local") != 0) {
+ DEBUG(0, ("Local ID provider does not support [%s] as an ACCESS provider.\n", tmp));
+ ret = EINVAL;
+ goto done;
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_CHPASS_PROVIDER,
+ NULL);
+ if (tmp && strcasecmp(tmp, "local") != 0) {
+ DEBUG(0, ("Local ID provider does not support [%s] as a CHPASS provider.\n", tmp));
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ domain->timeout = ldb_msg_find_attr_as_int(res->msgs[0],
+ CONFDB_DOMAIN_TIMEOUT, 0);
+
+ /* Determine if this domain can be enumerated */
+
+ /* TEMP: test if the old bitfield conf value is used and warn it has been
+ * superceeded. */
+ val = ldb_msg_find_attr_as_int(res->msgs[0], CONFDB_DOMAIN_ENUMERATE, 0);
+ if (val > 0) { /* ok there was a number in here */
+ DEBUG(0, ("Warning: enumeration parameter in %s still uses integers! "
+ "Enumeration is now a boolean and takes true/false values. "
+ "Interpreting as true\n", domain->name));
+ domain->enumerate = true;
+ } else { /* assume the new format */
+ ret = get_entry_as_bool(res->msgs[0], &domain->enumerate,
+ CONFDB_DOMAIN_ENUMERATE, 1);
+ if(ret != EOK) {
+ DEBUG(0, ("Invalid value for %s\n", CONFDB_DOMAIN_ENUMERATE));
+ goto done;
+ }
+ }
+ if (!domain->enumerate) {
+ DEBUG(1, ("No enumeration for [%s]!\n", domain->name));
+ }
+
+ /* Determine if user/group names will be Fully Qualified
+ * in NSS interfaces */
+ ret = get_entry_as_bool(res->msgs[0], &domain->fqnames, CONFDB_DOMAIN_FQ, 0);
+ if(ret != EOK) {
+ DEBUG(0, ("Invalid value for %s\n", CONFDB_DOMAIN_FQ));
+ goto done;
+ }
+
+ ret = get_entry_as_uint32(res->msgs[0], &domain->id_min,
+ CONFDB_DOMAIN_MINID, SSSD_MIN_ID);
+ if (ret != EOK) {
+ DEBUG(0, ("Invalid value for minId\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = get_entry_as_uint32(res->msgs[0], &domain->id_max,
+ CONFDB_DOMAIN_MAXID, 0);
+ if (ret != EOK) {
+ DEBUG(0, ("Invalid value for maxId\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (domain->id_max && (domain->id_max < domain->id_min)) {
+ DEBUG(0, ("Invalid domain range\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ /* Do we allow to cache credentials */
+ ret = get_entry_as_bool(res->msgs[0], &domain->cache_credentials,
+ CONFDB_DOMAIN_CACHE_CREDS, 0);
+ if(ret != EOK) {
+ DEBUG(0, ("Invalid value for %s\n", CONFDB_DOMAIN_CACHE_CREDS));
+ goto done;
+ }
+
+ ret = get_entry_as_bool(res->msgs[0], &domain->legacy_passwords,
+ CONFDB_DOMAIN_LEGACY_PASS, 0);
+ if(ret != EOK) {
+ DEBUG(0, ("Invalid value for %s\n", CONFDB_DOMAIN_LEGACY_PASS));
+ goto done;
+ }
+
+ *_domain = domain;
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_get_domains(struct confdb_ctx *cdb,
+ struct sss_domain_info **domains)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sss_domain_info *domain, *prevdom = NULL;
+ char **domlist;
+ int ret, i;
+
+ if (cdb->doms) {
+ *domains = cdb->doms;
+ return EOK;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ ret = confdb_get_string_as_list(cdb, tmp_ctx,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_ACTIVE_DOMAINS,
+ &domlist);
+ if (ret == ENOENT) {
+ DEBUG(0, ("No domains configured, fatal error!\n"));
+ goto done;
+ }
+ if (ret != EOK ) {
+ DEBUG(0, ("Fatal error retrieving domains list!\n"));
+ goto done;
+ }
+
+ for (i = 0; domlist[i]; i++) {
+ ret = confdb_get_domain_internal(cdb, cdb, domlist[i], &domain);
+ if (ret) {
+ DEBUG(0, ("Error (%d [%s]) retrieving domain [%s], skipping!\n",
+ ret, strerror(ret), domlist[i]));
+ ret = EOK;
+ continue;
+ }
+
+ if (cdb->doms == NULL) {
+ cdb->doms = domain;
+ prevdom = cdb->doms;
+ } else {
+ prevdom->next = domain;
+ prevdom = domain;
+ }
+ }
+
+ if (cdb->doms == NULL) {
+ DEBUG(0, ("No properly configured domains, fatal error!\n"));
+ ret = ENOENT;
+ goto done;
+ }
+
+ *domains = cdb->doms;
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_get_domain(struct confdb_ctx *cdb,
+ const char *name,
+ struct sss_domain_info **_domain)
+{
+ struct sss_domain_info *dom, *doms;
+ int ret;
+
+ ret = confdb_get_domains(cdb, &doms);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ for (dom = doms; dom; dom = dom->next) {
+ if (strcasecmp(dom->name, name) == 0) {
+ *_domain = dom;
+ return EOK;
+ }
+ }
+
+ return ENOENT;
+}
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
new file mode 100644
index 00000000..e848e8bc
--- /dev/null
+++ b/src/confdb/confdb.h
@@ -0,0 +1,364 @@
+/*
+ SSSD
+
+ NSS Configuratoin DB
+
+ 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/>.
+*/
+
+#ifndef _CONF_DB_H
+#define _CONF_DB_H
+
+#include <stdbool.h>
+#include "talloc.h"
+#include "tevent.h"
+#include "ldb.h"
+#include "ldb_errors.h"
+#include "config.h"
+
+/**
+ * @defgroup sss_confdb The ConfDB API
+ * The ConfDB is an interface for data providers to
+ * access the configuration information provided in
+ * the sssd.conf
+ * @{
+ */
+
+#define CONFDB_FILE "config.ldb"
+#define CONFDB_DEFAULT_CONFIG_FILE SSSD_CONF_DIR"/sssd.conf"
+#define SSSD_MIN_ID 1000
+
+
+/* Configuration options */
+
+/* Services */
+#define CONFDB_SERVICE_PATH_TMPL "config/%s"
+#define CONFDB_SERVICE_COMMAND "command"
+#define CONFDB_SERVICE_DEBUG_LEVEL "debug_level"
+#define CONFDB_SERVICE_DEBUG_TIMESTAMPS "debug_timestamps"
+#define CONFDB_SERVICE_DEBUG_TO_FILES "debug_to_files"
+#define CONFDB_SERVICE_TIMEOUT "timeout"
+#define CONFDB_SERVICE_RECON_RETRIES "reconnection_retries"
+
+/* Monitor */
+#define CONFDB_MONITOR_CONF_ENTRY "config/sssd"
+#define CONFDB_MONITOR_SBUS_TIMEOUT "sbus_timeout"
+#define CONFDB_MONITOR_ACTIVE_SERVICES "services"
+#define CONFDB_MONITOR_ACTIVE_DOMAINS "domains"
+#define CONFDB_MONITOR_NAME_REGEX "re_expression"
+#define CONFDB_MONITOR_FULL_NAME_FORMAT "full_name_format"
+
+/* NSS */
+#define CONFDB_NSS_CONF_ENTRY "config/nss"
+#define CONFDB_NSS_ENUM_CACHE_TIMEOUT "enum_cache_timeout"
+#define CONFDB_NSS_ENTRY_CACHE_NOWAIT_PERCENTAGE "entry_cache_nowait_percentage"
+#define CONFDB_NSS_ENTRY_NEG_TIMEOUT "entry_negative_timeout"
+#define CONFDB_NSS_FILTER_USERS_IN_GROUPS "filter_users_in_groups"
+#define CONFDB_NSS_FILTER_USERS "filter_users"
+#define CONFDB_NSS_FILTER_GROUPS "filter_groups"
+#define CONFDB_NSS_PWFIELD "pwfield"
+
+/* PAM */
+#define CONFDB_PAM_CONF_ENTRY "config/pam"
+#define CONFDB_PAM_CRED_TIMEOUT "offline_credentials_expiration"
+#define CONFDB_PAM_FAILED_LOGIN_ATTEMPTS "offline_failed_login_attempts"
+#define CONFDB_DEFAULT_PAM_FAILED_LOGIN_ATTEMPTS 0
+#define CONFDB_PAM_FAILED_LOGIN_DELAY "offline_failed_login_delay"
+#define CONFDB_DEFAULT_PAM_FAILED_LOGIN_DELAY 5
+
+/* Data Provider */
+#define CONFDB_DP_CONF_ENTRY "config/dp"
+
+/* Domains */
+#define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s"
+#define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config"
+#define CONFDB_DOMAIN_ID_PROVIDER "id_provider"
+#define CONFDB_DOMAIN_AUTH_PROVIDER "auth_provider"
+#define CONFDB_DOMAIN_ACCESS_PROVIDER "access_provider"
+#define CONFDB_DOMAIN_CHPASS_PROVIDER "chpass_provider"
+#define CONFDB_DOMAIN_COMMAND "command"
+#define CONFDB_DOMAIN_TIMEOUT "timeout"
+#define CONFDB_DOMAIN_ATTR "cn"
+#define CONFDB_DOMAIN_ENUMERATE "enumerate"
+#define CONFDB_DOMAIN_MINID "min_id"
+#define CONFDB_DOMAIN_MAXID "max_id"
+#define CONFDB_DOMAIN_CACHE_CREDS "cache_credentials"
+#define CONFDB_DOMAIN_LEGACY_PASS "store_legacy_passwords"
+#define CONFDB_DOMAIN_MPG "magic_private_groups"
+#define CONFDB_DOMAIN_FQ "use_fully_qualified_names"
+#define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout"
+
+/* Local Provider */
+#define CONFDB_LOCAL_DEFAULT_SHELL "default_shell"
+#define CONFDB_LOCAL_DEFAULT_BASEDIR "base_directory"
+#define CONFDB_LOCAL_CREATE_HOMEDIR "create_homedir"
+#define CONFDB_LOCAL_REMOVE_HOMEDIR "remove_homedir"
+#define CONFDB_LOCAL_UMASK "homedir_umask"
+#define CONFDB_LOCAL_SKEL_DIR "skel_dir"
+#define CONFDB_LOCAL_MAIL_DIR "mail_dir"
+
+/* Proxy Provider */
+#define CONFDB_PROXY_LIBNAME "proxy_lib_name"
+#define CONFDB_PROXY_PAM_TARGET "proxy_pam_target"
+
+/* KRB5 Provider */
+#define CONFDB_KRB5_KDCIP "krb5_kdcip"
+#define CONFDB_KRB5_REALM "krb5_realm"
+#define CONFDB_KRB5_CCACHEDIR "krb5_ccachedir"
+#define CONFDB_KRB5_CCNAME_TMPL "krb5_ccname_template"
+#define CONFDB_KRB5_CHANGEPW_PRINC "krb5_changepw_principal"
+#define CONFDB_KRB5_AUTH_TIMEOUT "krb5_auth_timeout"
+
+struct confdb_ctx;
+struct config_file_ctx;
+
+/**
+ * Data structure storing all of the basic features
+ * of a domain.
+ */
+struct sss_domain_info {
+ char *name;
+ char *provider;
+ int timeout;
+ bool enumerate;
+ bool fqnames;
+ uint32_t id_min;
+ uint32_t id_max;
+
+ bool cache_credentials;
+ bool legacy_passwords;
+
+ struct sss_domain_info *next;
+};
+
+/**
+ * Initialize the connection to the ConfDB
+ *
+ * @param[in] mem_ctx The parent memory context for the confdb_ctx
+ * @param[out] cdb_ctx The newly-created connection object
+ * @param[in] confdb_location The absolute path to the ConfDB file on the
+ * filesystem
+ *
+ * @return 0 - Connection succeeded and cdb_ctx was populated
+ * @return ENOMEM - There was not enough memory to create the cdb_ctx
+ * @return EIO - There was an I/O error communicating with the ConfDB file
+ */
+int confdb_init(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx **cdb_ctx,
+ char *confdb_location);
+
+/**
+ * Get a domain object for the named domain
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] name The name of the domain to retrieve
+ * @param[out] domain A pointer to a domain object for the domain given by
+ * name
+ *
+ * @return 0 - Lookup succeeded and domain was populated
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return ENOENT - The named domain does not exist or is not set active
+ */
+int confdb_get_domain(struct confdb_ctx *cdb,
+ const char *name,
+ struct sss_domain_info **domain);
+
+/**
+ * Get a null-terminated linked-list of active domain objects
+ * @param[in] cdb The connection object to the confdb
+ * @param[out] domains A pointer to the first entry of a linked-list of domain
+ * objects
+ *
+ * @return 0 - Lookup succeeded and all active domains are in the list
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return ENOENT - No active domains are configured
+ */
+int confdb_get_domains(struct confdb_ctx *cdb,
+ struct sss_domain_info **domains);
+
+
+/**
+ * @brief Add an arbitrary parameter to the confdb.
+ *
+ * This is mostly useful
+ * for testing, as they will not persist between SSSD restarts. For
+ * persistence, make changes to the sssd.conf file.
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] replace If replace is set to true, pre-existing values will be
+ * overwritten.
+ * If it is false, the provided values will be added to the
+ * attribute.
+ * @param[in] section The ConfDB section to update. This is constructed from
+ * the format of the sssd.conf file. All sections start
+ * with 'config/'. Subsections are separated by slashes.
+ * e.g. [domain/LDAP] in sssd.conf would translate to
+ * config/domain/LDAP
+ * @param[in] attribute The name of the attribute to update
+ * @param[in] values A null-terminated array of values to add to the attribute
+ *
+ * @return 0 - Successfully added the provided value(s)
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return EINVAL - The section could not be parsed
+ * @return EIO - An I/O error occurred communicating with the ConfDB
+ */
+int confdb_add_param(struct confdb_ctx *cdb,
+ bool replace,
+ const char *section,
+ const char *attribute,
+ const char **values);
+
+/**
+ * @brief Retrieve all values for an attribute
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] mem_ctx The parent memory context for the value list
+ * @param[in] section The ConfDB section to update. This is constructed from
+ * the format of the sssd.conf file. All sections start
+ * with 'config/'. Subsections are separated by slashes.
+ * e.g. [domain/LDAP] in sssd.conf would translate to
+ * config/domain/LDAP
+ * @param[in] attribute The name of the attribute to update
+ * @param[out] values A null-terminated array of cstrings containing all
+ * values for this attribute
+ *
+ * @return 0 - Successfully retrieved the value(s)
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return EINVAL - The section could not be parsed
+ * @return EIO - An I/O error occurred while communicating with the ConfDB
+ */
+int confdb_get_param(struct confdb_ctx *cdb,
+ TALLOC_CTX *mem_ctx,
+ const char *section,
+ const char *attribute,
+ char ***values);
+
+/**
+ * @brief Convenience function to retrieve a single-valued attribute as a
+ * string
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] ctx The parent memory context for the returned string
+ * @param[in] section The ConfDB section to update. This is constructed from
+ * the format of the sssd.conf file. All sections start
+ * with 'config/'. Subsections are separated by slashes.
+ * e.g. [domain/LDAP] in sssd.conf would translate to
+ * config/domain/LDAP
+ * @param[in] attribute The name of the attribute to update
+ * @param[in] defstr If not NULL, the string to use if the attribute does not
+ * exist in the ConfDB
+ * @param[out] result A pointer to the retrieved (or default) string
+ *
+ * @return 0 - Successfully retrieved the entry (or used the default)
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return EINVAL - The section could not be parsed, or the attribute was not
+ * single-valued.
+ * @return EIO - An I/O error occurred while communicating with the ConfDB
+ */
+int confdb_get_string(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ const char *defstr, char **result);
+
+/**
+ * @brief Convenience function to retrieve a single-valued attribute as an
+ * integer
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] ctx The parent memory context for the returned string
+ * @param[in] section The ConfDB section to update. This is constructed from
+ * the format of the sssd.conf file. All sections start
+ * with 'config/'. Subsections are separated by slashes.
+ * e.g. [domain/LDAP] in sssd.conf would translate to
+ * config/domain/LDAP
+ * @param[in] attribute The name of the attribute to update
+ * @param[in] defval If not NULL, the integer to use if the attribute does not
+ * exist in the ConfDB
+ * @param[out] result A pointer to the retrieved (or default) integer
+ *
+ * @return 0 - Successfully retrieved the entry (or used the default)
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return EINVAL - The section could not be parsed, or the attribute was not
+ * single-valued.
+ * @return EIO - An I/O error occurred while communicating with the ConfDB
+ * @return ERANGE - The value stored in the ConfDB was outside the range
+ * [INT_MIN..INT_MAX]
+ */
+int confdb_get_int(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ int defval, int *result);
+
+/**
+ * @brief Convenience function to retrieve a single-valued attribute as a
+ * boolean
+ *
+ * This function will read (in a case-insensitive manner) a "true" or "false"
+ * value from the ConfDB and convert it to an integral bool value.
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] ctx The parent memory context for the returned string
+ * @param[in] section The ConfDB section to update. This is constructed from
+ * the format of the sssd.conf file. All sections start
+ * with 'config/'. Subsections are separated by slashes.
+ * e.g. [domain/LDAP] in sssd.conf would translate to
+ * config/domain/LDAP
+ * @param[in] attribute The name of the attribute to update
+ * @param[in] defval If not NULL, the boolean state to use if the attribute
+ * does not exist in the ConfDB
+ * @param[out] result A pointer to the retrieved (or default) bool
+ *
+ * @return 0 - Successfully retrieved the entry (or used the default)
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return EINVAL - The section could not be parsed, the attribute was not
+ * single-valued, or the value was not a boolean.
+ * @return EIO - An I/O error occurred while communicating with the ConfDB
+ */
+int confdb_get_bool(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ bool defval, bool *result);
+
+/**
+ * @brief Convenience function to retrieve a single-valued attribute as a
+ * null-terminated array of strings
+ *
+ * This function will automatically split a comma-separated string in an
+ * attribute into a null-terminated array of strings. This is useful for
+ * storing and retrieving ordered lists, as ConfDB multivalued attributes do
+ * not guarantee retrieval order.
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] ctx The parent memory context for the returned string
+ * @param[in] section The ConfDB section to update. This is constructed from
+ * the format of the sssd.conf file. All sections start
+ * with 'config/'. Subsections are separated by slashes.
+ * e.g. [domain/LDAP] in sssd.conf would translate to
+ * config/domain/LDAP
+ * @param[in] attribute The name of the attribute to update
+ * @param[out] result A pointer to the retrieved array of strings
+ *
+ * @return 0 - Successfully retrieved the entry (or used the default)
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return EINVAL - The section could not be parsed, or the attribute was not
+ * single-valued.
+ * @return ENOENT - The attribute was not found.
+ * @return EIO - An I/O error occurred while communicating with the ConfDB
+ */
+int confdb_get_string_as_list(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
+ const char *section, const char *attribute,
+ char ***result);
+/**
+ * @}
+ */
+#endif
diff --git a/src/confdb/confdb_private.h b/src/confdb/confdb_private.h
new file mode 100644
index 00000000..1bab99ca
--- /dev/null
+++ b/src/confdb/confdb_private.h
@@ -0,0 +1,35 @@
+/*
+ SSSD
+
+ Configuration Database
+
+ Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009
+
+ 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/>.
+*/
+
+#ifndef CONFDB_PRIVATE_H_
+#define CONFDB_PRIVATE_H_
+
+struct confdb_ctx {
+ struct tevent_context *pev;
+ struct ldb_context *ldb;
+
+ struct sss_domain_info *doms;
+};
+
+int parse_section(TALLOC_CTX *mem_ctx, const char *section,
+ char **sec_dn, const char **rdn_name);
+
+#endif /* CONFDB_PRIVATE_H_ */
diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
new file mode 100644
index 00000000..3c10c06c
--- /dev/null
+++ b/src/confdb/confdb_setup.c
@@ -0,0 +1,423 @@
+/*
+ SSSD
+
+ Configuration Database
+
+ Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009
+
+ 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 "config.h"
+#include <sys/stat.h>
+#include "util/util.h"
+#include "db/sysdb.h"
+#include "confdb.h"
+#include "confdb_private.h"
+#include "confdb_setup.h"
+#include "collection.h"
+#include "collection_tools.h"
+#include "ini_config.h"
+
+
+int confdb_test(struct confdb_ctx *cdb)
+{
+ char **values;
+ int ret;
+
+ ret = confdb_get_param(cdb, cdb,
+ "config",
+ "version",
+ &values);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (values[0] == NULL) {
+ /* empty database, will need to init */
+ talloc_free(values);
+ return ENOENT;
+ }
+
+ if (values[1] != NULL) {
+ /* more than 1 value ?? */
+ talloc_free(values);
+ return EIO;
+ }
+
+ if (strcmp(values[0], CONFDB_VERSION) != 0) {
+ /* Existing version does not match executable version */
+ DEBUG(1, ("Upgrading confdb version from %s to %s\n",
+ values[0], CONFDB_VERSION));
+
+ /* This is recoverable, since we purge the confdb file
+ * when we re-initialize it.
+ */
+ talloc_free(values);
+ return ENOENT;
+ }
+
+ talloc_free(values);
+ return EOK;
+}
+
+static int confdb_purge(struct confdb_ctx *cdb)
+{
+ int ret, i;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ struct ldb_dn *dn;
+ const char *attrs[] = { "dn", NULL };
+
+ tmp_ctx = talloc_new(NULL);
+
+ dn = ldb_dn_new(tmp_ctx, cdb->ldb, "cn=config");
+
+ /* Get the list of all DNs */
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn,
+ LDB_SCOPE_SUBTREE, attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ for(i=0; i<res->count; i++) {
+ /* Delete this DN */
+ ret = ldb_delete(cdb->ldb, res->msgs[i]->dn);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_create_base(struct confdb_ctx *cdb)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+
+ const char *base_ldif = CONFDB_BASE_LDIF;
+
+ while ((ldif = ldb_ldif_read_string(cdb->ldb, &base_ldif))) {
+ ret = ldb_add(cdb->ldb, ldif->msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("Failed to initialize DB (%d,[%s]), aborting!\n",
+ ret, ldb_errstring(cdb->ldb)));
+ return EIO;
+ }
+ ldb_ldif_read_free(cdb->ldb, ldif);
+ }
+
+ return EOK;
+}
+
+static int confdb_create_ldif(TALLOC_CTX *mem_ctx,
+ struct collection_item *sssd_config,
+ char **config_ldif)
+{
+ int ret, i, j;
+ char *ldif;
+ char *tmp_ldif;
+ char *writer;
+ char **sections;
+ int section_count;
+ char *dn;
+ char *tmp_dn;
+ char *sec_dn;
+ char **attrs;
+ int attr_count;
+ char *ldif_attr;
+ struct collection_item *attr;
+ TALLOC_CTX *tmp_ctx;
+ size_t dn_size;
+ size_t ldif_len;
+ size_t attr_len;
+
+ ldif_len = strlen(CONFDB_INTERNAL_LDIF);
+ ldif = talloc_array(mem_ctx, char, ldif_len+1);
+ if (!ldif) return ENOMEM;
+
+ tmp_ctx = talloc_new(ldif);
+ if (!tmp_ctx) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ memcpy(ldif, CONFDB_INTERNAL_LDIF, ldif_len);
+ writer = ldif+ldif_len;
+
+ /* Read in the collection and convert it to an LDIF */
+ /* Get the list of sections */
+ sections = get_section_list(sssd_config, &section_count, &ret);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ for(i = 0; i < section_count; i++) {
+ const char *rdn = NULL;
+ DEBUG(6,("Processing config section [%s]\n", sections[i]));
+ ret = parse_section(tmp_ctx, sections[i], &sec_dn, &rdn);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ dn = talloc_asprintf(tmp_ctx,
+ "dn: %s,cn=config\n"
+ "cn: %s\n",
+ sec_dn, rdn);
+ if(!dn) {
+ ret = ENOMEM;
+ free_section_list(sections);
+ goto error;
+ }
+ dn_size = strlen(dn);
+
+ /* Get all of the attributes and their values as LDIF */
+ attrs = get_attribute_list(sssd_config, sections[i],
+ &attr_count, &ret);
+ if (ret != EOK) {
+ free_section_list(sections);
+ goto error;
+ }
+
+ for(j = 0; j < attr_count; j++) {
+ DEBUG(6, ("Processing attribute [%s]\n", attrs[j]));
+ ret = get_config_item(sections[i], attrs[j], sssd_config,
+ &attr);
+ if (ret != EOK) goto error;
+
+ const char *value = get_const_string_config_value(attr, &ret);
+ if (ret != EOK) goto error;
+
+ ldif_attr = talloc_asprintf(tmp_ctx,
+ "%s: %s\n", attrs[j], value);
+ DEBUG(9, ("%s", ldif_attr));
+
+ attr_len = strlen(ldif_attr);
+
+ tmp_dn = talloc_realloc(tmp_ctx, dn, char,
+ dn_size+attr_len+1);
+ if(!tmp_dn) {
+ ret = ENOMEM;
+ free_attribute_list(attrs);
+ free_section_list(sections);
+ goto error;
+ }
+ dn = tmp_dn;
+ memcpy(dn+dn_size, ldif_attr, attr_len+1);
+ dn_size += attr_len;
+ }
+
+ dn_size ++;
+ tmp_dn = talloc_realloc(tmp_ctx, dn, char,
+ dn_size+1);
+ if(!tmp_dn) {
+ ret = ENOMEM;
+ free_attribute_list(attrs);
+ free_section_list(sections);
+ goto error;
+ }
+ dn = tmp_dn;
+ dn[dn_size-1] = '\n';
+ dn[dn_size] = '\0';
+
+ DEBUG(9, ("Section dn\n%s", dn));
+
+ tmp_ldif = talloc_realloc(mem_ctx, ldif, char,
+ ldif_len+dn_size+1);
+ if(!tmp_ldif) {
+ ret = ENOMEM;
+ free_attribute_list(attrs);
+ free_section_list(sections);
+ goto error;
+ }
+ ldif = tmp_ldif;
+ memcpy(ldif+ldif_len, dn, dn_size);
+ ldif_len += dn_size;
+
+ free_attribute_list(attrs);
+ talloc_free(dn);
+ }
+
+ ldif[ldif_len] = '\0';
+
+ free_section_list(sections);
+
+ *config_ldif = ldif;
+ talloc_free(tmp_ctx);
+ return EOK;
+
+error:
+ talloc_free(ldif);
+ return ret;
+}
+
+int confdb_init_db(const char *config_file, struct confdb_ctx *cdb)
+{
+ int ret, i;
+ int fd = -1;
+ struct collection_item *sssd_config = NULL;
+ struct collection_item *error_list = NULL;
+ struct collection_item *item = NULL;
+ char *config_ldif;
+ struct ldb_ldif *ldif;
+ TALLOC_CTX *tmp_ctx;
+ char *lasttimestr, timestr[21];
+ const char *vals[2] = { timestr, NULL };
+ struct stat cstat;
+ int version;
+
+ tmp_ctx = talloc_new(cdb);
+ if (tmp_ctx == NULL) return ENOMEM;
+
+ ret = check_and_open_readonly(config_file, &fd, 0, 0, (S_IRUSR|S_IWUSR));
+ if (ret != EOK) {
+ DEBUG(1, ("Permission check on config file failed.\n"));
+ talloc_zfree(tmp_ctx);
+ return EIO;
+ }
+
+ /* Determine if the conf file has changed since we last updated
+ * the confdb
+ */
+ ret = fstat(fd, &cstat);
+ if (ret != 0) {
+ DEBUG(0, ("Unable to stat config file [%s]! (%d [%s])\n",
+ config_file, errno, strerror(errno)));
+ close(fd);
+ talloc_zfree(tmp_ctx);
+ return errno;
+ }
+ ret = snprintf(timestr, 21, "%llu", (long long unsigned)cstat.st_mtime);
+ if (ret <= 0 || ret >= 21) {
+ DEBUG(0, ("Failed to convert time_t to string ??\n"));
+ close(fd);
+ talloc_zfree(tmp_ctx);
+ return errno ? errno: EFAULT;
+ }
+
+ /* check if we need to re-init the db */
+ ret = confdb_get_string(cdb, tmp_ctx, "config", "lastUpdate", NULL, &lasttimestr);
+ if (ret == EOK && lasttimestr != NULL) {
+
+ /* now check if we lastUpdate and last file modification change differ*/
+ if (strcmp(lasttimestr, timestr) == 0) {
+ /* not changed, get out, nothing more to do */
+ close(fd);
+ talloc_zfree(tmp_ctx);
+ return EOK;
+ }
+ }
+
+ /* Set up a transaction to replace the configuration */
+ ret = ldb_transaction_start(cdb->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("Failed to start a transaction for updating the configuration\n"));
+ talloc_zfree(tmp_ctx);
+ close(fd);
+ return sysdb_error_to_errno(ret);
+ }
+
+ /* Purge existing database */
+ ret = confdb_purge(cdb);
+ if (ret != EOK) {
+ DEBUG(0, ("Could not purge existing configuration\n"));
+ close(fd);
+ goto done;
+ }
+
+ /* Read the configuration into a collection */
+ ret = config_from_fd("sssd", fd, config_file, &sssd_config,
+ INI_STOP_ON_ANY, &error_list);
+ close(fd);
+ if (ret != EOK) {
+ DEBUG(0, ("Parse error reading configuration file [%s]\n",
+ config_file));
+ print_file_parsing_errors(stderr, error_list);
+ free_ini_config_errors(error_list);
+ free_ini_config(sssd_config);
+ goto done;
+ }
+
+ /* Make sure that the config file version matches the confdb version */
+ ret = get_config_item("sssd", "config_file_version",
+ sssd_config, &item);
+ if (ret != EOK) {
+ DEBUG(0, ("Internal error determining config_file_version\n"));
+ goto done;
+ }
+ if (item == NULL) {
+ /* No known version. Assumed to be version 1 */
+ DEBUG(0, ("Config file is an old version. "
+ "Please run configuration upgrade script.\n"));
+ ret = EINVAL;
+ goto done;
+ }
+ version = get_int_config_value(item, 1, -1, &ret);
+ if (ret != EOK) {
+ DEBUG(0, ("Config file version could not be determined\n"));
+ goto done;
+ } else if (version < CONFDB_VERSION_INT) {
+ DEBUG(0, ("Config file is an old version. "
+ "Please run configuration upgrade script.\n"));
+ ret = EINVAL;
+ goto done;
+ } else if (version > CONFDB_VERSION_INT) {
+ DEBUG(0, ("Config file version is newer than confdb\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = confdb_create_ldif(tmp_ctx, sssd_config, &config_ldif);
+ free_ini_config(sssd_config);
+ if (ret != EOK) {
+ DEBUG(0, ("Could not create LDIF for confdb\n"));
+ goto done;
+ }
+
+ DEBUG(7, ("LDIF file to import: \n%s", config_ldif));
+
+ i=0;
+ while ((ldif = ldb_ldif_read_string(cdb->ldb, (const char **)&config_ldif))) {
+ ret = ldb_add(cdb->ldb, ldif->msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("Failed to initialize DB (%d,[%s]), aborting!\n",
+ ret, ldb_errstring(cdb->ldb)));
+ ret = EIO;
+ goto done;
+ }
+ ldb_ldif_read_free(cdb->ldb, ldif);
+ }
+
+ /* now store the lastUpdate time so that we do not re-init if nothing
+ * changed on restart */
+
+ ret = confdb_add_param(cdb, true, "config", "lastUpdate", vals);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to set last update time on db!\n"));
+ }
+
+ ret = EOK;
+
+done:
+ ret == EOK ?
+ ldb_transaction_commit(cdb->ldb) :
+ ldb_transaction_cancel(cdb->ldb);
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
diff --git a/src/confdb/confdb_setup.h b/src/confdb/confdb_setup.h
new file mode 100644
index 00000000..2b8802f6
--- /dev/null
+++ b/src/confdb/confdb_setup.h
@@ -0,0 +1,52 @@
+/*
+ SSSD
+
+ Configuration Database
+
+ Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009
+
+ 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/>.
+*/
+
+#ifndef CONFDB_SETUP_H_
+#define CONFDB_SETUP_H_
+
+#define CONFDB_VERSION "2"
+#define CONFDB_VERSION_INT 2
+
+#define CONFDB_BASE_LDIF \
+ "dn: @ATTRIBUTES\n" \
+ "cn: CASE_INSENSITIVE\n" \
+ "dc: CASE_INSENSITIVE\n" \
+ "dn: CASE_INSENSITIVE\n" \
+ "name: CASE_INSENSITIVE\n" \
+ "objectclass: CASE_INSENSITIVE\n" \
+ "\n" \
+ "dn: @INDEXLIST\n" \
+ "@IDXATTR: cn\n" \
+ "\n" \
+ "dn: @MODULES\n" \
+ "@LIST: server_sort\n" \
+ "\n"
+
+#define CONFDB_INTERNAL_LDIF \
+ "dn: cn=config\n" \
+ "version: "CONFDB_VERSION"\n" \
+ "\n"
+
+int confdb_create_base(struct confdb_ctx *cdb);
+int confdb_test(struct confdb_ctx *cdb);
+int confdb_init_db(const char *config_file, struct confdb_ctx *cdb);
+
+#endif /* CONFDB_SETUP_H_ */