From 9396e620134760e7b562b5452f34ec80dc6f2af7 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Thu, 6 Nov 2008 15:45:24 -0500 Subject: Store all domains served by the SSSD to a binary-tree map for fast NSS lookup. Changed the "section" feature of confdb.c to use '/' as a delimiter instead of '.', because this conflicted with the ability to use dots in domain names. --- server/confdb/confdb.c | 93 +++++++++++++++++++++++++++++++++++++++++++-- server/confdb/confdb.h | 8 ++++ server/examples/config.ldif | 18 +++++++++ server/monitor.c | 8 ++-- server/nss/nsssrv.c | 58 +++++++++++++++++++++++++++- server/nss/nsssrv.h | 1 + server/nss/nsssrv_ldb.c | 2 +- server/server.mk | 1 + 8 files changed, 179 insertions(+), 10 deletions(-) (limited to 'server') diff --git a/server/confdb/confdb.c b/server/confdb/confdb.c index bab94b3f9..3064101a1 100644 --- a/server/confdb/confdb.c +++ b/server/confdb/confdb.c @@ -27,6 +27,8 @@ #include "util/util.h" #define CONFDB_VERSION "0.1" #define CONFDB_FILE "/var/lib/sss/db/config.ldb" +#define CONFDB_DOMAIN_BASEDN "cn=domains,cn=config" +#define CONFDB_DOMAIN_ATTR "cn" #define CONFDB_ZERO_CHECK_OR_JUMP(var, ret, err, label) do { \ if (!var) { \ @@ -67,15 +69,15 @@ static int parse_section(TALLOC_CTX *mem_ctx, const char *section, const char *s; int l, ret; - /* section must be a non null string and must not start with '.' */ - if (!section || !*section || *section == '.') return EINVAL; + /* 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, '.'))) { + while ((p = strchrnul(s, '/'))) { if (l == 0) { dn = talloc_asprintf(tmp_ctx, "cn=%s", s); l = 3 + (p-s); @@ -446,3 +448,88 @@ int confdb_init(TALLOC_CTX *mem_ctx, return EOK; } + +int confdb_get_domains(struct confdb_ctx *cdb, + TALLOC_CTX *mem_ctx, + char ***values) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_dn *dn; + struct ldb_result *res; + struct ldb_message_element *el; + int ret, i; + const char *attrs[] = {CONFDB_DOMAIN_ATTR, NULL}; + char **vals; + int val_count; + + tmp_ctx = talloc_new(mem_ctx); + + dn = ldb_dn_new(tmp_ctx,cdb->ldb, CONFDB_DOMAIN_BASEDN); + if (!dn) { + ret = EIO; + goto done; + } + + ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, + LDB_SCOPE_ONELEVEL, attrs, NULL); + if (ret != LDB_SUCCESS) { + ret = EIO; + goto done; + } + + val_count = 1; + vals = talloc(mem_ctx, char *); + if (!vals) { + ret = ENOMEM; + goto done; + } + + i = 0; + while (i < res->count) { + el = ldb_msg_find_element(res->msgs[i], CONFDB_DOMAIN_ATTR); + if (el && el->num_values > 0) { + if (el->num_values > 1) { + DEBUG(0, ("Error, domains should not have multivalued cn\n")); + ret = EINVAL; + goto done; + } + val_count++; + vals = talloc_realloc(mem_ctx, vals, char *, val_count); + if (!vals) { + DEBUG(0, ("realloc failed\n")); + ret = ENOMEM; + goto done; + } + /* should always be strings so this should be safe */ + struct ldb_val v = el->values[0]; + vals[i] = talloc_strndup(vals, (char *)v.data, v.length); + if (!vals[i]) { + ret = ENOMEM; + goto done; + } + } + i++; + } + vals[i] = NULL; + + *values = vals; + +done: + talloc_free(tmp_ctx); + return ret; +} + +int confdb_get_domain_basedn(struct confdb_ctx *cdb, + TALLOC_CTX *mem_ctx, + const char *domain, + char **basedn) +{ + char *section; + int ret; + + section = talloc_asprintf(mem_ctx, "config/domains/%s", domain); + ret = confdb_get_string(cdb, mem_ctx, section, "basedn", "cn=local", basedn); + + talloc_free(section); + return ret; +} diff --git a/server/confdb/confdb.h b/server/confdb/confdb.h index 7841d4c12..62ab45c7d 100644 --- a/server/confdb/confdb.h +++ b/server/confdb/confdb.h @@ -45,3 +45,11 @@ int confdb_get_int(struct confdb_ctx *cdb, TALLOC_CTX *ctx, int confdb_init(TALLOC_CTX *mem_ctx, struct event_context *ev, struct confdb_ctx **cdb_ctx); + +int confdb_get_domains(struct confdb_ctx *cdb, + TALLOC_CTX *mem_ctx, + char ***values); +int confdb_get_domain_basedn(struct confdb_ctx *cdb, + TALLOC_CTX *mem_ctx, + const char *domain, + char **basedn); diff --git a/server/examples/config.ldif b/server/examples/config.ldif index 9548d907e..13ddb026a 100644 --- a/server/examples/config.ldif +++ b/server/examples/config.ldif @@ -20,3 +20,21 @@ description: Monitor Configuration sbusTimeout: 10 sbusAddress: unix:path=/var/lib/sss/pipes/private/dbus servicePingTime: 10 + +dn: cn=domains,cn=config +cn: domains +description: Domains served by SSSD + +dn: cn=LOCAL,cn=domains,cn=config +cn: LOCAL +description: Reserved domain for local configurations +provider: local +basedn: cn=local + +dn: cn=EXAMPLE.COM,cn=domains,cn=config +cn: EXAMPLE.COM +description: Example domain served by IPA +provider: ipa +server: ipaserver1.example.com +server: ipabackupserver.example.com +basedn: cn=EXAMPLE.COM,cn=ipa,cn=remote diff --git a/server/monitor.c b/server/monitor.c index c5d5781f8..9eccb0b9e 100644 --- a/server/monitor.c +++ b/server/monitor.c @@ -112,7 +112,7 @@ static int monitor_dbus_init(struct mt_ctx *ctx) int ret; ret = confdb_get_string(ctx->cdb, ctx, - "config.services.monitor", "sbusAddress", + "config/services/monitor", "sbusAddress", DEFAULT_SBUS_ADDRESS, &sbus_address); if (ret != EOK) { return ret; @@ -253,14 +253,14 @@ int get_monitor_config(struct mt_ctx *ctx) int ret; ret = confdb_get_int(ctx->cdb, ctx, - "config.services.monitor", "sbusTimeout", + "config/services/monitor", "sbusTimeout", -1, &ctx->service_id_timeout); if (ret != EOK) { return ret; } ret = confdb_get_int(ctx->cdb, ctx, - "config.services.monitor", "servicePingTime", + "config/services/monitor", "servicePingTime", MONITOR_MIN_PING_TIME, &ctx->service_ping_time); if (ret != EOK) { return ret; @@ -269,7 +269,7 @@ int get_monitor_config(struct mt_ctx *ctx) ctx->service_ping_time = MONITOR_MIN_PING_TIME; ret = confdb_get_param(ctx->cdb, ctx, - "config.services", "activeServices", + "config/services", "activeServices", &ctx->services); if (ctx->services[0] == NULL) { diff --git a/server/nss/nsssrv.c b/server/nss/nsssrv.c index bd0f761b2..93f8d2235 100644 --- a/server/nss/nsssrv.c +++ b/server/nss/nsssrv.c @@ -38,9 +38,12 @@ #include "dbus/dbus.h" #include "sbus/sssd_dbus.h" #include "sbus_interfaces.h" +#include "util/btreemap.h" static int provide_identity(DBusMessage *message, void *data, DBusMessage **r); static int reply_ping(DBusMessage *message, void *data, DBusMessage **r); +static int nss_init_domains(struct nss_ctx *nctx); +static int _domain_comparator(void *key1, void *key2); struct sbus_method nss_sbus_methods[] = { {SERVICE_METHOD_IDENTITY, provide_identity}, @@ -250,7 +253,7 @@ static int nss_sbus_init(struct nss_ctx *nctx) int ret; ret = confdb_get_string(nctx->cdb, nctx, - "config.services.monitor", "sbusAddress", + "config/services/monitor", "sbusAddress", DEFAULT_SBUS_ADDRESS, &sbus_address); if (ret != EOK) { return ret; @@ -313,7 +316,7 @@ static int set_unix_socket(struct nss_ctx *nctx) int ret; ret = confdb_get_string(nctx->cdb, nctx, - "config.services.nss", "unixSocket", + "config/services/nss", "unixSocket", SSS_NSS_SOCKET_NAME, &nctx->sock_name); if (ret != EOK) { return ret; @@ -363,6 +366,51 @@ failed: return EIO; } +static int _domain_comparator(void *key1, void *key2) +{ + return strcmp((char *)key1, (char *)key2); +} + +static int nss_init_domains(struct nss_ctx *nctx) +{ + char **domains; + char *basedn; + TALLOC_CTX *tmp_ctx; + int ret, i; + int retval; + + tmp_ctx = talloc_new(nctx); + ret = confdb_get_domains(nctx->cdb, tmp_ctx, &domains); + if (ret != EOK) { + retval = ret; + goto done; + } + + i = 0; + while (domains[i] != NULL) { + DEBUG(3, ("Adding domain %s to the map\n", domains[i])); + /* Look up the appropriate basedn for this domain */ + ret = confdb_get_domain_basedn(nctx->cdb, tmp_ctx, domains[i], &basedn); + DEBUG(3, ("BaseDN: %s\n", basedn)); + btreemap_set_value(&nctx->domain_map, domains[i], basedn, _domain_comparator); + i++; + } + if (i == 0) { + /* No domains configured! + * Note: this should never happen, since LOCAL should + * always be configured */ + DEBUG(0, ("No domains configured on this client!\n")); + retval = EINVAL; + goto done; + } + + retval = EOK; + +done: + talloc_free(tmp_ctx); + return retval; +} + void nss_task_init(struct task_server *task) { struct nss_ctx *nctx; @@ -384,6 +432,12 @@ void nss_task_init(struct task_server *task) return; } + ret = nss_init_domains(nctx); + if (ret != EOK) { + task_server_terminate(task, "fatal error setting up domain map\n"); + return; + } + ret = nss_sbus_init(nctx); if (ret != EOK) { task_server_terminate(task, "fatal error setting up message bus\n"); diff --git a/server/nss/nsssrv.h b/server/nss/nsssrv.h index 5e2649370..5d49e79fe 100644 --- a/server/nss/nsssrv.h +++ b/server/nss/nsssrv.h @@ -50,6 +50,7 @@ struct nss_ctx { struct confdb_ctx *cdb; char *sock_name; struct nss_sbus_ctx *ns_ctx; + struct btreemap *domain_map; }; struct cli_ctx { diff --git a/server/nss/nsssrv_ldb.c b/server/nss/nsssrv_ldb.c index 56cdb5d7c..418b16e22 100644 --- a/server/nss/nsssrv_ldb.c +++ b/server/nss/nsssrv_ldb.c @@ -600,7 +600,7 @@ int nss_ldb_initgroups(TALLOC_CTX *mem_ctx, return LDB_SUCCESS; } -#define NSS_LDB_CONF_SECTION "config.services.nss" +#define NSS_LDB_CONF_SECTION "config/services/nss" static int nss_ldb_read_var(TALLOC_CTX *tmp_ctx, struct confdb_ctx *cdb, diff --git a/server/server.mk b/server/server.mk index 6339791e0..6277a5597 100644 --- a/server/server.mk +++ b/server/server.mk @@ -8,6 +8,7 @@ SERVER_OBJ = \ util/signal.o \ util/become_daemon.o \ util/memory.o \ + util/btreemap.o \ confdb/confdb.o \ nss/nsssrv.o \ nss/nsssrv_packet.o \ -- cgit