summaryrefslogtreecommitdiffstats
path: root/src/confdb
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/confdb
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/confdb')
-rw-r--r--src/confdb/confdb.c2826
-rw-r--r--src/confdb/confdb.h785
-rw-r--r--src/confdb/confdb_private.h35
-rw-r--r--src/confdb/confdb_setup.c444
-rw-r--r--src/confdb/confdb_setup.h55
5 files changed, 4145 insertions, 0 deletions
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
new file mode 100644
index 0000000..a7344e1
--- /dev/null
+++ b/src/confdb/confdb.c
@@ -0,0 +1,2826 @@
+/*
+ SSSD
+
+ SSSD Configuration 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/>.
+*/
+
+#include "config.h"
+
+#include <ctype.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)
+
+/* Warning messages */
+#define SAME_DOMAINS_ERROR_MSG "Domain '%s' is the same as or differs only "\
+ "in case from domain '%s'.\n"
+
+#define RETRIEVE_DOMAIN_ERROR_MSG "Error (%d [%s]) retrieving domain [%s], "\
+ "skipping!\n"
+
+#ifdef BUILD_FILES_PROVIDER
+/* SSSD domain name that is used for the auto-configured files domain */
+#define IMPLICIT_FILES_DOMAIN_NAME "implicit_files"
+#endif
+
+static int confdb_get_domain_enabled(struct confdb_ctx *cdb,
+ const char *domain, bool *_enabled);
+
+
+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) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "ldb_modify failed: [%s](%d)[%s]\n",
+ ldb_strerror(ret), ret, ldb_errstring(cdb->ldb));
+ ret = EIO;
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to add [%s] to [%s], error [%d] (%s)\n",
+ 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 = NULL;
+ 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(SSSDBG_CRIT_FAILURE,
+ "Failed to get [%s] from [%s], error [%d] (%s)\n",
+ attribute, section, ret, strerror(ret));
+ }
+ return ret;
+}
+
+int confdb_set_string(struct confdb_ctx *cdb,
+ const char *section,
+ const char *attribute,
+ const char *val)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn;
+ char *secdn;
+ struct ldb_message *msg;
+ int ret, lret;
+
+ tmp_ctx = talloc_new(NULL);
+ 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;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = dn;
+
+ lret = ldb_msg_add_empty(msg, attribute, LDB_FLAG_MOD_REPLACE, NULL);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "ldb_msg_add_empty failed: [%s]\n", ldb_strerror(lret));
+ ret = EIO;
+ goto done;
+ }
+
+ lret = ldb_msg_add_string(msg, attribute, val);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "ldb_msg_add_string failed: [%s]\n", ldb_strerror(lret));
+ ret = EIO;
+ goto done;
+ }
+
+ lret = ldb_modify(cdb->ldb, msg);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "ldb_modify failed: [%s](%d)[%s]\n",
+ ldb_strerror(lret), lret, ldb_errstring(cdb->ldb));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to set [%s] from [%s], error [%d] (%s)\n",
+ 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(SSSDBG_CRIT_FAILURE,
+ "Failed to get [%s] from [%s], error [%d] (%s)\n",
+ attribute, section, ret, strerror(ret));
+ return ret;
+}
+
+int confdb_get_int(struct confdb_ctx *cdb,
+ const char *section, const char *attribute,
+ int defval, int *result)
+{
+ char **values = NULL;
+ long val;
+ int ret;
+ char *endptr;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto failed;
+ }
+
+ ret = confdb_get_param(cdb, tmp_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], &endptr, 0);
+ ret = errno;
+ if (ret != 0) {
+ goto failed;
+ }
+ if (*endptr || (values[0] == endptr)) {
+ ret = EINVAL;
+ goto failed;
+ }
+ if (val < INT_MIN || val > INT_MAX) {
+ ret = ERANGE;
+ goto failed;
+ }
+
+ } else {
+ val = defval;
+ }
+
+ talloc_free(tmp_ctx);
+
+ *result = (int)val;
+ return EOK;
+
+failed:
+ talloc_free(tmp_ctx);
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read [%s] from [%s], error [%d] (%s)\n",
+ attribute, section, ret, strerror(ret));
+ return ret;
+}
+
+long confdb_get_long(struct confdb_ctx *cdb,
+ const char *section, const char *attribute,
+ long defval, long *result)
+{
+ char **values = NULL;
+ long val;
+ int ret;
+ char *endptr;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto failed;
+ }
+
+ ret = confdb_get_param(cdb, tmp_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], &endptr, 0);
+ ret = errno;
+ if (ret != 0) {
+ goto failed;
+ }
+ if (*endptr || (values[0] == endptr)) {
+ ret = EINVAL;
+ goto failed;
+ }
+ } else {
+ val = defval;
+ }
+
+ talloc_free(tmp_ctx);
+
+ *result = val;
+ return EOK;
+
+failed:
+ talloc_free(tmp_ctx);
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read [%s] from [%s], error [%d] (%s)\n",
+ attribute, section, ret, strerror(ret));
+ return ret;
+}
+
+int confdb_get_bool(struct confdb_ctx *cdb,
+ const char *section, const char *attribute,
+ bool defval, bool *result)
+{
+ char **values = NULL;
+ bool val;
+ int ret;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto failed;
+ }
+
+ ret = confdb_get_param(cdb, tmp_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(SSSDBG_OP_FAILURE, "Value is not a boolean!\n");
+ ret = EINVAL;
+ goto failed;
+ }
+
+ } else {
+ val = defval;
+ }
+
+ talloc_free(tmp_ctx);
+
+ *result = val;
+ return EOK;
+
+failed:
+ talloc_free(tmp_ctx);
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read [%s] from [%s], error [%d] (%s)\n",
+ 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, true, result, NULL);
+
+done:
+ talloc_free(values);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to get [%s] from [%s], error [%d] (%s)\n",
+ attribute, section, ret, strerror(ret));
+ }
+ return ret;
+}
+
+int confdb_init(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx **cdb_ctx,
+ const char *confdb_location)
+{
+ struct confdb_ctx *cdb;
+ int ret = EOK;
+ mode_t old_umask;
+ uid_t sssd_uid;
+ gid_t sssd_gid;
+
+ 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(SSSDBG_FATAL_FAILURE,"Could not set up debug fn.\n");
+ talloc_free(cdb);
+ return EIO;
+ }
+
+ old_umask = umask(SSS_DFL_UMASK);
+ /* file may exists and could be owned by root from previous version */
+ sss_sssd_user_uid_and_gid(&sssd_uid, &sssd_gid);
+ ret = chown(confdb_location, sssd_uid, sssd_gid);
+ if (ret != EOK && errno != ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to chown config database [%s]: %s\n",
+ confdb_location, sss_strerror(errno));
+ }
+ sss_set_sssd_user_eid();
+
+ ret = ldb_connect(cdb->ldb, confdb_location, 0, NULL);
+
+ sss_restore_sssd_user_eid();
+ umask(old_umask);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "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;
+}
+
+
+/* The default UID/GID for domains is 1. */
+static uint32_t confdb_get_min_id(struct sss_domain_info *domain)
+{
+ return SSSD_MIN_ID;
+}
+
+static errno_t init_cached_auth_timeout(struct confdb_ctx *cdb,
+ struct ldb_message *msg,
+ uint32_t *_cached_auth_timeout)
+{
+ int cred_expiration;
+ int id_timeout;
+ errno_t ret;
+ uint32_t cached_auth_timeout;
+
+ ret = get_entry_as_uint32(msg, &cached_auth_timeout,
+ CONFDB_DOMAIN_CACHED_AUTH_TIMEOUT, 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n", CONFDB_DOMAIN_CACHED_AUTH_TIMEOUT);
+ goto done;
+ }
+
+ ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
+ CONFDB_PAM_CRED_TIMEOUT, 0, &cred_expiration);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read expiration time [%s] of offline credentials.\n",
+ CONFDB_PAM_CRED_TIMEOUT);
+ goto done;
+ }
+
+ /* convert from days to seconds */
+ cred_expiration *= 3600 * 24;
+ if (cred_expiration != 0 &&
+ cred_expiration < cached_auth_timeout) {
+ cached_auth_timeout = cred_expiration;
+ }
+
+ /* Set up the PAM identity timeout */
+ ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
+ CONFDB_PAM_ID_TIMEOUT, 5,
+ &id_timeout);
+ if (ret != EOK) goto done;
+
+ if (cached_auth_timeout > id_timeout) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "cached_auth_timeout is greater than pam_id_timeout so be aware "
+ "that back end could be called to handle initgroups.\n");
+ }
+
+ ret = EOK;
+
+done:
+ if (ret == EOK) {
+ *_cached_auth_timeout = cached_auth_timeout;
+ }
+ return ret;
+}
+
+static int confdb_get_domain_section(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ const char *section,
+ const char *name,
+ struct ldb_result **_res)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_result *res;
+ struct ldb_dn *dn;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", name, section);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = sss_ldb_error_to_errno(ret);
+ goto done;
+ }
+
+ if (res->count == 0) {
+ ret = ENOENT;
+ goto done;
+ } else if (res->count > 1) {
+ ret = E2BIG;
+ goto done;
+ }
+
+ *_res = talloc_steal(mem_ctx, res);
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static char *confdb_get_domain_hostname(TALLOC_CTX *mem_ctx,
+ struct ldb_result *res,
+ const char *provider)
+{
+ char sys[HOST_NAME_MAX + 1] = {'\0'};
+ const char *opt = NULL;
+ int ret;
+
+ if (strcasecmp(provider, "ad") == 0) {
+ opt = ldb_msg_find_attr_as_string(res->msgs[0], "ad_hostname", NULL);
+ } else if (strcasecmp(provider, "ipa") == 0) {
+ opt = ldb_msg_find_attr_as_string(res->msgs[0], "ipa_hostname", NULL);
+ }
+
+ if (opt != NULL) {
+ return talloc_strdup(mem_ctx, opt);
+ }
+
+ ret = gethostname(sys, sizeof(sys));
+ if (ret != 0) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get hostname [%d]: %s\n", ret,
+ sss_strerror(ret));
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, sys);
+}
+
+static errno_t confdb_init_domain(struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ errno_t ret;
+ const char *tmp;
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], "cn", NULL);
+ if (!tmp) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid configuration entry, fatal error!\n");
+ ret = EINVAL;
+ goto done;
+ }
+ domain->name = talloc_strdup(domain, tmp);
+ if (!domain->name) {
+ ret = ENOMEM;
+ goto done;
+ }
+ domain->conn_name = domain->name;
+
+ 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(SSSDBG_FATAL_FAILURE,
+ "Domain [%s] does not specify an ID provider, disabling!\n",
+ domain->name);
+ ret = EINVAL;
+ goto done;
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_DOMAIN_AUTO_UPG, NULL);
+ if (tmp == NULL || *tmp == '\0') {
+ tmp = "false";
+ }
+
+ domain->mpg_mode = str_to_domain_mpg_mode(tmp);
+
+ domain->timeout = ldb_msg_find_attr_as_int(res->msgs[0],
+ CONFDB_DOMAIN_TIMEOUT, 0);
+
+ ret = get_entry_as_bool(res->msgs[0], &domain->ignore_group_members,
+ CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS, 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for %s\n",
+ CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS);
+ goto done;
+ }
+
+ ret = get_entry_as_uint32(res->msgs[0], &domain->id_min,
+ CONFDB_DOMAIN_MINID,
+ confdb_get_min_id(domain));
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "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(SSSDBG_FATAL_FAILURE, "Invalid value for maxId\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (domain->id_max && (domain->id_max < domain->id_min)) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "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(SSSDBG_FATAL_FAILURE,
+ "Invalid value for %s\n", CONFDB_DOMAIN_CACHE_CREDS);
+ goto done;
+ }
+
+ ret = get_entry_as_uint32(res->msgs[0],
+ &domain->cache_credentials_min_ff_length,
+ CONFDB_DOMAIN_CACHE_CREDS_MIN_FF_LENGTH,
+ CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for %s\n",
+ CONFDB_DOMAIN_CACHE_CREDS_MIN_FF_LENGTH);
+ goto done;
+ }
+
+ ret = get_entry_as_uint32(res->msgs[0], &domain->override_gid,
+ CONFDB_DOMAIN_OVERRIDE_GID, 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n", CONFDB_DOMAIN_OVERRIDE_GID);
+ goto done;
+ }
+
+ domain->hostname = confdb_get_domain_hostname(domain, res, domain->provider);
+ if (domain->hostname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain hostname\n");
+ goto done;
+ }
+
+ domain->krb5_keytab = NULL;
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], "krb5_keytab", NULL);
+ if (tmp != NULL) {
+ domain->krb5_keytab = talloc_strdup(domain, tmp);
+ if (domain->krb5_keytab == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain keytab!\n");
+ goto done;
+ }
+ }
+
+ domain->has_views = false;
+ domain->view_name = NULL;
+
+ domain->state = DOM_ACTIVE;
+
+#ifdef BUILD_FILES_PROVIDER
+ domain->fallback_to_nss = false;
+ if (is_files_provider(domain)) {
+ ret = get_entry_as_bool(res->msgs[0], &domain->fallback_to_nss,
+ CONFDB_DOMAIN_FALLBACK_TO_NSS, true);
+ if(ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for %s\n", CONFDB_DOMAIN_FALLBACK_TO_NSS);
+ goto done;
+ }
+ }
+#endif
+
+ domain->not_found_counter = 0;
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_provider_and_enum(struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ int val;
+ errno_t ret;
+ const char *tmp, *tmp_pam_target, *tmp_auth;
+
+ /* TEMP: test if the old bitfield conf value is used and warn it has been
+ * superseded. */
+ 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(SSSDBG_FATAL_FAILURE,
+ "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, 0);
+ if(ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for %s\n", CONFDB_DOMAIN_ENUMERATE);
+ goto done;
+ }
+ }
+
+ if (is_files_provider(domain)) {
+ /* The password field must be reported as 'x', else pam_unix won't
+ * authenticate this entry. See man pwconv(8) for more details.
+ */
+ domain->pwfield = "x";
+ }
+
+ if (domain->provider != NULL && strcasecmp(domain->provider, "proxy") == 0) {
+ /* The password field must be reported as 'x' for proxy provider
+ * using files library, else pam_unix won't authenticate this entry.
+ * We set this only for sssd-shadowutils target which can be used
+ * to authenticate with pam_unix only. Otherwise we let administrator
+ * to overwrite default * value with pwfield option to avoid regression
+ * on more common use case where remote authentication is required. */
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_PROXY_LIBNAME,
+ NULL);
+
+ tmp_auth = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_AUTH_PROVIDER,
+ NULL);
+
+ tmp_pam_target = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_PROXY_PAM_TARGET,
+ NULL);
+
+ if (tmp != NULL && tmp_pam_target != NULL
+ && strcasecmp(tmp, "files") == 0
+ && (tmp_auth == NULL || strcasecmp(tmp_auth, "proxy") == 0)
+ && strcmp(tmp_pam_target, "sssd-shadowutils") == 0) {
+ domain->pwfield = "x";
+ }
+ }
+
+ if (!domain->enumerate) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No enumeration for [%s]!\n", domain->name);
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Please note that when enumeration is disabled `getent "
+ "passwd` does not return all users by design. See "
+ "sssd.conf man page for more detailed information\n");
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_fqn(struct confdb_ctx *cdb,
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ errno_t ret;
+ char *default_domain;
+ bool fqnames_default = false;
+
+ ret = confdb_get_string(cdb, mem_ctx, CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_DEFAULT_DOMAIN, NULL,
+ &default_domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot get the default domain [%d]: %s\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ /* Determine if user/group names will be Fully Qualified
+ * in NSS interfaces */
+ if (default_domain != NULL
+ && is_files_provider(domain) == false
+ ) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Default domain suffix set. Changing default for "
+ "use_fully_qualified_names to True.\n");
+ fqnames_default = true;
+ }
+
+ ret = get_entry_as_bool(res->msgs[0], &domain->fqnames,
+ CONFDB_DOMAIN_FQ, fqnames_default);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Invalid value for %s\n",
+ CONFDB_DOMAIN_FQ);
+ goto done;
+ }
+
+ if (default_domain != NULL
+ && domain->fqnames == false
+ && is_files_provider(domain) == false
+ ) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid configuration detected (default_domain_suffix is used "
+ "while use_fully_qualified_names was set to false).\n");
+ ret = ERR_INVALID_CONFIG;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_timeouts(struct confdb_ctx *cdb,
+ struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ errno_t ret;
+ uint32_t entry_cache_timeout;
+ int memcache_timeout;
+
+ ret = confdb_get_int(cdb,
+ CONFDB_NSS_CONF_ENTRY,
+ CONFDB_MEMCACHE_TIMEOUT,
+ 300, &memcache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Unable to get memory cache entry timeout [%s].\n",
+ CONFDB_MEMCACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Get the global entry cache timeout setting */
+ ret = get_entry_as_uint32(res->msgs[0], &entry_cache_timeout,
+ CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT, 5400);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Override the user cache timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->user_timeout,
+ CONFDB_DOMAIN_USER_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_USER_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ if (domain->user_timeout < memcache_timeout) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "%s is less than %s. User records will not be updated before "
+ "memory cache entry expires.\n",
+ CONFDB_DOMAIN_USER_CACHE_TIMEOUT, CONFDB_MEMCACHE_TIMEOUT);
+ }
+
+ /* Override the group cache timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->group_timeout,
+ CONFDB_DOMAIN_GROUP_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_GROUP_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ if (domain->group_timeout < memcache_timeout) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "%s is less than %s. Group records will not be updated before "
+ "memory cache entry expires.\n",
+ CONFDB_DOMAIN_GROUP_CACHE_TIMEOUT, CONFDB_MEMCACHE_TIMEOUT);
+ }
+
+ /* Override the netgroup cache timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->netgroup_timeout,
+ CONFDB_DOMAIN_NETGROUP_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_NETGROUP_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Override the service cache timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->service_timeout,
+ CONFDB_DOMAIN_SERVICE_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_SERVICE_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Override the autofs cache timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->autofsmap_timeout,
+ CONFDB_DOMAIN_AUTOFS_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_AUTOFS_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Override the sudo cache timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->sudo_timeout,
+ CONFDB_DOMAIN_SUDO_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_SUDO_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Override the ssh known hosts timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->ssh_host_timeout,
+ CONFDB_DOMAIN_SSH_HOST_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_SSH_HOST_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Override the computer timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->computer_timeout,
+ CONFDB_DOMAIN_COMPUTER_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_COMPUTER_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Override the resolver timeout, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->resolver_timeout,
+ CONFDB_DOMAIN_RESOLVER_CACHE_TIMEOUT,
+ entry_cache_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_RESOLVER_CACHE_TIMEOUT);
+ goto done;
+ }
+
+ /* Set refresh_expired_interval, if specified */
+ ret = get_entry_as_uint32(res->msgs[0], &domain->refresh_expired_interval,
+ CONFDB_DOMAIN_REFRESH_EXPIRED_INTERVAL,
+ 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_REFRESH_EXPIRED_INTERVAL);
+ goto done;
+ }
+
+ /* Set refresh_expired_interval_offset, if specified */
+ ret = get_entry_as_uint32(res->msgs[0],
+ &domain->refresh_expired_interval_offset,
+ CONFDB_DOMAIN_REFRESH_EXPIRED_INTERVAL_OFFSET,
+ 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n",
+ CONFDB_DOMAIN_REFRESH_EXPIRED_INTERVAL_OFFSET);
+ goto done;
+ }
+
+ /* detect and fix misconfiguration */
+ if (domain->refresh_expired_interval + domain->refresh_expired_interval_offset > entry_cache_timeout) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "refresh_expired_interval (%d) + "
+ "refresh_expired_interval_offset (%d) cannot be greater than "
+ "entry_cache_timeout (%u)\n",
+ domain->refresh_expired_interval,
+ domain->refresh_expired_interval_offset, entry_cache_timeout);
+
+ domain->refresh_expired_interval = 0.70 * entry_cache_timeout;
+ domain->refresh_expired_interval_offset =
+ 0.10 * domain->refresh_expired_interval;
+
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "refresh_expired_interval is being set to recommended value "
+ "entry_cache_timeout * 0.70 (%u).\n",
+ domain->refresh_expired_interval);
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "refresh_expired_interval_offset is being set to recommended value "
+ "refresh_expired_interval * 0.10 (%u).\n",
+ domain->refresh_expired_interval_offset);
+ }
+
+ ret = init_cached_auth_timeout(cdb, res->msgs[0],
+ &domain->cached_auth_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "init_cached_auth_timeout failed: %s:[%d].\n",
+ sss_strerror(ret), ret);
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_user_info(struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ errno_t ret;
+ const char *tmp;
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_NSS_OVERRIDE_HOMEDIR, NULL);
+ /* Here we skip the files provider as it should always return *only*
+ * what's in the files and nothing else. */
+ if (tmp != NULL
+ && !is_files_provider(domain)
+ ) {
+ domain->override_homedir = talloc_strdup(domain, tmp);
+ if (!domain->override_homedir) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_NSS_FALLBACK_HOMEDIR, NULL);
+ if (tmp != NULL) {
+ domain->fallback_homedir = talloc_strdup(domain, tmp);
+ if (!domain->fallback_homedir) {
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ if (strcasecmp(domain->provider, "ad") == 0) {
+ /* ad provider default */
+ domain->fallback_homedir = talloc_strdup(domain, "/home/%d/%u");
+ if (!domain->fallback_homedir) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_SUBDOMAIN_HOMEDIR,
+ CONFDB_DOMAIN_DEFAULT_SUBDOMAIN_HOMEDIR);
+ if (tmp != NULL) {
+ domain->subdomain_homedir = talloc_strdup(domain, tmp);
+ if (!domain->subdomain_homedir) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_NSS_HOMEDIR_SUBSTRING, NULL);
+ if (tmp != NULL) {
+ domain->homedir_substr = talloc_strdup(domain, tmp);
+ if (domain->homedir_substr == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_NSS_OVERRIDE_SHELL, NULL);
+ /* Here we skip the files provider as it should always return *only*
+ * what's in the files and nothing else. */
+ if (tmp != NULL
+ && !is_files_provider(domain)
+ ) {
+ domain->override_shell = talloc_strdup(domain, tmp);
+ if (!domain->override_shell) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_NSS_DEFAULT_SHELL, NULL);
+ if (tmp != NULL) {
+ domain->default_shell = talloc_strdup(domain, tmp);
+ if (!domain->default_shell) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_NSS_PWFIELD, NULL);
+ if (tmp != NULL) {
+ domain->pwfield = talloc_strdup(domain, tmp);
+ if (!domain->pwfield) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_case(struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ errno_t ret;
+ const char *tmp;
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_CASE_SENSITIVE, NULL);
+ if (tmp != NULL) {
+ if (strcasecmp(tmp, "true") == 0) {
+ domain->case_sensitive = true;
+ domain->case_preserve = true;
+ } else if (strcasecmp(tmp, "false") == 0) {
+ domain->case_sensitive = false;
+ domain->case_preserve = false;
+ } else if (strcasecmp(tmp, "preserving") == 0) {
+ domain->case_sensitive = false;
+ domain->case_preserve = true;
+ } else {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for %s\n", CONFDB_DOMAIN_CASE_SENSITIVE);
+ ret = EINVAL;
+ goto done;
+ }
+ } else {
+ /* default */
+ if (strcasecmp(domain->provider, "ad") == 0) {
+ domain->case_sensitive = false;
+ domain->case_preserve = false;
+ } else {
+ domain->case_sensitive = true;
+ domain->case_preserve = true;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_subdomains(struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ errno_t ret;
+ const char *tmp;
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_SUBDOMAIN_ENUMERATE,
+ CONFDB_DEFAULT_SUBDOMAIN_ENUMERATE);
+ if (tmp != NULL) {
+ ret = split_on_separator(domain, tmp, ',', true, true,
+ &domain->sd_enumerate, NULL);
+ if (ret != 0) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Cannot parse %s\n", CONFDB_SUBDOMAIN_ENUMERATE);
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_SUBDOMAIN_INHERIT,
+ NULL);
+ if (tmp != NULL) {
+ ret = split_on_separator(domain, tmp, ',', true, true,
+ &domain->sd_inherit, NULL);
+ if (ret != 0) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Cannot parse %s\n", CONFDB_SUBDOMAIN_ENUMERATE);
+ goto done;
+ }
+ }
+
+ domain->type = DOM_TYPE_POSIX;
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_TYPE,
+ CONFDB_DOMAIN_TYPE_POSIX);
+ if (tmp != NULL) {
+ if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_POSIX) == 0) {
+ domain->type = DOM_TYPE_POSIX;
+ } else if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_APP) == 0) {
+ domain->type = DOM_TYPE_APPLICATION;
+ } else {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value %s for [%s]\n", tmp, CONFDB_DOMAIN_TYPE);
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ ret = get_entry_as_uint32(res->msgs[0], &domain->subdomain_refresh_interval,
+ CONFDB_DOMAIN_SUBDOMAIN_REFRESH,
+ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n", CONFDB_DOMAIN_SUBDOMAIN_REFRESH);
+ goto done;
+ } else if (domain->subdomain_refresh_interval == 0) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Invalid value for [%s]. Setting up the default value: %d\n",
+ CONFDB_DOMAIN_SUBDOMAIN_REFRESH,
+ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE);
+
+ domain->subdomain_refresh_interval =
+ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE;
+ }
+
+ ret = get_entry_as_uint32(res->msgs[0],
+ &domain->subdomain_refresh_interval_offset,
+ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_OFFSET,
+ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_OFFSET_DEFAULT_VALUE);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value for [%s]\n", CONFDB_DOMAIN_SUBDOMAIN_REFRESH_OFFSET);
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_gssapi(struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ errno_t ret;
+ const char *tmp;
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_PAM_GSSAPI_SERVICES,
+ NULL);
+ if (tmp != NULL) {
+ ret = split_on_separator(domain, tmp, ',', true, true,
+ &domain->gssapi_services, NULL);
+ if (ret != 0) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Cannot parse %s\n", CONFDB_PAM_GSSAPI_SERVICES);
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_PAM_GSSAPI_CHECK_UPN,
+ NULL);
+ if (tmp != NULL) {
+ domain->gssapi_check_upn = talloc_strdup(domain, tmp);
+ if (domain->gssapi_check_upn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_PAM_GSSAPI_INDICATORS_MAP,
+ NULL);
+ if (tmp != NULL && tmp[0] != '\0') {
+ ret = split_on_separator(domain, tmp, ',', true, true,
+ &domain->gssapi_indicators_map, NULL);
+ if (ret != 0) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Cannot parse %s\n", CONFDB_PAM_GSSAPI_INDICATORS_MAP);
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t confdb_init_domain_pwd_expire(struct confdb_ctx *cdb,
+ struct sss_domain_info *domain,
+ struct ldb_result *res)
+{
+ int val;
+ errno_t ret;
+
+ /* Set the PAM warning time, if specified. If not specified, pass on
+ * the "not set" value of "-1" which means "use provider default". The
+ * value 0 means "always display the warning if server sends one" */
+ domain->pwd_expiration_warning = -1;
+
+ val = ldb_msg_find_attr_as_int(res->msgs[0],
+ CONFDB_DOMAIN_PWD_EXPIRATION_WARNING,
+ -1);
+ if (val == -1) {
+ ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
+ CONFDB_PAM_PWD_EXPIRATION_WARNING,
+ -1, &val);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read PAM expiration warning, not fatal.\n");
+ val = -1;
+ }
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, "pwd_expiration_warning is %d\n", val);
+ if (val >= 0) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Setting domain password expiration warning to %d days\n", val);
+ /* The value is in days, transform it to seconds */
+ domain->pwd_expiration_warning = val * 24 * 3600;
+ }
+
+ 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;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) return ENOMEM;
+
+ ret = confdb_get_domain_section(tmp_ctx, cdb, CONFDB_DOMAIN_BASEDN,
+ name, &res);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unknown domain [%s]\n", name);
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Error %d: %s while retrieving %s\n",
+ ret, sss_strerror(ret), name);
+ goto done;
+ }
+
+ domain = talloc_zero(mem_ctx, struct sss_domain_info);
+ if (!domain) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = confdb_init_domain(domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Determine if this domain can be enumerated */
+ ret = confdb_init_domain_provider_and_enum(domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = confdb_init_domain_fqn(cdb, mem_ctx, domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get all the timeouts */
+ ret = confdb_init_domain_timeouts(cdb, domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get password expiration information */
+ ret = confdb_init_domain_pwd_expire(cdb, domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get the behavior about the homedir */
+ ret = confdb_init_domain_user_info(domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get the case sensitivity */
+ ret = confdb_init_domain_case(domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get the subdomains information */
+ ret = confdb_init_domain_subdomains(domain, res);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get the GSSAPI information */
+ ret = confdb_init_domain_gssapi(domain, res);
+ if (ret != EOK) {
+ 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 = 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_enabled_domain_list(cdb, tmp_ctx, &domlist);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No domains configured, fatal error!\n");
+ ret = ERR_NO_DOMAIN_ENABLED;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error retrieving domains list!\n");
+ goto done;
+ }
+
+ for (i = 0; domlist[i]; i++) {
+ /* check if domain name is really unique */
+ DLIST_FOR_EACH(domain, cdb->doms) {
+ if (strcasecmp(domain->name, domlist[i]) == 0) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ SAME_DOMAINS_ERROR_MSG, domlist[i], domain->name);
+ sss_log(SSS_LOG_CRIT,
+ SAME_DOMAINS_ERROR_MSG, domlist[i], domain->name);
+
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ domain = NULL;
+ ret = confdb_get_domain_internal(cdb, cdb, domlist[i], &domain);
+ if (ret) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ RETRIEVE_DOMAIN_ERROR_MSG,
+ ret, sss_strerror(ret), domlist[i]);
+ sss_log(SSS_LOG_CRIT,
+ RETRIEVE_DOMAIN_ERROR_MSG,
+ ret, sss_strerror(ret), domlist[i]);
+
+ continue;
+ }
+
+ DLIST_ADD_END(cdb->doms, domain, struct sss_domain_info *);
+ }
+
+ if (cdb->doms == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "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 = get_next_domain(dom, 0)) {
+ if (strcasecmp(dom->name, name) == 0) {
+ *_domain = dom;
+ return EOK;
+ }
+ }
+
+ return ENOENT;
+}
+
+int confdb_list_all_domain_names(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ char ***_names)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_dn *dn = NULL;
+ struct ldb_result *res = NULL;
+ static const char *attrs[] = {CONFDB_DOMAIN_ATTR, NULL};
+ const char *name = NULL;
+ char **names = NULL;
+ int i;
+ int ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, cdb->ldb, CONFDB_DOMAIN_BASEDN);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL,
+ attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ names = talloc_zero_array(tmp_ctx, char*, res->count + 1);
+ if (names == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < res->count; i++) {
+ name = ldb_msg_find_attr_as_string(res->msgs[i], CONFDB_DOMAIN_ATTR,
+ NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "The object [%s] doesn't have a name\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ ret = EINVAL;
+ goto done;
+ }
+
+ names[i] = talloc_strdup(names, name);
+ if (names[i] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ *_names = talloc_steal(mem_ctx, names);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_get_sub_sections(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ const char *section,
+ char ***sections,
+ int *num_sections)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *secdn;
+ struct ldb_dn *base = NULL;
+ struct ldb_result *res = NULL;
+ static const char *attrs[] = {"cn", NULL};
+ char **names;
+ int base_comp_num;
+ int num;
+ int i;
+ int ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = parse_section(tmp_ctx, section, &secdn, NULL);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ base = ldb_dn_new(tmp_ctx, cdb->ldb, secdn);
+ if (base == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ base_comp_num = ldb_dn_get_comp_num(base);
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, base, LDB_SCOPE_SUBTREE,
+ attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ names = talloc_zero_array(tmp_ctx, char *, res->count + 1);
+ if (names == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (num = 0, i = 0; i < res->count; i++) {
+ const struct ldb_val *val;
+ char *name;
+ int n;
+ int j;
+
+ n = ldb_dn_get_comp_num(res->msgs[i]->dn);
+ if (n == base_comp_num) continue;
+
+ name = NULL;
+ for (j = n - base_comp_num - 1; j >= 0; j--) {
+ val = ldb_dn_get_component_val(res->msgs[i]->dn, j);
+ if (name == NULL) {
+ name = talloc_strndup(names,
+ (const char *)val->data, val->length);
+ } else {
+ name = talloc_asprintf(names, "%s/%.*s", name,
+ (int)val->length,
+ (const char *)val->data);
+ }
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ names[num] = name;
+ if (names[num] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ num++;
+ }
+
+ *sections = talloc_steal(mem_ctx, names);
+ *num_sections = num;
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+#ifdef BUILD_FILES_PROVIDER
+static bool need_implicit_files_domain(TALLOC_CTX *tmp_ctx,
+ struct confdb_ctx *cdb,
+ struct ldb_result *doms)
+{
+ const char *id_provider = NULL;
+ unsigned int i;
+ errno_t ret;
+ char **domlist;
+ const char *val;
+
+ ret = confdb_get_string_as_list(cdb, tmp_ctx,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_ACTIVE_DOMAINS,
+ &domlist);
+ if (ret == ENOENT) {
+ return true;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot get active domains %d[%s]\n",
+ ret, sss_strerror(ret));
+ return false;
+ }
+
+ for (i = 0; i < doms->count; i++) {
+ val = ldb_msg_find_attr_as_string(doms->msgs[i], CONFDB_DOMAIN_ATTR,
+ NULL);
+ if (val == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "The object [%s] doesn't have a name\n",
+ ldb_dn_get_linearized(doms->msgs[i]->dn));
+ continue;
+ }
+
+ /* skip disabled domain */
+ if (!string_in_list(val, domlist, false)) {
+ continue;
+ }
+
+ id_provider = ldb_msg_find_attr_as_string(doms->msgs[i],
+ CONFDB_DOMAIN_ID_PROVIDER,
+ NULL);
+ if (id_provider == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "The object [%s] doesn't have an id_provider\n",
+ ldb_dn_get_linearized(doms->msgs[i]->dn));
+ continue;
+ }
+
+ if (strcasecmp(id_provider, "files") == 0) {
+ return false;
+ }
+
+ if (strcasecmp(id_provider, "proxy") == 0) {
+ val = ldb_msg_find_attr_as_string(doms->msgs[i],
+ CONFDB_PROXY_LIBNAME, NULL);
+ if (val == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "The object [%s] doesn't have proxy_lib_name with "
+ "id_provider proxy\n",
+ ldb_dn_get_linearized(doms->msgs[i]->dn));
+ continue;
+ }
+
+ /* id_provider = proxy + proxy_lib_name = files are equivalent
+ * to id_provider = files
+ */
+ if (strcmp(val, "files") == 0) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int confdb_has_files_domain(struct confdb_ctx *cdb)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_dn *dn = NULL;
+ struct ldb_result *res = NULL;
+ static const char *attrs[] = { CONFDB_DOMAIN_ID_PROVIDER,
+ CONFDB_DOMAIN_ATTR,
+ CONFDB_PROXY_LIBNAME, NULL };
+ int ret;
+ bool need_files_dom;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, cdb->ldb, CONFDB_DOMAIN_BASEDN);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL,
+ attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ need_files_dom = need_implicit_files_domain(tmp_ctx, cdb, res);
+
+ ret = need_files_dom ? ENOENT : EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static int create_files_domain(struct confdb_ctx *cdb,
+ const char *name)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ errno_t ret;
+ char *cdb_path = NULL;
+ const char *val[2] = { NULL, NULL };
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ cdb_path = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, name);
+ if (cdb_path == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ val[0] = "files";
+ ret = confdb_add_param(cdb, true, cdb_path, "id_provider", val);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add id_provider [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static int activate_files_domain(struct confdb_ctx *cdb,
+ const char *name)
+{
+ errno_t ret;
+ TALLOC_CTX *tmp_ctx;
+ char *monitor_domlist;
+ const char *domlist[2] = { NULL, NULL };
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = confdb_get_string(cdb, tmp_ctx,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_ACTIVE_DOMAINS,
+ NULL,
+ &monitor_domlist);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error retrieving domains list!\n");
+ goto done;
+ }
+
+ if (monitor_domlist != NULL) {
+ domlist[0] = talloc_asprintf(tmp_ctx, "%s,%s", name, monitor_domlist);
+ if (domlist[0] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ domlist[0] = name;
+ }
+
+ ret = confdb_add_param(cdb, true,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_ACTIVE_DOMAINS,
+ domlist);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot extend the domain list [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static int confdb_ensure_files_domain(struct confdb_ctx *cdb,
+ const char *implicit_files_dom_name)
+{
+ errno_t ret;
+ bool enable_files;
+
+ ret = confdb_get_bool(cdb,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_ENABLE_FILES_DOM,
+ false, &enable_files);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot get the value of %s\n",
+ CONFDB_MONITOR_ENABLE_FILES_DOM);
+ return ret;
+ }
+
+ if (enable_files == false) {
+ DEBUG(SSSDBG_CONF_SETTINGS, "The implicit files domain is disabled\n");
+ return EOK;
+ }
+
+ ret = confdb_has_files_domain(cdb);
+ if (ret == EOK) {
+ DEBUG(SSSDBG_CONF_SETTINGS, "The files domain is already enabled\n");
+ return EOK;
+ } else if (ret != ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up the files domain\n");
+ return ret;
+ }
+
+ /* ENOENT, so let's add a files domain */
+ ret = create_files_domain(cdb, implicit_files_dom_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add an implicit files domain\n");
+ return ret;
+ }
+
+ return activate_files_domain(cdb, implicit_files_dom_name);
+}
+#endif
+
+static int confdb_get_parent_domain(TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct confdb_ctx *cdb,
+ struct ldb_result *app_dom,
+ struct ldb_result **_parent_dom)
+{
+ const char *inherit_from;
+
+ inherit_from = ldb_msg_find_attr_as_string(app_dom->msgs[0],
+ CONFDB_DOMAIN_INHERIT_FROM, NULL);
+ if (inherit_from == NULL) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "%s does not inherit from any POSIX domain\n", name);
+ *_parent_dom = NULL;
+ return EOK;
+ }
+
+ return confdb_get_domain_section(mem_ctx, cdb,
+ CONFDB_DOMAIN_BASEDN, inherit_from,
+ _parent_dom);
+}
+
+static int confdb_add_app_domain(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ const char *name)
+{
+ char *cdb_path = NULL;
+ const char *val[2] = { NULL, NULL };
+ int ret;
+
+ cdb_path = talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL, name);
+ if (cdb_path == NULL) {
+ return ENOMEM;
+ }
+
+ val[0] = CONFDB_DOMAIN_TYPE_APP;
+ ret = confdb_add_param(cdb, true, cdb_path, CONFDB_DOMAIN_TYPE, val);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add id_provider [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ return EOK;
+}
+
+static int confdb_merge_parent_domain(const char *name,
+ struct confdb_ctx *cdb,
+ struct ldb_result *app_section)
+{
+ int ret;
+ int ldb_flag;
+ struct ldb_result *parent_domain = NULL;
+ struct ldb_message *replace_msg = NULL;
+ struct ldb_message *app_msg = NULL;
+ struct ldb_dn *domain_dn;
+ struct ldb_message_element *el = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ domain_dn = ldb_dn_new_fmt(tmp_ctx,
+ cdb->ldb,
+ "%s=%s,%s",
+ CONFDB_DOMAIN_ATTR,
+ name,
+ CONFDB_DOMAIN_BASEDN);
+ if (domain_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Copy the parent domain parameters */
+ ret = confdb_get_parent_domain(tmp_ctx, name, cdb,
+ app_section, &parent_domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot retrieve the parent domain [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (parent_domain != NULL) {
+ replace_msg = ldb_msg_copy(tmp_ctx, parent_domain->msgs[0]);
+ if (replace_msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ replace_msg->dn = domain_dn;
+
+ for (unsigned i = 0; i < replace_msg->num_elements; i++) {
+ replace_msg->elements[i].flags = LDB_FLAG_MOD_ADD;
+ }
+
+ el = ldb_msg_find_element(replace_msg, "cn");
+ if (el != NULL) {
+ /* Don't add second cn */
+ ldb_msg_remove_element(replace_msg, el);
+ }
+
+ ret = ldb_modify(cdb->ldb, replace_msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sss_ldb_error_to_errno(ret);
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Inheriting options from parent domain failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ /* Finally, add any app-domain specific overrides */
+ app_msg = ldb_msg_new(tmp_ctx);
+ if (app_msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ app_msg->dn = domain_dn;
+
+ for (unsigned i = 0; i < app_section->msgs[0]->num_elements; i++) {
+ struct ldb_message_element *app_el = &app_section->msgs[0]->elements[i];
+
+ /* These elements will be skipped when replacing attributes in
+ * a domain to avoid EEXIST errors
+ */
+ if (strcasecmp(app_el->name, "cn") == 0) {
+ continue;
+ }
+
+ if (replace_msg != NULL) {
+ el = ldb_msg_find_element(replace_msg,
+ app_section->msgs[0]->elements[i].name);
+ if (el == NULL) {
+ /* Adding an element */
+ ldb_flag = LDB_FLAG_MOD_ADD;
+ } else {
+ /* Overriding an element */
+ ldb_flag = LDB_FLAG_MOD_REPLACE;
+ }
+ } else {
+ /* If there was no domain to inherit from, just add all */
+ ldb_flag = LDB_FLAG_MOD_ADD;
+ }
+
+ ret = ldb_msg_add(app_msg,
+ &app_section->msgs[0]->elements[i],
+ ldb_flag);
+ if (ret != LDB_SUCCESS) {
+ continue;
+ }
+ }
+
+ /* We use permissive modification here because adding cn or
+ * distinguishedName from the app_section to the application
+ * message would throw EEXIST
+ */
+ ret = sss_ldb_modify_permissive(cdb->ldb, app_msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sss_ldb_error_to_errno(ret);
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Adding app-specific options failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, "Added a domain section for %s\n", name);
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_expand_app_domains(struct confdb_ctx *cdb)
+{
+ int ret;
+ char **domlist;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *app_domain = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+#ifdef BUILD_FILES_PROVIDER
+ ret = confdb_ensure_files_domain(cdb, IMPLICIT_FILES_DOMAIN_NAME);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot add the implicit files domain [%d]: %s\n",
+ ret, strerror(ret));
+ /* Not fatal */
+ }
+#endif
+
+ ret = confdb_get_enabled_domain_list(cdb, tmp_ctx, &domlist);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured, fatal error!\n");
+ ret = ERR_NO_DOMAIN_ENABLED;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error retrieving domains list!\n");
+ goto done;
+ }
+
+ for (int i = 0; domlist[i]; i++) {
+ ret = confdb_get_domain_section(tmp_ctx, cdb,
+ CONFDB_APP_DOMAIN_BASEDN, domlist[i],
+ &app_domain);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "%s is not an app domain\n", domlist[i]);
+ continue;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Error %d: %s while retrieving %s\n",
+ ret, sss_strerror(ret), domlist[i]);
+ goto done;
+ }
+
+ ret = confdb_add_app_domain(tmp_ctx, cdb, domlist[i]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot add the app domain section [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = confdb_merge_parent_domain(domlist[i], cdb, app_domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot add options into the app domain section [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t certmap_local_check(struct ldb_message *msg)
+{
+ const char *rule_name;
+ const char *tmp_str;
+ int ret;
+
+ rule_name = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_NAME, NULL);
+ if (rule_name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Certificate mapping rule [%s] has no name.",
+ ldb_dn_get_linearized(msg->dn));
+ return EINVAL;
+ }
+
+ tmp_str = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_DOMAINS, NULL);
+ if (tmp_str != NULL) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Option [%s] is ignored for local certmap rules.\n",
+ CONFDB_CERTMAP_DOMAINS);
+ }
+
+ tmp_str = ldb_msg_find_attr_as_string(msg, CONFDB_CERTMAP_MAPRULE, NULL);
+ if (tmp_str != NULL) {
+ if (tmp_str[0] != '(' || tmp_str[strlen(tmp_str) - 1] != ')') {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Mapping rule must be in braces (...).\n");
+ return EINVAL;
+ }
+ DEBUG(SSSDBG_TRACE_ALL, "Using [%s] mapping rule of [%s].\n",
+ tmp_str, ldb_dn_get_linearized(msg->dn));
+ return EOK;
+ }
+
+ tmp_str = talloc_asprintf(msg, "(%s)", rule_name);
+ if (tmp_str == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ return ENOMEM;
+ }
+ ret = ldb_msg_add_string(msg, CONFDB_CERTMAP_MAPRULE, tmp_str);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(discard_const(tmp_str));
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
+ return EIO;
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL, "Using [%s] as mapping rule for [%s].\n",
+ tmp_str, ldb_dn_get_linearized(msg->dn));
+
+ return EOK;
+}
+
+static errno_t confdb_get_all_certmaps(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ struct sss_domain_info *dom,
+ bool certmaps_for_local_users,
+ struct certmap_info ***_certmap_list)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_dn *dn = NULL;
+ struct ldb_result *res = NULL;
+ /* The attribute order is important, because it is used in
+ * sysdb_ldb_msg_attr_to_certmap_info and must match
+ * enum certmap_info_member. */
+ static const char *attrs[] = { CONFDB_CERTMAP_NAME,
+ CONFDB_CERTMAP_MAPRULE,
+ CONFDB_CERTMAP_MATCHRULE,
+ CONFDB_CERTMAP_PRIORITY,
+ CONFDB_CERTMAP_DOMAINS,
+ NULL};
+ struct certmap_info **certmap_list = NULL;
+ size_t c;
+ int ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", dom->name,
+ CONFDB_CERTMAP_BASEDN);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL,
+ attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ certmap_list = talloc_zero_array(tmp_ctx, struct certmap_info *,
+ res->count + 1);
+ if (certmap_list == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (c = 0; c < res->count; c++) {
+ if (certmaps_for_local_users) {
+ ret = certmap_local_check(res->msgs[c]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Invalid certificate mapping [%s] for local user, "
+ "ignored.\n", ldb_dn_get_linearized(res->msgs[c]->dn));
+ continue;
+ }
+ }
+ ret = sysdb_ldb_msg_attr_to_certmap_info(certmap_list, res->msgs[c],
+ attrs, &certmap_list[c]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_ldb_msg_attr_to_certmap_info failed.\n");
+ goto done;
+ }
+ }
+
+ *_certmap_list = talloc_steal(mem_ctx, certmap_list);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_certmap_to_sysdb(struct confdb_ctx *cdb,
+ struct sss_domain_info *dom,
+ bool certmaps_for_local_users)
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx;
+ struct certmap_info **certmap_list;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+ return ENOMEM;
+ }
+
+ ret = confdb_get_all_certmaps(tmp_ctx, cdb, dom, certmaps_for_local_users,
+ &certmap_list);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "confdb_get_all_certmaps failed.\n");
+ goto done;
+ }
+
+ ret = sysdb_update_certmap(dom->sysdb, certmap_list, false /* TODO */);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_certmap failed.\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+int confdb_get_enabled_domain_list(struct confdb_ctx *cdb,
+ TALLOC_CTX *ctx, char ***_result)
+{
+ int ret;
+ char **domlist = NULL;
+ char **all_domains = NULL;
+ bool enabled = false;
+
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ ret = confdb_get_string_as_list(cdb, tmp_ctx,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_ACTIVE_DOMAINS,
+ &domlist);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to get [%s] from [%s], error [%d] (%s)\n",
+ CONFDB_MONITOR_ACTIVE_DOMAINS, "sssd",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ ret = confdb_list_all_domain_names(tmp_ctx, cdb, &all_domains);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed retrieving all domain name "
+ "list, error [%d], description '%s'\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ for (int idx = 0; all_domains[idx]; idx++) {
+ ret = confdb_get_domain_enabled(cdb, all_domains[idx], &enabled);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed retrieving 'enabled' attribute from '%s' domain; "
+ "error [%d], description '%s'\n",
+ all_domains[idx],
+ ret, strerror(ret));
+ goto done;
+ }
+
+ if (ret == ENOENT) continue;
+
+ if (enabled && !string_in_list(all_domains[idx], domlist, false)) {
+ ret = add_string_to_list(tmp_ctx, all_domains[idx], &domlist);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed adding '%s' domain to domain list; "
+ "error [%d], description '%s'\n",
+ all_domains[idx],
+ ret, strerror(ret));
+ goto done;
+ }
+ }
+
+ if (!enabled && string_in_list(all_domains[idx], domlist, false)) {
+ ret = del_string_from_list(all_domains[idx], &domlist, false);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed deleting '%s' domain from domain list; "
+ "error [%d], description '%s'\n",
+ all_domains[idx],
+ ret, strerror(ret));
+ goto done;
+ }
+ }
+ }
+
+ if (domlist == NULL || domlist[0] == NULL) {
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = EOK;
+ talloc_steal(ctx, domlist);
+ *_result = domlist;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+/**
+ * Retrieve the enabled attribute for a specific domain.
+ * @param cdb The database configuration context.
+ * @param domain The domain name.
+ * @param enabled The output variable; it can not be NULL; if the
+ * domain is explicitely enabled, *enabled is equal to 1; if the
+ * domain is explicitely disabled, *enabled is equal to 0.
+ * @param Return EOK if the operation happened properly and *enabled
+ * contain the value of the attribute; if no entry found for enabled
+ * attribute it returns ENOENT, else an error code.
+ */
+static int confdb_get_domain_enabled(struct confdb_ctx *cdb,
+ const char *domain, bool *_enabled)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *section = NULL;
+ char **values = NULL;
+ int ret = EINVAL;
+
+ section = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, domain);
+ values = NULL;
+ ret = confdb_get_param(cdb, tmp_ctx, section, CONFDB_DOMAIN_ENABLED, &values);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed retrieving '%s' attribute in '%s' section; "
+ "error [%d], description '%s'\n",
+ CONFDB_DOMAIN_ENABLED, section,
+ ret, strerror(ret));
+ goto done;
+ }
+
+ /* Check return and output value */
+ if (ret == ENOENT || !values || !values[0]) {
+ ret = ENOENT;
+ goto done;
+ }
+ if (values[1]) {
+ /* More than one value it's an invalid configuration file */
+ ret = EINVAL;
+ goto done;
+ }
+ if (0 == strcasecmp(values[0], "true")) {
+ ret = EOK;
+ *_enabled = true;
+ goto done;
+ }
+ if (0 == strcasecmp(values[0], "false")) {
+ ret = EOK;
+ *_enabled = false;
+ goto done;
+ }
+ /* Failed to parse value */
+ ret = EINVAL;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
new file mode 100644
index 0000000..4487d78
--- /dev/null
+++ b/src/confdb/confdb.h
@@ -0,0 +1,785 @@
+/*
+ SSSD
+
+ SSSD Configuration 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_DEFAULT_CFG_FILE_VER 2
+#define CONFDB_FILE "config.ldb"
+#define SSSD_CONFIG_FILE_NAME "sssd.conf"
+#define SSSD_CONFIG_FILE SSSD_CONF_DIR"/"SSSD_CONFIG_FILE_NAME
+#define CONFDB_DEFAULT_CONFIG_DIR_NAME "conf.d"
+#define CONFDB_DEFAULT_CONFIG_DIR SSSD_CONF_DIR"/"CONFDB_DEFAULT_CONFIG_DIR_NAME
+#define SSSD_MIN_ID 1
+#define CONFDB_DEFAULT_SHELL_FALLBACK "/bin/sh"
+#define CONFDB_FALLBACK_CONFIG \
+ "[sssd]\n" \
+ "services = nss\n"
+
+
+/* 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_LEVEL_ALIAS "debug"
+#define CONFDB_SERVICE_DEBUG_TIMESTAMPS "debug_timestamps"
+#define CONFDB_SERVICE_DEBUG_MICROSECONDS "debug_microseconds"
+#define CONFDB_SERVICE_DEBUG_BACKTRACE_ENABLED "debug_backtrace_enabled"
+#define CONFDB_SERVICE_RECON_RETRIES "reconnection_retries"
+#define CONFDB_SERVICE_FD_LIMIT "fd_limit"
+#define CONFDB_SERVICE_ALLOWED_UIDS "allowed_uids"
+
+/* Monitor */
+#define CONFDB_MONITOR_CONF_ENTRY "config/sssd"
+#define CONFDB_MONITOR_ACTIVE_SERVICES "services"
+#define CONFDB_MONITOR_ACTIVE_DOMAINS "domains"
+#define CONFDB_MONITOR_RESOLV_CONF "monitor_resolv_conf"
+#define CONFDB_MONITOR_TRY_INOTIFY "try_inotify"
+#define CONFDB_MONITOR_KRB5_RCACHEDIR "krb5_rcache_dir"
+#define CONFDB_MONITOR_DEFAULT_DOMAIN "default_domain_suffix"
+#define CONFDB_MONITOR_OVERRIDE_SPACE "override_space"
+#ifdef SSSD_NON_ROOT_USER
+#define CONFDB_MONITOR_USER_RUNAS "user"
+#endif
+#define CONFDB_MONITOR_CERT_VERIFICATION "certificate_verification"
+#define CONFDB_MONITOR_DISABLE_NETLINK "disable_netlink"
+#define CONFDB_MONITOR_ENABLE_FILES_DOM "enable_files_domain"
+#define CONFDB_MONITOR_DOMAIN_RESOLUTION_ORDER "domain_resolution_order"
+#define CONFDB_MONITOR_IMPLICIT_PAC_RESPONDER "implicit_pac_responder"
+#define CONFDB_MONITOR_DUMPABLE "core_dumpable"
+#define CONFDB_MONITOR_PASSKEY_VERIFICATION "passkey_verification"
+
+/* Both monitor and domains */
+#define CONFDB_NAME_REGEX "re_expression"
+#define CONFDB_FULL_NAME_FORMAT "full_name_format"
+#define CONFDB_DEFAULT_FULL_NAME_FORMAT_INTERNAL "%1$s@%2$s%3$s"
+#define CONFDB_DEFAULT_FULL_NAME_FORMAT "%1$s@%2$s"
+
+/* Responders */
+#define CONFDB_RESPONDER_GET_DOMAINS_TIMEOUT "get_domains_timeout"
+#define CONFDB_RESPONDER_CLI_IDLE_TIMEOUT "client_idle_timeout"
+#define CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT 60
+#define CONFDB_RESPONDER_LOCAL_NEG_TIMEOUT "local_negative_timeout"
+#define CONFDB_RESPONDER_LOCAL_NEG_TIMEOUT_DEFAULT 14400
+#define CONFDB_RESPONDER_IDLE_TIMEOUT "responder_idle_timeout"
+#define CONFDB_RESPONDER_IDLE_DEFAULT_TIMEOUT 300
+#define CONFDB_RESPONDER_CACHE_FIRST "cache_first"
+#ifdef BUILD_FILES_PROVIDER
+/* There is a subtile issue with this option when 'files' + another domain is enabled */
+#define CONFDB_RESPONDER_CACHE_FIRST_DEFAILT false
+#else
+#define CONFDB_RESPONDER_CACHE_FIRST_DEFAILT true
+#endif
+
+/* 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"
+#define CONFDB_NSS_OVERRIDE_HOMEDIR "override_homedir"
+#define CONFDB_NSS_FALLBACK_HOMEDIR "fallback_homedir"
+#define CONFDB_NSS_OVERRIDE_SHELL "override_shell"
+#define CONFDB_NSS_VETOED_SHELL "vetoed_shells"
+#define CONFDB_NSS_ALLOWED_SHELL "allowed_shells"
+#define CONFDB_NSS_SHELL_FALLBACK "shell_fallback"
+#define CONFDB_NSS_DEFAULT_SHELL "default_shell"
+#define CONFDB_MEMCACHE_TIMEOUT "memcache_timeout"
+#define CONFDB_NSS_MEMCACHE_SIZE_PASSWD "memcache_size_passwd"
+#define CONFDB_NSS_MEMCACHE_SIZE_GROUP "memcache_size_group"
+#define CONFDB_NSS_MEMCACHE_SIZE_INITGROUPS "memcache_size_initgroups"
+#define CONFDB_NSS_MEMCACHE_SIZE_SID "memcache_size_sid"
+#define CONFDB_NSS_HOMEDIR_SUBSTRING "homedir_substring"
+#define CONFDB_DEFAULT_HOMEDIR_SUBSTRING "/home"
+
+/* 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
+#define CONFDB_PAM_VERBOSITY "pam_verbosity"
+#define CONFDB_PAM_RESPONSE_FILTER "pam_response_filter"
+#define CONFDB_PAM_ID_TIMEOUT "pam_id_timeout"
+#define CONFDB_PAM_PWD_EXPIRATION_WARNING "pam_pwd_expiration_warning"
+#define CONFDB_PAM_TRUSTED_USERS "pam_trusted_users"
+#define CONFDB_PAM_PUBLIC_DOMAINS "pam_public_domains"
+#define CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE "pam_account_expired_message"
+#define CONFDB_PAM_ACCOUNT_LOCKED_MESSAGE "pam_account_locked_message"
+#define CONFDB_PAM_CERT_AUTH "pam_cert_auth"
+#define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path"
+#define CONFDB_PAM_CERT_VERIFICATION "pam_cert_verification"
+#define CONFDB_PAM_P11_CHILD_TIMEOUT "p11_child_timeout"
+#define CONFDB_PAM_WAIT_FOR_CARD_TIMEOUT "p11_wait_for_card_timeout"
+#define CONFDB_PAM_APP_SERVICES "pam_app_services"
+#define CONFDB_PAM_P11_ALLOWED_SERVICES "pam_p11_allowed_services"
+#define CONFDB_PAM_P11_URI "p11_uri"
+#define CONFDB_PAM_INITGROUPS_SCHEME "pam_initgroups_scheme"
+#define CONFDB_PAM_GSSAPI_SERVICES "pam_gssapi_services"
+#define CONFDB_PAM_GSSAPI_CHECK_UPN "pam_gssapi_check_upn"
+#define CONFDB_PAM_GSSAPI_INDICATORS_MAP "pam_gssapi_indicators_map"
+#define CONFDB_PAM_PASSKEY_AUTH "pam_passkey_auth"
+#define CONFDB_PAM_PASSKEY_CHILD_TIMEOUT "passkey_child_timeout"
+#define CONFDB_PAM_PASSKEY_DEBUG_LIBFIDO2 "passkey_debug_libfido2"
+
+/* SUDO */
+#define CONFDB_SUDO_CONF_ENTRY "config/sudo"
+#define CONFDB_SUDO_CACHE_TIMEOUT "sudo_cache_timeout"
+#define CONFDB_DEFAULT_SUDO_CACHE_TIMEOUT 180
+#define CONFDB_SUDO_TIMED "sudo_timed"
+#define CONFDB_DEFAULT_SUDO_TIMED false
+#define CONFDB_SUDO_INVERSE_ORDER "sudo_inverse_order"
+#define CONFDB_DEFAULT_SUDO_INVERSE_ORDER false
+#define CONFDB_SUDO_THRESHOLD "sudo_threshold"
+#define CONFDB_DEFAULT_SUDO_THRESHOLD 50
+
+/* autofs */
+#define CONFDB_AUTOFS_CONF_ENTRY "config/autofs"
+#define CONFDB_AUTOFS_MAP_NEG_TIMEOUT "autofs_negative_timeout"
+
+/* SSH */
+#define CONFDB_SSH_CONF_ENTRY "config/ssh"
+#define CONFDB_SSH_HASH_KNOWN_HOSTS "ssh_hash_known_hosts"
+#define CONFDB_DEFAULT_SSH_HASH_KNOWN_HOSTS false
+#define CONFDB_SSH_KNOWN_HOSTS_TIMEOUT "ssh_known_hosts_timeout"
+#define CONFDB_DEFAULT_SSH_KNOWN_HOSTS_TIMEOUT 180
+#define CONFDB_SSH_CA_DB "ca_db"
+#define CONFDB_DEFAULT_SSH_CA_DB SYSCONFDIR"/sssd/pki/sssd_auth_ca_db.pem"
+#define CONFDB_SSH_USE_CERT_KEYS "ssh_use_certificate_keys"
+#define CONFDB_DEFAULT_SSH_USE_CERT_KEYS true
+#define CONFDB_SSH_USE_CERT_RULES "ssh_use_certificate_matching_rules"
+
+/* PAC */
+#define CONFDB_PAC_CONF_ENTRY "config/pac"
+#define CONFDB_PAC_LIFETIME "pac_lifetime"
+#define CONFDB_PAC_CHECK "pac_check"
+#define CONFDB_PAC_CHECK_DEFAULT "no_check"
+#define CONFDB_PAC_CHECK_IPA_AD_DEFAULT "check_upn, check_upn_allow_missing, check_upn_dns_info_ex"
+
+/* InfoPipe */
+#define CONFDB_IFP_CONF_ENTRY "config/ifp"
+#define CONFDB_IFP_USER_ATTR_LIST "user_attributes"
+#define CONFDB_IFP_WILDCARD_LIMIT "wildcard_limit"
+
+/* Session Recording */
+#define CONFDB_SESSION_RECORDING_CONF_ENTRY "config/session_recording"
+#define CONFDB_SESSION_RECORDING_SCOPE "scope"
+#define CONFDB_SESSION_RECORDING_USERS "users"
+#define CONFDB_SESSION_RECORDING_GROUPS "groups"
+#define CONFDB_SESSION_RECORDING_EXCLUDE_USERS "exclude_users"
+#define CONFDB_SESSION_RECORDING_EXCLUDE_GROUPS "exclude_groups"
+
+/* Domains */
+#define CONFDB_DOMAIN_ENABLED "enabled"
+#define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s"
+#define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config"
+#define CONFDB_APP_DOMAIN_BASEDN "cn=application,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_SUDO_PROVIDER "sudo_provider"
+#define CONFDB_DOMAIN_AUTOFS_PROVIDER "autofs_provider"
+#define CONFDB_DOMAIN_SELINUX_PROVIDER "selinux_provider"
+#define CONFDB_DOMAIN_HOSTID_PROVIDER "hostid_provider"
+#define CONFDB_DOMAIN_SUBDOMAINS_PROVIDER "subdomains_provider"
+#define CONFDB_DOMAIN_SESSION_PROVIDER "session_provider"
+#define CONFDB_DOMAIN_RESOLVER_PROVIDER "resolver_provider"
+#define CONFDB_DOMAIN_COMMAND "command"
+#define CONFDB_DOMAIN_TIMEOUT "timeout"
+#define CONFDB_DOMAIN_ATTR "cn"
+#define CONFDB_DOMAIN_ENUMERATE "enumerate"
+#define CONFDB_SUBDOMAIN_ENUMERATE "subdomain_enumerate"
+#define CONFDB_DEFAULT_SUBDOMAIN_ENUMERATE "none"
+#define CONFDB_DOMAIN_MINID "min_id"
+#define CONFDB_DOMAIN_MAXID "max_id"
+#define CONFDB_DOMAIN_CACHE_CREDS "cache_credentials"
+#define CONFDB_DOMAIN_CACHE_CREDS_MIN_FF_LENGTH \
+ "cache_credentials_minimal_first_factor_length"
+#define CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH 8
+#define CONFDB_DOMAIN_AUTO_UPG "auto_private_groups"
+#define CONFDB_DOMAIN_FQ "use_fully_qualified_names"
+#define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout"
+#define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration"
+#define CONFDB_DOMAIN_OVERRIDE_GID "override_gid"
+#define CONFDB_DOMAIN_CASE_SENSITIVE "case_sensitive"
+#define CONFDB_DOMAIN_SUBDOMAIN_HOMEDIR "subdomain_homedir"
+#define CONFDB_DOMAIN_DEFAULT_SUBDOMAIN_HOMEDIR "/home/%d/%u"
+#define CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS "ignore_group_members"
+#define CONFDB_DOMAIN_SUBDOMAIN_REFRESH "subdomain_refresh_interval"
+#define CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE 14400
+#define CONFDB_DOMAIN_SUBDOMAIN_REFRESH_OFFSET "subdomain_refresh_interval_offset"
+#define CONFDB_DOMAIN_SUBDOMAIN_REFRESH_OFFSET_DEFAULT_VALUE 300
+
+#define CONFDB_DOMAIN_USER_CACHE_TIMEOUT "entry_cache_user_timeout"
+#define CONFDB_DOMAIN_GROUP_CACHE_TIMEOUT "entry_cache_group_timeout"
+#define CONFDB_DOMAIN_NETGROUP_CACHE_TIMEOUT "entry_cache_netgroup_timeout"
+#define CONFDB_DOMAIN_SERVICE_CACHE_TIMEOUT "entry_cache_service_timeout"
+#define CONFDB_DOMAIN_AUTOFS_CACHE_TIMEOUT "entry_cache_autofs_timeout"
+#define CONFDB_DOMAIN_SUDO_CACHE_TIMEOUT "entry_cache_sudo_timeout"
+#define CONFDB_DOMAIN_SSH_HOST_CACHE_TIMEOUT "entry_cache_ssh_host_timeout"
+#define CONFDB_DOMAIN_COMPUTER_CACHE_TIMEOUT "entry_cache_computer_timeout"
+#define CONFDB_DOMAIN_RESOLVER_CACHE_TIMEOUT "entry_cache_resolver_timeout"
+#define CONFDB_DOMAIN_PWD_EXPIRATION_WARNING "pwd_expiration_warning"
+#define CONFDB_DOMAIN_REFRESH_EXPIRED_INTERVAL "refresh_expired_interval"
+#define CONFDB_DOMAIN_REFRESH_EXPIRED_INTERVAL_OFFSET "refresh_expired_interval_offset"
+#define CONFDB_DOMAIN_OFFLINE_TIMEOUT "offline_timeout"
+#define CONFDB_DOMAIN_OFFLINE_TIMEOUT_MAX "offline_timeout_max"
+#define CONFDB_DOMAIN_OFFLINE_TIMEOUT_RANDOM_OFFSET "offline_timeout_random_offset"
+#define CONFDB_DOMAIN_SUBDOMAIN_INHERIT "subdomain_inherit"
+#define CONFDB_DOMAIN_CACHED_AUTH_TIMEOUT "cached_auth_timeout"
+#define CONFDB_DOMAIN_TYPE "domain_type"
+#define CONFDB_DOMAIN_TYPE_POSIX "posix"
+#define CONFDB_DOMAIN_TYPE_APP "application"
+#define CONFDB_DOMAIN_INHERIT_FROM "inherit_from"
+#define CONFDB_DOMAIN_LOCAL_AUTH_POLICY "local_auth_policy"
+
+/* Proxy Provider */
+#define CONFDB_PROXY_LIBNAME "proxy_lib_name"
+#define CONFDB_PROXY_RESOLVER_LIBNAME "proxy_resolver_lib_name"
+#define CONFDB_PROXY_PAM_TARGET "proxy_pam_target"
+#define CONFDB_PROXY_FAST_ALIAS "proxy_fast_alias"
+#define CONFDB_PROXY_MAX_CHILDREN "proxy_max_children"
+
+#ifdef BUILD_FILES_PROVIDER
+/* Files Provider */
+#define CONFDB_FILES_PASSWD "passwd_files"
+#define CONFDB_FILES_GROUP "group_files"
+#define CONFDB_DOMAIN_FALLBACK_TO_NSS "fallback_to_nss"
+#endif
+
+/* KCM Service */
+#define CONFDB_KCM_CONF_ENTRY "config/kcm"
+#define CONFDB_KCM_SOCKET "socket_path"
+#define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */
+#define CONFDB_KCM_CONTAINERS_NEST_LEVEL "containers_nest_level"
+#define CONFDB_KCM_MAX_CCACHES "max_ccaches"
+#define CONFDB_KCM_MAX_UID_CCACHES "max_uid_ccaches"
+#define CONFDB_KCM_MAX_CCACHE_SIZE "max_ccache_size"
+#define CONFDB_KCM_TGT_RENEWAL "tgt_renewal"
+#define CONFDB_KCM_TGT_RENEWAL_INHERIT "tgt_renewal_inherit"
+#define CONFDB_KCM_KRB5_LIFETIME "krb5_lifetime"
+#define CONFDB_KCM_KRB5_RENEWABLE_LIFETIME "krb5_renewable_lifetime"
+#define CONFDB_KCM_KRB5_RENEW_INTERVAL "krb5_renew_interval"
+#define CONFDB_KCM_KRB5_VALIDATE "krb5_validate"
+#define CONFDB_KCM_KRB5_CANONICALIZE "krb5_canonicalize"
+#define CONFDB_KCM_KRB5_AUTH_TIMEOUT "krb5_auth_timeout"
+
+/* Certificate mapping rules */
+#define CONFDB_CERTMAP_BASEDN "cn=certmap,cn=config"
+#define CONFDB_CERTMAP_NAME "cn"
+#define CONFDB_CERTMAP_MAPRULE "maprule"
+#define CONFDB_CERTMAP_MATCHRULE "matchrule"
+#define CONFDB_CERTMAP_DOMAINS "domains"
+#define CONFDB_CERTMAP_PRIORITY "priority"
+
+/* Prompting */
+#define CONFDB_PC_CONF_ENTRY "config/prompting"
+#define CONFDB_PC_TYPE_PASSWORD "password"
+#define CONFDB_PC_PASSWORD_PROMPT "password_prompt"
+#define CONFDB_PC_TYPE_2FA "2fa"
+#define CONFDB_PC_2FA_SINGLE_PROMPT "single_prompt"
+#define CONFDB_PC_2FA_1ST_PROMPT "first_prompt"
+#define CONFDB_PC_2FA_2ND_PROMPT "second_prompt"
+#define CONFDB_PC_TYPE_CERT_AUTH "cert_auth"
+#define CONFDB_PC_TYPE_PASSKEY "passkey"
+#define CONFDB_PC_PASSKEY_INTERACTIVE "interactive"
+#define CONFDB_PC_PASSKEY_INTERACTIVE_PROMPT "interactive_prompt"
+#define CONFDB_PC_PASSKEY_TOUCH "touch"
+#define CONFDB_PC_PASSKEY_TOUCH_PROMPT "touch_prompt"
+
+struct confdb_ctx;
+
+/** sssd domain state */
+enum sss_domain_state {
+ /** Domain is usable by both responders and providers. This
+ * is the default state after creating a new domain
+ */
+ DOM_ACTIVE,
+ /** Domain was removed, should not be used be neither responders
+ * not providers.
+ */
+ DOM_DISABLED,
+ /** Domain cannot be contacted. Providers return an offline error code
+ * when receiving request for inactive domain, but responders should
+ * return cached data
+ */
+ DOM_INACTIVE,
+ /** Domain is being updated. Responders should ignore cached data and
+ * always contact the DP
+ */
+ DOM_INCONSISTENT,
+};
+
+/** Whether the domain only supports looking up POSIX entries */
+enum sss_domain_type {
+ /** This is the default domain type. It resolves only entries
+ * with the full POSIX set of attributes
+ */
+ DOM_TYPE_POSIX,
+ /** In this mode, entries are typically resolved only by name */
+ DOM_TYPE_APPLICATION,
+};
+
+enum sss_domain_mpg_mode {
+ MPG_DISABLED,
+ MPG_ENABLED,
+ MPG_HYBRID,
+ MPG_DEFAULT, /* Use default value for given id mapping. */
+};
+
+/**
+ * Data structure storing all of the basic features
+ * of a domain.
+ */
+struct sss_domain_info {
+ enum sss_domain_type type;
+
+ char *name;
+ char *conn_name;
+ char *provider;
+ int timeout;
+ bool enumerate;
+ char **sd_enumerate;
+ bool fqnames;
+ enum sss_domain_mpg_mode mpg_mode;
+ bool ignore_group_members;
+ uint32_t id_min;
+ uint32_t id_max;
+ const char *pwfield;
+
+ bool cache_credentials;
+ uint32_t cache_credentials_min_ff_length;
+ bool case_sensitive;
+ bool case_preserve;
+
+ gid_t override_gid;
+ const char *override_homedir;
+ const char *fallback_homedir;
+ const char *subdomain_homedir;
+ const char *homedir_substr;
+ const char *override_shell;
+ const char *default_shell;
+
+ uint32_t user_timeout;
+ uint32_t group_timeout;
+ uint32_t netgroup_timeout;
+ uint32_t service_timeout;
+ uint32_t autofsmap_timeout;
+ uint32_t sudo_timeout;
+ uint32_t ssh_host_timeout;
+ uint32_t computer_timeout;
+ uint32_t resolver_timeout;
+
+ uint32_t refresh_expired_interval;
+ uint32_t refresh_expired_interval_offset;
+ uint32_t subdomain_refresh_interval;
+ uint32_t subdomain_refresh_interval_offset;
+ uint32_t cached_auth_timeout;
+
+ int pwd_expiration_warning;
+
+ struct sysdb_ctx *sysdb;
+ struct sss_names_ctx *names;
+
+ struct sss_domain_info *parent;
+ struct sss_domain_info *subdomains;
+ char *realm;
+ char *flat_name;
+ char *dns_name;
+ char *domain_id;
+ uint32_t trust_direction;
+ struct timeval subdomains_last_checked;
+
+ bool has_views;
+ const char *view_name;
+
+ struct sss_domain_info *prev;
+ struct sss_domain_info *next;
+
+ enum sss_domain_state state;
+#ifdef BUILD_FILES_PROVIDER
+ bool fallback_to_nss;
+#endif
+ char **sd_inherit;
+
+ /* Do not use the forest pointer directly in new code, but rather the
+ * forest_root pointer. sss_domain_info will be more opaque in the future
+ */
+ char *forest;
+ struct sss_domain_info *forest_root;
+ const char **upn_suffixes;
+
+ struct certmap_info **certmaps;
+ bool user_name_hint;
+
+ /* Do not use the _output_fqnames property directly in new code, but rather
+ * use sss_domain_info_{get,set}_output_fqnames(). */
+ bool output_fqnames;
+
+ /* Hostname associated with this domain. */
+ const char *hostname;
+
+ /* Keytab used by this domain. */
+ const char *krb5_keytab;
+
+ /* List of PAM services that are allowed to authenticate with GSSAPI. */
+ char **gssapi_services;
+ char *gssapi_check_upn; /* true | false | NULL */
+ /* List of indicators associated with the specific PAM service */
+ char **gssapi_indicators_map;
+
+ /* Counts how often the domain was not found during a refresh of the
+ * domain list */
+ size_t not_found_counter;
+};
+
+/**
+ * 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,
+ const 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);
+
+/**
+ * Retrieve the list of enabled domains considering the explicit list
+ * and the 'enabled' attribute.
+ * @param cdb The database configuration context.
+ * @param ctx The memory context.
+ * @param result Output variable where the list of domains will be stored.
+ * @return 0 if the list was retrieved properly, ENOENT if no domain is enabled, another value on error.
+ */
+int confdb_get_enabled_domain_list(struct confdb_ctx *cdb,
+ TALLOC_CTX *ctx, char ***_result);
+
+int confdb_expand_app_domains(struct confdb_ctx *cdb);
+
+/**
+ * Get a null-terminated linked-list of all domain names
+ * @param[in] mem_ctx The parent memory context for the value list
+ * @param[in] cdb The connection object to the confdb
+ * @param[out] _names Output list
+ *
+ * @return 0 - Lookup succeeded and all domain names are in the list
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return ENOENT - No active domains are configured
+ * @return EIO - There was an I/O error communicating with the ConfDB file
+ * @return EINVAL - Corrupted confdb object
+ */
+int confdb_list_all_domain_names(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ char ***_names);
+
+
+/**
+ * @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] 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,
+ 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] 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,
+ const char *section, const char *attribute,
+ bool defval, bool *result);
+
+/**
+ * @brief Convenience function to set a single-valued attribute as a string
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @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] val New value of the attribute.
+ *
+ * @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
+ * @return EIO - An I/O error occurred while communicating with the ConfDB
+ */
+int confdb_set_string(struct confdb_ctx *cdb,
+ const char *section,
+ const char *attribute,
+ const char *val);
+
+/**
+ * @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);
+
+/**
+ * @brief Convenience function to retrieve a list of subsections given a
+ * configuration section name
+ *
+ * @param[in] mem_ctx The parent memory context for the returned list
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] section The ConfDB section to look for.
+ * All sections should start with 'config/'.
+ * Subsections are separated by slashes.
+ * @param[out] sections Names of the subsections relative to the section
+ * requested. If "a/b" is requested then "c/d" is
+ * returned for the section named [a/b/c/d]
+ * @param[out] num_sections Number of section names returned
+ *
+ * @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.
+ * @return ENOENT - No section was found.
+ * @return EIO - An I/O error occurred while communicating with the ConfDB
+ */
+int confdb_get_sub_sections(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ const char *section,
+ char ***sections,
+ int *num_sections);
+
+/**
+ * @brief Convenience function to write the certificate mapping and matching
+ * rules from the configuration database to the cache of a domain
+ *
+ * @param[in] cdb The connection object to the confdb
+ * @param[in] dom Target domain where to rules should be written to
+ *
+ * @return 0 - Successfully retrieved the entry (or used the default)
+ * @return ENOMEM - There was insufficient memory to complete the operation
+ * @return EINVAL - Typically internal processing error
+ */
+int confdb_certmap_to_sysdb(struct confdb_ctx *cdb,
+ struct sss_domain_info *dom,
+ bool certmaps_for_local_users);
+
+/**
+ * @}
+ */
+#endif
diff --git a/src/confdb/confdb_private.h b/src/confdb/confdb_private.h
new file mode 100644
index 0000000..1bab99c
--- /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 0000000..d33df1f
--- /dev/null
+++ b/src/confdb/confdb_setup.c
@@ -0,0 +1,444 @@
+/*
+ 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 "util/sss_ini.h"
+
+static 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(SSSDBG_CRIT_FAILURE, "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;
+ unsigned int 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 = sss_ldb_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 = sss_ldb_error_to_errno(ret);
+ goto done;
+ }
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static 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(SSSDBG_FATAL_FAILURE,
+ "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_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
+ const char *config_file,
+ const char *config_dir,
+ const char *only_section,
+ struct sss_ini *init_data,
+ const char **_timestr,
+ const char **_ldif)
+{
+ errno_t ret;
+ char timestr[21] = "1";
+ int version;
+
+ ret = sss_ini_read_sssd_conf(init_data,
+ config_file,
+ config_dir);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (sss_ini_exists(init_data)) {
+ ret = sss_ini_get_stat(init_data);
+ if (ret != EOK) {
+ ret = errno;
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Status check on config file failed.\n");
+ return ret;
+ }
+
+ errno = 0;
+ ret = sss_ini_get_mtime(init_data, sizeof(timestr), timestr);
+ if (ret <= 0 || ret >= (int)sizeof(timestr)) {
+ ret = errno ? errno : EFAULT;
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to convert time_t to string??\n");
+ return ret;
+ }
+ }
+
+ /* FIXME: Determine if the conf file or any snippet has changed
+ * since we last updated the confdb or if some snippet was
+ * added or removed.
+ */
+
+ ret = sss_ini_call_validators(init_data,
+ SSSDDATADIR"/cfg_rules.ini");
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to call validators\n");
+ /* This is not fatal, continue */
+ }
+
+ /* Make sure that the config file version matches the confdb version */
+ ret = sss_ini_get_cfgobj(init_data, "sssd", "config_file_version");
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Internal error determining config_file_version\n");
+ return ret;
+ }
+
+ ret = sss_ini_check_config_obj(init_data);
+ if (ret != EOK) {
+ /* No known version. Use default. */
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Value of config_file_version option not found. "
+ "Assumed to be version %d.\n", CONFDB_DEFAULT_CFG_FILE_VER);
+ } else {
+ version = sss_ini_get_int_config_value(init_data,
+ CONFDB_DEFAULT_CFG_FILE_VER,
+ -1, &ret);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Config file version could not be determined\n");
+ return ret;
+ } else if (version < CONFDB_VERSION_INT) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Config file is an old version. "
+ "Please run configuration upgrade script.\n");
+ return EINVAL;
+ } else if (version > CONFDB_VERSION_INT) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Config file version is newer than confdb\n");
+ return EINVAL;
+ }
+ }
+
+ ret = sss_confdb_create_ldif(mem_ctx, init_data, only_section, _ldif);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not create LDIF for confdb\n");
+ return ret;
+ }
+
+ *_timestr = talloc_strdup(mem_ctx, timestr);
+ if (*_timestr == NULL) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+static int confdb_write_ldif(struct confdb_ctx *cdb,
+ const char *config_ldif,
+ bool replace_whole_db)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+
+ while ((ldif = ldb_ldif_read_string(cdb->ldb, &config_ldif))) {
+ if (ldif->changetype == LDB_CHANGETYPE_DELETE) {
+ /* We should remove this section */
+ ret = ldb_delete(cdb->ldb, ldif->msg->dn);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* Removing a non-existing section is not an error */
+ ret = LDB_SUCCESS;
+ }
+ } else {
+ ret = ldb_add(cdb->ldb, ldif->msg);
+ if (ret != LDB_SUCCESS && replace_whole_db == false) {
+ /* This section already existed, remove and re-add it. We
+ * really want to replace the whole thing instead of messing
+ * around with changetypes and flags on individual elements
+ */
+ ret = ldb_delete(cdb->ldb, ldif->msg->dn);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_add(cdb->ldb, ldif->msg);
+ }
+ }
+ }
+
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "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_init_db(const char *config_file,
+ const char *config_dir,
+ const char *only_section,
+ struct confdb_ctx *cdb)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ int sret = EOK;
+ bool in_transaction = false;
+ const char *timestr = NULL;
+ const char *config_ldif;
+ const char *vals[2] = { NULL, NULL };
+ struct sss_ini *init_data;
+
+ tmp_ctx = talloc_new(cdb);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory.\n");
+ return ENOMEM;
+ }
+
+ init_data = sss_ini_new(tmp_ctx);
+ if (!init_data) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = confdb_ldif_from_ini_file(tmp_ctx,
+ config_file,
+ config_dir,
+ only_section,
+ init_data,
+ &timestr,
+ &config_ldif);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot convert INI to LDIF [%d]: [%s]\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ DEBUG(SSSDBG_CONF_SETTINGS, "LDIF file to import: \n%s\n", config_ldif);
+
+ /* Set up a transaction to replace the configuration */
+ ret = ldb_transaction_start(cdb->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to start a transaction for "
+ "updating the configuration\n");
+ ret = sss_ldb_error_to_errno(ret);
+ goto done;
+ }
+ in_transaction = true;
+
+ /* Purge existing database, if we are reinitializing the confdb completely */
+ if (only_section == NULL) {
+ ret = confdb_purge(cdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Could not purge existing configuration\n");
+ goto done;
+ }
+ }
+
+ ret = confdb_write_ldif(cdb,
+ config_ldif,
+ only_section == NULL ? true : false);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* now store the lastUpdate time so that we do not re-init if nothing
+ * changed on restart */
+
+ vals[0] = timestr;
+ ret = confdb_add_param(cdb, true, "config", "lastUpdate", vals);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to set last update time on db!\n");
+ goto done;
+ }
+
+ ret = ldb_transaction_commit(cdb->ldb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
+ goto done;
+ }
+ in_transaction = false;
+
+ ret = EOK;
+
+done:
+ if (in_transaction) {
+ sret = ldb_transaction_cancel(cdb->ldb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
+ }
+ }
+
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+errno_t confdb_setup(TALLOC_CTX *mem_ctx,
+ const char *cdb_file,
+ const char *config_file,
+ const char *config_dir,
+ const char *only_section,
+ struct confdb_ctx **_cdb)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct confdb_ctx *cdb;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ ret = confdb_init(tmp_ctx, &cdb, cdb_file);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "The confdb initialization failed "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ /* Initialize the CDB from the configuration file */
+ ret = confdb_test(cdb);
+ if (ret == ENOENT) {
+ /* First-time setup */
+
+ /* Purge any existing confdb in case an old
+ * misconfiguration gets in the way
+ */
+ talloc_zfree(cdb);
+ ret = unlink(cdb_file);
+ if (ret != EOK && errno != ENOENT) {
+ ret = errno;
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Purging existing confdb failed: %d [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = confdb_init(tmp_ctx, &cdb, cdb_file);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "The confdb initialization failed "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ }
+
+ /* Load special entries */
+ ret = confdb_create_base(cdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Unable to load special entries into confdb\n");
+ goto done;
+ }
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error initializing confdb\n");
+ goto done;
+ }
+
+ ret = confdb_init_db(config_file, config_dir, only_section, cdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "ConfDB initialization has failed "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ *_cdb = talloc_steal(mem_ctx, cdb);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/confdb/confdb_setup.h b/src/confdb/confdb_setup.h
new file mode 100644
index 0000000..c7fe595
--- /dev/null
+++ b/src/confdb/confdb_setup.h
@@ -0,0 +1,55 @@
+/*
+ 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"
+
+errno_t confdb_setup(TALLOC_CTX *mem_ctx,
+ const char *cdb_file,
+ const char *config_file,
+ const char *config_dir,
+ const char *only_section,
+ struct confdb_ctx **_cdb);
+
+#endif /* CONFDB_SETUP_H_ */