diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2010-02-18 07:49:04 -0500 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2010-02-18 13:48:45 -0500 |
commit | 1c48b5a62f73234ed26bb20f0ab345ab61cda0ab (patch) | |
tree | 0b6cddd567a862e1a7b5df23764869782a62ca78 /src/confdb | |
parent | 8c56df3176f528fe0260974b3bf934173c4651ea (diff) | |
download | sssd-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.c | 908 | ||||
-rw-r--r-- | src/confdb/confdb.h | 364 | ||||
-rw-r--r-- | src/confdb/confdb_private.h | 35 | ||||
-rw-r--r-- | src/confdb/confdb_setup.c | 423 | ||||
-rw-r--r-- | src/confdb/confdb_setup.h | 52 |
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, §ion_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_ */ |