From 080d0d13b0447806ec6f1a8beb21f6b9d322d309 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Sat, 11 Apr 2009 10:20:48 -0400 Subject: [PATCH] Allow configuration of the SSSD through /etc/sssd/sssd.conf The SSSD now links with the ini_config and collection libraries in the common directory. The monitor will track changes to the /etc/sssd/sssd.conf file using inotify on platforms that support it, or polled every 5 seconds on platforms that do not. At startup or modification of the conf file, the monitor will purge the existing confdb and reread it completely from the conf file, to ensure that there are no lingering entries. It does this in a transaction, so there should be no race condition with the client services. A new option has been added to the startup options for the SSSD. It is now possible to specify an alternate config file with the -c at the command line. --- server/Makefile.in | 20 ++- server/confdb/confdb.c | 498 +++++++++++++++++++++++++++++++---- server/confdb/confdb.h | 22 ++- server/confdb/confdb_private.h | 42 +--- server/configure.ac | 2 + server/etc/sssd.conf | 51 ++++ server/infopipe/infopipe.c | 2 +- server/monitor/monitor.c | 87 ++++++- server/monitor/monitor.h | 5 +- server/providers/data_provider.c | 2 +- server/providers/data_provider_be.c | 2 +- server/responder/nss/nsssrv.c | 2 +- server/responder/pam/pamsrv.c | 2 +- server/sbus/sssd_dbus_connection.c | 1 + server/tools/tools_util.c | 2 +- server/util/server.c | 5 +- server/util/util.h | 1 + 17 files changed, 632 insertions(+), 114 deletions(-) create mode 100644 server/etc/sssd.conf diff --git a/server/Makefile.in b/server/Makefile.in index d7d114c..df211bf 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -18,6 +18,7 @@ builddir = @builddir@ sharedbuilddir = @sharedbuilddir@ INSTALLCMD = @INSTALL@ EXTRA_OBJ=@EXTRA_OBJ@ +SSSD_CONF_DIR = @sysconfdir@/sssd SSSD_LIBEXEC_PATH = @libexecdir@/@PACKAGE_NAME@ SSSD_LIBDIR = @pluginpath@ LDB_LIBDIR = @libdir@/ldb @@ -62,6 +63,12 @@ OPENLDAP_LIBS = @OPENLDAP_LIBS@ LDAP_CFLAGS = $(OPENLDAP_CFLAGS) LDAP_LIBS = $(OPENLDAP_LIBS) +COLLECTION_CFLAGS = -I ../common/collection -I../common/trace +COLLECTION_LIBS = -L ../common/collection/.libs/ -lcollection + +INI_CFG_CFLAGS = -I ../common/ini +INI_CFG_LIBS = -L ../common/ini/.libs/ -lini_config + LIBDL = @LIBDL@ SHLIBEXT = @SHLIBEXT@ @@ -72,13 +79,15 @@ SHLD_FLAGS = @SHLD_FLAGS@ SONAMEFLAG = @SONAMEFLAG@ LDFLAGS += @LDFLAGS@ -L$(srcdir)/lib -LIBS = @LIBS@ $(TALLOC_LIBS) $(TDB_LIBS) $(TEVENT_LIBS) $(POPT_LIBS) $(LDB_LIBS) $(DBUS_LIBS) $(PCRE_LIBS) +LIBS = @LIBS@ $(TALLOC_LIBS) $(TDB_LIBS) $(TEVENT_LIBS) $(POPT_LIBS) $(LDB_LIBS) $(DBUS_LIBS) $(PCRE_LIBS) $(INI_CFG_LIBS) $(COLLECTION_LIBS) PICFLAG = @PICFLAG@ CFLAGS := -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ - $(POPT_CFLAGS) $(TALLOC_CFLAGS) $(TDB_CFLAGS) $(TEVENT_CFLAGS) $(LDB_CFLAGS) $(DBUS_CFLAGS) $(CHECK_CFLAGS) $(PCRE_CFLAGS) \ + $(POPT_CFLAGS) $(TALLOC_CFLAGS) $(TDB_CFLAGS) $(TEVENT_CFLAGS) \ + $(LDB_CFLAGS) $(DBUS_CFLAGS) $(CHECK_CFLAGS) $(PCRE_CFLAGS) \ + $(COLLECTION_CFLAGS) $(INI_CFG_CFLAGS)\ -DLIBDIR=\"$(libdir)\" -DVARDIR=\"$(localstatedir)\" -DSHLIBEXT=\"$(SHLIBEXT)\" -DSSSD_LIBEXEC_PATH=\"$(SSSD_LIBEXEC_PATH)\" \ - -DSSSD_INTROSPECT_PATH=\"$(SSSD_INTROSPECT_PATH)\" -DUSE_MMAP=1 $(CFLAGS) + -DSSSD_INTROSPECT_PATH=\"$(SSSD_INTROSPECT_PATH)\" -DSSSD_CONF_DIR=\"$(SSSD_CONF_DIR)\" -DUSE_MMAP=1 $(CFLAGS) MDLD = @MDLD@ MDLD_FLAGS = @MDLD_FLAGS@ @@ -109,6 +118,7 @@ OBJS = $(SERVER_OBJ) $(EXTRA_OBJ) headers = DBUS_SYSBUS_POLICY_DIR = @sysconfdir@/dbus-1/system.d +SSSD_CONF_FILE = etc/sssd.conf LIBEXECBINS = sbin/sssd_nss sbin/sssd_dp sbin/sssd_be sbin/sssd_pam ifneq (x$(HAVE_INFOPIPE), x) @@ -180,7 +190,8 @@ installdirs:: $(DESTDIR)$(SSSD_INTROSPECT_PATH)/infopipe \ $(DESTDIR)$(SSSD_PIPE_PATH)/private \ $(DESTDIR)$(SSSD_DB_PATH) \ - $(DESTDIR)$(SSSD_PID_PATH) + $(DESTDIR)$(SSSD_PID_PATH) \ + $(DESTDIR)$(SSSD_CONF_DIR) installheaders:: installdirs ifneq (x$(headers), x) @@ -207,3 +218,4 @@ ifneq (x$(HAVE_INFOPIPE), x) cp $(DBUS_SYSBUS_POLICIES) $(DESTDIR)$(DBUS_SYSBUS_POLICY_DIR) cp $(INFP_INTROSPECT_XML) $(DESTDIR)$(SSSD_INTROSPECT_PATH)/infopipe endif + cp $(SSSD_CONF_FILE) $(DESTDIR)$(SSSD_CONF_DIR) diff --git a/server/confdb/confdb.c b/server/confdb/confdb.c index 88700e3..4b996e1 100644 --- a/server/confdb/confdb.c +++ b/server/confdb/confdb.c @@ -20,6 +20,14 @@ */ #define _GNU_SOURCE + +#include +#include +#include + +#include "talloc.h" +#include "tevent.h" +#include "config.h" #include "ldb.h" #include "ldb_errors.h" #include "util/util.h" @@ -27,8 +35,17 @@ #include "confdb/confdb_private.h" #include "util/btreemap.h" #include "db/sysdb.h" -#define CONFDB_VERSION "0.1" -#define CONFDB_DOMAIN_BASEDN "cn=domains,cn=config" +#include "collection.h" +#include "collection_tools.h" +#include "ini_config.h" + +#ifdef HAVE_SYS_INOTIFY_H +#include +#endif + +#define CONFDB_VERSION "1" +#define CONFDB_BASEDN "cn=config" +#define CONFDB_DOMAIN_BASEDN "cn=domains,"CONFDB_BASEDN #define CONFDB_DOMAIN_ATTR "cn" #define CONFDB_MPG "magicPrivateGroups" #define CONFDB_FQ "useFullyQualifiedNames" @@ -41,6 +58,7 @@ } while(0) struct confdb_ctx { + char *config_file; struct tevent_context *pev; struct ldb_context *ldb; }; @@ -522,23 +540,243 @@ static int confdb_test(struct confdb_ctx *cdb) return EOK; } -static int confdb_init_db(struct confdb_ctx *cdb) +static int confdb_purge(struct confdb_ctx *cdb) +{ + int ret, i; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + struct ldb_dn *dn; + const char *attrs[] = { "dn", NULL }; + + tmp_ctx = talloc_new(NULL); + + dn = ldb_dn_new(tmp_ctx, cdb->ldb, "cn=config"); + + /* Get the list of all DNs */ + ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, + LDB_SCOPE_SUBTREE, attrs, NULL); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + goto done; + } + + for(i=0; icount; i++) { + /* Delete this DN */ + ret = ldb_delete(cdb->ldb, res->msgs[i]->dn); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + goto done; + } + } + +done: + talloc_free(tmp_ctx); + return ret; +} + +static int confdb_create_base(struct confdb_ctx *cdb) { - const char *base_ldif; - struct ldb_ldif *ldif; - const char *val[2] = {NULL, NULL}; int ret; + struct ldb_ldif *ldif; + + const char *base_ldif = CONFDB_BASE_LDIF; + + while ((ldif = ldb_ldif_read_string(cdb->ldb, &base_ldif))) { + ret = ldb_add(cdb->ldb, ldif->msg); + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Failed to initialize DB (%d,[%s]), aborting!\n", + ret, ldb_errstring(cdb->ldb))); + return EIO; + } + ldb_ldif_read_free(cdb->ldb, ldif); + } + + return EOK; +} + +static int confdb_create_ldif(TALLOC_CTX *mem_ctx, + struct collection_item *sssd_config, + char **config_ldif) +{ + int ret, i, j; + char *ldif; + char *tmp_ldif; + char *writer; + char **sections; + int section_count; + char *dn; + char *tmp_dn; + char *sec_dn; + char **attrs; + int attr_count; + char *ldif_attr; + struct collection_item *attr; + TALLOC_CTX *tmp_ctx; + size_t dn_size; + size_t ldif_len; + size_t attr_len; + + ldif_len = strlen(CONFDB_INTERNAL_LDIF); + ldif = talloc_array(mem_ctx, char, ldif_len+1); + if (!ldif) return ENOMEM; + + tmp_ctx = talloc_new(ldif); + if (!tmp_ctx) { + ret = ENOMEM; + goto error; + } + + memcpy(ldif, CONFDB_INTERNAL_LDIF, ldif_len); + writer = ldif+ldif_len; + + /* Read in the collection and convert it to an LDIF */ + /* Get the list of sections */ + sections = get_section_list(sssd_config, §ion_count, &ret); + if (ret != EOK) { + goto error; + } + + for(i = 0; i < section_count; i++) { + const char *rdn = NULL; + DEBUG(6,("Processing config section [%s]\n", sections[i])); + ret = parse_section(tmp_ctx, sections[i], &sec_dn, &rdn); + if (ret != EOK) { + goto error; + } + + dn = talloc_asprintf(tmp_ctx, + "dn: %s,cn=config\n" + "cn: %s\n", + sec_dn, rdn); + if(!dn) { + ret = ENOMEM; + goto error; + } + dn_size = strlen(dn); + + /* Get all of the attributes and their values as LDIF */ + attrs = get_attribute_list(sssd_config, sections[i], + &attr_count, &ret); + if (ret != EOK) { + goto error; + } + + for(j = 0; j < attr_count; j++) { + DEBUG(6, ("Processing attribute [%s]\n", attrs[j])); + ret = get_config_item(sections[i], attrs[j], sssd_config, + &attr); + if (ret != EOK) goto error; + + const char *value = get_const_string_config_value(attr, &ret); + if (ret != EOK) goto error; + + ldif_attr = talloc_asprintf(tmp_ctx, + "%s: %s\n", attrs[j], value); + DEBUG(9, ("%s", ldif_attr)); + + attr_len = strlen(ldif_attr); + + tmp_dn = talloc_realloc(tmp_ctx, dn, char, + dn_size+attr_len+1); + if(!tmp_dn) { + ret = ENOMEM; + goto error; + } + dn = tmp_dn; + memcpy(dn+dn_size, ldif_attr, attr_len+1); + dn_size += attr_len; + } + + dn_size ++; + tmp_dn = talloc_realloc(tmp_ctx, dn, char, + dn_size+1); + if(!tmp_dn) { + ret = ENOMEM; + goto error; + } + dn = tmp_dn; + dn[dn_size-1] = '\n'; + dn[dn_size] = '\0'; + + DEBUG(9, ("Section dn\n%s", dn)); + + tmp_ldif = talloc_realloc(mem_ctx, ldif, char, + ldif_len+dn_size+1); + if(!tmp_ldif) { + ret = ENOMEM; + goto error; + } + ldif = tmp_ldif; + memcpy(ldif+ldif_len, dn, dn_size); + ldif_len += dn_size; + + free_attribute_list(attrs); + talloc_free(dn); + } + + ldif[ldif_len] = '\0'; + + free_section_list(sections); + + *config_ldif = ldif; + talloc_free(tmp_ctx); + return EOK; + +error: + talloc_free(ldif); + return ret; +} + +static int confdb_init_db(struct confdb_ctx *cdb) +{ + int ret, i; + struct collection_item *sssd_config = NULL; + struct collection_item *error_list = NULL; + char *config_ldif; + struct ldb_ldif *ldif; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(cdb); if(tmp_ctx == NULL) return ENOMEM; - /* cn=confdb does not exists, means db is empty, populate */ - base_ldif = CONFDB_BASE_LDIF; - while ((ldif = ldb_ldif_read_string(cdb->ldb, &base_ldif))) { + /* Set up a transaction to replace the configuration */ + ret = ldb_transaction_start(cdb->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Failed to start a transaction for updating the configuration\n")); + talloc_free(tmp_ctx); + return sysdb_error_to_errno(ret); + } + + /* Purge existing database */ + ret = confdb_purge(cdb); + if (ret != EOK) { + DEBUG(0, ("Could not purge existing configuration\n")); + goto done; + } + + /* Read the configuration into a collection */ + ret = config_from_file("sssd", cdb->config_file, &sssd_config, + INI_STOP_ON_ANY, &error_list); + if (ret != EOK) { + DEBUG(0, ("Parse error reading configuration file [%s]\n", + cdb->config_file)); + print_file_parsing_errors(stderr, error_list); + goto done; + } + + ret = confdb_create_ldif(tmp_ctx, sssd_config, &config_ldif); + if (ret != EOK) { + DEBUG(0, ("Could not create LDIF for confdb\n")); + goto done; + } + + DEBUG(7, ("LDIF file to import: \n%s", config_ldif)); + + i=0; + while ((ldif = ldb_ldif_read_string(cdb->ldb, (const char **)&config_ldif))) { ret = ldb_add(cdb->ldb, ldif->msg); if (ret != LDB_SUCCESS) { - DEBUG(0, ("Failed to inizialiaze DB (%d,[%s]), aborting!\n", + DEBUG(0, ("Failed to initialize DB (%d,[%s]), aborting!\n", ret, ldb_errstring(cdb->ldb))); ret = EIO; goto done; @@ -546,45 +784,12 @@ static int confdb_init_db(struct confdb_ctx *cdb) ldb_ldif_read_free(cdb->ldb, ldif); } -/* InfoPipe */ -#ifdef HAVE_INFOPIPE - /* Set the sssd_info description */ - val[0] = "InfoPipe Configuration"; - ret = confdb_add_param(cdb, false, "config/services/info", "description", val); - if (ret != EOK) goto done; - - /* Set the sssd_info command path */ - val[0] = talloc_asprintf(tmp_ctx, "%s/sssd_info", SSSD_LIBEXEC_PATH); - CONFDB_ZERO_CHECK_OR_JUMP(val[0], ret, ENOMEM, done); - ret = confdb_add_param(cdb, false, "config/services/info", "command", val); - if (ret != EOK) goto done; - - /* Add the InfoPipe to the list of active services */ - val[0] = "info"; - ret = confdb_add_param(cdb, false, "config/services", "activeServices", val); - if (ret != EOK) goto done; -#endif - -/* PolicyKit */ -#ifdef HAVE_POLICYKIT - /* Set the sssd_pk description */ - val[0] = "PolicyKit Backend Configuration"; - ret = confdb_add_param(cdb, false, "config/services/pk", "description", val); - if (ret != EOK) goto done; - - /* Set the sssd_info command path */ - val[0] = talloc_asprintf(tmp_ctx, "%s/sssd_pk", SSSD_LIBEXEC_PATH); - CONFDB_ZERO_CHECK_OR_JUMP(val[0], ret, ENOMEM, done); - ret = confdb_add_param(cdb, false, "config/services/pk", "command", val); - if (ret != EOK) goto done; - - /* Add the InfoPipe to the list of active services */ - val[0] = "pk"; - ret = confdb_add_param(cdb, false, "config/services", "activeServices", val); - if (ret != EOK) goto done; -#endif + ret = EOK; done: + ret == EOK ? + ldb_transaction_commit(cdb->ldb) : + ldb_transaction_cancel(cdb->ldb); talloc_free(tmp_ctx); return ret; } @@ -592,10 +797,11 @@ done: int confdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx **cdb_ctx, - char *confdb_location) + char *confdb_location, + const char *config_file) { struct confdb_ctx *cdb; - int ret; + int ret = EOK; cdb = talloc_zero(mem_ctx, struct confdb_ctx); if (!cdb) @@ -614,6 +820,8 @@ int confdb_init(TALLOC_CTX *mem_ctx, return EIO; } + cdb->config_file = talloc_strdup(cdb, config_file); + cdb->ldb = ldb_init(cdb, cdb->pev); if (!cdb->ldb) { talloc_free(cdb); @@ -628,10 +836,24 @@ int confdb_init(TALLOC_CTX *mem_ctx, ret = confdb_test(cdb); if (ret == ENOENT) { + /* First-time setup + * Load special entries + */ + confdb_create_base(cdb); + } + + + if (config_file) { ret = confdb_init_db(cdb); + if (ret != EOK) { + DEBUG(0,("Unable to initialize confdb!\n")); + } } + if (ret != EOK) { talloc_free(cdb); + DEBUG(0, ("ConfDB initialization has failed [%s]\n", + strerror(ret))); return ret; } @@ -640,6 +862,184 @@ int confdb_init(TALLOC_CTX *mem_ctx, return EOK; } +struct confdb_file_ctx { + TALLOC_CTX *parent_ctx; + struct confdb_ctx *cdb; + int fd; + char *filename; + time_t modified; + confdb_reconf_fn reconf_fn; + void *reconf_pvt; +}; + +#ifdef HAVE_SYS_INOTIFY_H +static void confdb_config_file_changed(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, void *data) +{ + int ret; + TALLOC_CTX *tmp_ctx; + struct inotify_event *in_event; + char *buf; + char *name; + ssize_t len; + ssize_t event_size = sizeof(struct inotify_event); + struct confdb_file_ctx *file_ctx = + talloc_get_type(data, struct confdb_file_ctx); + + DEBUG(1, ("Config file changed\n")); + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return; + + buf = talloc_size(tmp_ctx, event_size); + if (!buf) { + talloc_free(tmp_ctx); + return; + } + + len = read(file_ctx->fd, &buf, event_size); + if (len != event_size) { + DEBUG(0, ("Incomplete inotify event!\n")); + talloc_free(tmp_ctx); + return; + } + + in_event = (struct inotify_event *)&buf; + + if (in_event->len > 0) { + /* Read in the name, even though we don't use it, + * so that read ptr is in the right place + */ + name = talloc_size(tmp_ctx, len); + read(file_ctx->fd, &name, in_event->len); + } + + /* Parse the configuration file */ + ret = confdb_init_db(file_ctx->cdb); + if (ret != EOK) { + DEBUG(0, ("Could not reload configuration!")); + kill(getpid(), SIGTERM); + } + + /* Tell the monitor to signal the children */ + file_ctx->reconf_fn(file_ctx->cdb, file_ctx->reconf_pvt); + + talloc_free(tmp_ctx); +} +#else +static void confdb_poll_config_file(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval t, void *ptr) +{ + int ret, err; + struct stat file_stat; + struct timeval tv; + struct confdb_file_ctx *file_ctx = + talloc_get_type(ptr,struct confdb_file_ctx); + + ret = stat(file_ctx->filename, &file_stat); + if (ret < 0) { + err = errno; + DEBUG(0, ("Could not stat file [%s]. Error [%d:%s]\n", + file_ctx->filename, err, strerror(err))); + /* TODO: If the config file is missing, should we shut down? */ + return; + } + + if (file_stat.st_mtime != file_ctx->modified) { + /* Parse the configuration file and signal the children */ + /* Note: this will fire if the modification time changes into the past + * as well as the future. + */ + DEBUG(1, ("Config file changed\n")); + file_ctx->modified = file_stat.st_mtime; + + ret = confdb_init_db(file_ctx->cdb); + if (ret != EOK) { + DEBUG(0, ("Could not reload configuration!")); + kill(getpid(), SIGTERM); + } + + /* Tell the monitor to signal the children */ + file_ctx->reconf_fn(file_ctx->cdb, file_ctx->reconf_pvt); + } + + gettimeofday(&tv, NULL); + tv.tv_sec += CONFIG_FILE_POLL_INTERVAL; + tv.tv_usec = 0; + tevent_add_timer(ev, file_ctx->parent_ctx, tv, + confdb_poll_config_file, file_ctx); +} +#endif /* HAVE_SYS_INOTIFY_H */ + + + +int confdb_monitor_file(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + struct tevent_context *ev, + const char *file, + confdb_reconf_fn fn, + void *reconf_pvt) +{ + int ret, wd; + int fd, err; +#ifndef HAVE_SYS_INOTIFY_H + struct timeval tv; +#endif + struct stat file_stat; + struct confdb_file_ctx *file_ctx; + + ret = stat(file, &file_stat); + if (ret < 0) { + err = errno; + DEBUG(0, ("Could not stat file [%s]. Error [%d:%s]\n", + file, err, strerror(err))); + return err; + } + + file_ctx = talloc_zero(mem_ctx, struct confdb_file_ctx); + if (!file_ctx) return ENOMEM; + + file_ctx->parent_ctx = mem_ctx; + file_ctx->cdb = cdb; + file_ctx->filename = talloc_strdup(file_ctx, file); + file_ctx->modified = file_stat.st_mtime; + file_ctx->reconf_fn = fn; + file_ctx->reconf_pvt = reconf_pvt; + +#ifdef HAVE_SYS_INOTIFY_H + /* Set up inotify to monitor the config file for changes */ + fd = inotify_init(); + if (fd < 0) { + err = errno; + DEBUG(0, ("Could not initialize inotify, error [%d:%s]\n", + err, strerror(err))); + return err; + } + + wd = inotify_add_watch(fd, file, IN_MODIFY); + if (wd < 0) { + err = errno; + DEBUG(0, ("Could not add inotify watch for file [%s]. Error [%d:%s]\n", + file, err, strerror(err))); + return err; + } + + /* Add the inotify file descriptor to the TEvent context */ + file_ctx->fd = fd; + + tevent_add_fd(ev, mem_ctx, fd, TEVENT_FD_READ, + confdb_config_file_changed, file_ctx); +#else + gettimeofday(&tv, NULL); + tv.tv_sec += CONFIG_FILE_POLL_INTERVAL; + tv.tv_usec = 0; + tevent_add_timer(ev, mem_ctx, tv, confdb_poll_config_file, file_ctx); +#endif /* HAVE_SYS_INOTIFY_H */ + + return EOK; +} int confdb_get_domains(struct confdb_ctx *cdb, TALLOC_CTX *mem_ctx, struct sss_domain_info **domains) diff --git a/server/confdb/confdb.h b/server/confdb/confdb.h index b366d60..040d2ca 100644 --- a/server/confdb/confdb.h +++ b/server/confdb/confdb.h @@ -26,10 +26,20 @@ #include "talloc.h" #include "tevent.h" #include "util/btreemap.h" +#include "config.h" #define CONFDB_FILE "config.ldb" +#define CONFDB_DEFAULT_CONFIG_FILE SSSD_CONF_DIR"/sssd.conf" #define SSSD_MIN_ID 1000 +#ifndef HAVE_SYS_INOTIFY_H +#define CONFIG_FILE_POLL_INTERVAL 5 /* seconds */ +#endif + +struct confdb_ctx; + +typedef int (*confdb_reconf_fn) (struct confdb_ctx *cdb, void *pvt); + struct sss_domain_info { char *name; char *provider; @@ -44,8 +54,6 @@ struct sss_domain_info { struct sss_domain_info *next; }; -struct confdb_ctx; - int confdb_add_param(struct confdb_ctx *cdb, bool replace, const char *section, @@ -74,10 +82,18 @@ int confdb_get_bool(struct confdb_ctx *cdb, TALLOC_CTX *ctx, int confdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx **cdb_ctx, - char *confdb_location); + char *confdb_location, + const char *config_file); int confdb_get_domains(struct confdb_ctx *cdb, TALLOC_CTX *mem_ctx, struct sss_domain_info **domains); +int confdb_monitor_file(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + struct tevent_context *ev, + const char *file, + confdb_reconf_fn fn, + void *reconf_pvt); + #endif diff --git a/server/confdb/confdb_private.h b/server/confdb/confdb_private.h index c632f97..f379195 100644 --- a/server/confdb/confdb_private.h +++ b/server/confdb/confdb_private.h @@ -12,43 +12,9 @@ "\n" \ "dn: @MODULES\n" \ "@LIST: server_sort\n" \ - "\n" \ + "\n" + +#define CONFDB_INTERNAL_LDIF \ "dn: cn=config\n" \ - "cn: config\n" \ - "version: 0.1\n" \ - "description: base object\n" \ - "\n" \ - "dn: cn=services,cn=config\n" \ - "cn: services\n" \ - "description: Local service configuration\n" \ - "activeServices: dp\n" \ - "activeServices: nss\n" \ - "activeServices: pam\n" \ - "\n" \ - "dn: cn=monitor,cn=services,cn=config\n" \ - "cn: monitor\n" \ - "description: Monitor Configuration\n" \ - "\n" \ - "dn: cn=dp,cn=services,cn=config\n" \ - "cn: dp\n" \ - "description: Data Provider Configuration\n" \ - "\n" \ - "dn: cn=nss,cn=services,cn=config\n" \ - "cn: nss\n" \ - "description: NSS Responder Configuration\n" \ - "\n" \ - "dn: cn=pam,cn=services,cn=config\n" \ - "cn: pam\n" \ - "description: PAM Responder Configuration\n" \ - "\n" \ - "dn: cn=domains,cn=config\n" \ - "cn: domains\n" \ - "description: Domains served by SSSD\n" \ - "domains: LOCAL\n" \ - "\n" \ - "dn: cn=LOCAL,cn=domains,cn=config\n" \ - "cn: LOCAL\n" \ - "description: LOCAL domain\n" \ - "enumerate: 3\n" \ - "magicPrivateGroups: TRUE\n" \ + "version: 1\n" \ "\n" diff --git a/server/configure.ac b/server/configure.ac index b373880..fade762 100644 --- a/server/configure.ac +++ b/server/configure.ac @@ -76,4 +76,6 @@ AC_LIBREPLACE_MDLD AC_LIBREPLACE_MDLD_FLAGS AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR +AC_CHECK_HEADERS([sys/inotify.h]) + AC_OUTPUT(Makefile) diff --git a/server/etc/sssd.conf b/server/etc/sssd.conf new file mode 100644 index 0000000..b15e92f --- /dev/null +++ b/server/etc/sssd.conf @@ -0,0 +1,51 @@ +[services] +description = Local Service Configuration +activeServices = nss, dp, pam, info + +[services/nss] +description = NSS Responder Configuration +timeout = 10 +filterGroups = root, foo@TEST +filterUsers = root, bar@TEST + +[services/dp] +description = Data Provider Configuration +timeout = 10 + +[services/pam] +description = PAM Responder Configuration +timeout = 10 + +[services/info] +description = InfoPipe Configuration +timeout = 10 + +[services/monitor] +description = Service Monitor Configuration +sbusTimeout = 10 +servicePingTime = 10 + +[domains] +description = Domains served by SSSD +domains = LOCAL + +[domains/LOCAL] +description = Reserved domain for local configurations +enumerate = 3 +minId = 500 +maxId = 999 +legacy = TRUE +libName = files +libPath = /lib64/libnss_files.so.2 +magicPrivateGroups = FALSE +provider = proxy +auth-module = proxy +pam-target = sssdproxylocal + +[domains/EXAMPLE.COM] +description = Example LDAP domain +basedn = dc=example,dc=com +command = /usr/libexec/sssd/sssd_be --provider ldap --domain EXAMPLE.COM +provider = ldap +userSearchBase = ou=user,dc=example,dc=com + diff --git a/server/infopipe/infopipe.c b/server/infopipe/infopipe.c index 7299830..9a142ac 100644 --- a/server/infopipe/infopipe.c +++ b/server/infopipe/infopipe.c @@ -733,7 +733,7 @@ int main(int argc, const char *argv[]) poptFreeContext(pc); /* set up things like debug , signals, daemonization, etc... */ - ret = server_setup("sssd[info]", 0, INFP_CONF_ENTRY, &main_ctx); + ret = server_setup("sssd[info]", 0, INFP_CONF_ENTRY, NULL, &main_ctx); if (ret != EOK) return 2; ret = infp_process_init(main_ctx, diff --git a/server/monitor/monitor.c b/server/monitor/monitor.c index 65664ca..e325104 100644 --- a/server/monitor/monitor.c +++ b/server/monitor/monitor.c @@ -100,6 +100,9 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name, static int add_new_service (struct mt_ctx *ctx, const char *name); static int add_new_provider (struct mt_ctx *ctx, const char *name); +static int monitor_signal_reconf(struct confdb_ctx *cdb, void *pvt); +static int update_monitor_config(struct mt_ctx *ctx); + /* dbus_get_monitor_version * Return the monitor version over D-BUS */ static int dbus_get_monitor_version(DBusMessage *message, @@ -474,6 +477,13 @@ done: dbus_message_unref(reply); } +static int monitor_signal_reconf(struct confdb_ctx *cdb, void *pvt) +{ + struct mt_ctx *ctx = talloc_get_type(pvt, struct mt_ctx); + DEBUG(1, ("Configuration has changed. Reloading.\n")); + return update_monitor_config(ctx); +} + static int service_signal_reload(struct mt_svc *svc) { DBusMessage *msg; @@ -513,6 +523,11 @@ static int service_signal_reload(struct mt_svc *svc) int get_monitor_config(struct mt_ctx *ctx) { int ret; + size_t svc_count = 0; + char *svcs; + char *cur, *p, *t; + char **svc_list = NULL; + char **tmp_list = NULL; ret = confdb_get_int(ctx->cdb, ctx, MONITOR_CONF_ENTRY, "sbusTimeout", @@ -521,22 +536,61 @@ int get_monitor_config(struct mt_ctx *ctx) return ret; } - ret = confdb_get_param(ctx->cdb, ctx, - "config/services", "activeServices", - &ctx->services); + ret = confdb_get_string(ctx->cdb, ctx, + "config/services", "activeServices", + NULL, &svcs); - if (ctx->services[0] == NULL) { + if (ret != EOK || svcs == NULL) { DEBUG(0, ("No services configured!\n")); return EINVAL; } + cur = p = talloc_strdup(svcs, svcs); + while (p && *p) { + for (cur = p; (*cur == ' ' || *cur == '\t'); cur++) /* trim */ ; + if (!*cur) break; + + p = strchr(cur, ','); + if (p) { + /* terminate element */ + *p = '\0'; + /* trim spaces */ + for (t = p-1; (*t == ' ' || *t == '\t'); t--) *t = '\0'; + p++; + } + + svc_count++; + tmp_list = talloc_realloc(svcs, svc_list, char *, svc_count); + if (!tmp_list) { + ret = ENOMEM; + goto done; + } + svc_list = tmp_list; + svc_list[svc_count-1] = talloc_strdup(svc_list, cur); + } + + svc_count++; + tmp_list = talloc_realloc(svcs, svc_list, char *, svc_count); + if (!tmp_list) { + ret = ENOMEM; + goto done; + } + svc_list = tmp_list; + svc_list[svc_count-1] = NULL; + + ctx->services = talloc_steal(ctx, svc_list); + ret = confdb_get_domains(ctx->cdb, ctx, &ctx->domains); if (ret != EOK) { DEBUG(2, ("No domains configured. LOCAL should always exist!\n")); return ret; } - return EOK; + ret = EOK; + +done: + talloc_free(svcs); + return ret; } static int get_service_config(struct mt_ctx *ctx, const char *name, @@ -604,7 +658,7 @@ static int get_service_config(struct mt_ctx *ctx, const char *name, return EOK; } -static int add_new_service (struct mt_ctx *ctx, const char *name) +static int add_new_service(struct mt_ctx *ctx, const char *name) { int ret; struct mt_svc *svc; @@ -701,7 +755,7 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name, return EOK; } -static int add_new_provider (struct mt_ctx *ctx, const char *name) +static int add_new_provider(struct mt_ctx *ctx, const char *name) { int ret; struct mt_svc *svc; @@ -960,7 +1014,8 @@ static void monitor_hup(struct tevent_context *ev, int monitor_process_init(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, - struct confdb_ctx *cdb) + struct confdb_ctx *cdb, + const char *config_file) { struct mt_ctx *ctx; struct sysdb_ctx *sysdb; @@ -980,6 +1035,10 @@ int monitor_process_init(TALLOC_CTX *mem_ctx, if (ret != EOK) return ret; + /* Watch for changes to the confdb config file */ + ret = confdb_monitor_file(ctx, cdb, event_ctx, config_file, monitor_signal_reconf, ctx); + if (ret != EOK) return ret; + /* Avoid a startup race condition between InfoPipe * and NSS. If the sysdb doesn't exist yet, both * will try to create it at the same time. So @@ -1165,6 +1224,8 @@ static void identity_check(DBusPendingCall *pending, void *data) goto done; } + DEBUG(4,("Received ID reply: (%s,%d)\n", svc_name, svc_ver)); + /* search this service in the list */ svc = fake_svc->mt_ctx->svc_list; while (svc) { @@ -1546,6 +1607,7 @@ int main(int argc, const char *argv[]) poptContext pc; int opt_daemon = 0; int opt_interactive = 0; + char *opt_config_file = NULL; int flags = 0; struct main_context *main_ctx; int ret; @@ -1557,6 +1619,8 @@ int main(int argc, const char *argv[]) "Become a daemon (default)", NULL }, \ {"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \ "Run interactive (not a daemon)", NULL}, \ + {"config", 'c', POPT_ARG_STRING, &opt_config_file, 0, \ + "Specify a non-default config file", NULL}, \ { NULL } }; @@ -1581,17 +1645,20 @@ int main(int argc, const char *argv[]) if (opt_daemon) flags |= FLAGS_DAEMON; if (opt_interactive) flags |= FLAGS_INTERACTIVE; + if (!opt_config_file) opt_config_file = CONFDB_DEFAULT_CONFIG_FILE; /* we want a pid file check */ flags |= FLAGS_PID_FILE; /* set up things like debug , signals, daemonization, etc... */ - ret = server_setup("sssd", flags, MONITOR_CONF_ENTRY, &main_ctx); + ret = server_setup("sssd", flags, MONITOR_CONF_ENTRY, + opt_config_file, &main_ctx); if (ret != EOK) return 2; ret = monitor_process_init(main_ctx, main_ctx->event_ctx, - main_ctx->confdb_ctx); + main_ctx->confdb_ctx, + opt_config_file); if (ret != EOK) return 3; /* loop on main */ diff --git a/server/monitor/monitor.h b/server/monitor/monitor.h index 77b6e78..0cabfb2 100644 --- a/server/monitor/monitor.h +++ b/server/monitor/monitor.h @@ -1,4 +1,4 @@ -/* +/* SSSD Service monitor @@ -24,6 +24,7 @@ int monitor_process_init(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, - struct confdb_ctx *cdb); + struct confdb_ctx *cdb, + const char *config_file); #endif /* _MONITOR_H */ diff --git a/server/providers/data_provider.c b/server/providers/data_provider.c index 4614250..0cdf317 100644 --- a/server/providers/data_provider.c +++ b/server/providers/data_provider.c @@ -1094,7 +1094,7 @@ int main(int argc, const char *argv[]) poptFreeContext(pc); /* set up things like debug , signals, daemonization, etc... */ - ret = server_setup("sssd[dp]", 0, DP_CONF_ENTRY, &main_ctx); + ret = server_setup("sssd[dp]", 0, DP_CONF_ENTRY, NULL, &main_ctx); if (ret != EOK) return 2; ret = dp_process_init(main_ctx, diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c index 61844bb..2e925d4 100644 --- a/server/providers/data_provider_be.c +++ b/server/providers/data_provider_be.c @@ -1034,7 +1034,7 @@ int main(int argc, const char *argv[]) conf_entry = talloc_asprintf(NULL, BE_CONF_ENTRY, be_domain); if (!conf_entry) return 2; - ret = server_setup(srv_name, 0, conf_entry, &main_ctx); + ret = server_setup(srv_name, 0, conf_entry, NULL, &main_ctx); if (ret != EOK) { DEBUG(0, ("Could not set up mainloop [%d]\n", ret)); return 2; diff --git a/server/responder/nss/nsssrv.c b/server/responder/nss/nsssrv.c index 58b09fb..6458143 100644 --- a/server/responder/nss/nsssrv.c +++ b/server/responder/nss/nsssrv.c @@ -293,7 +293,7 @@ int main(int argc, const char *argv[]) poptFreeContext(pc); /* set up things like debug , signals, daemonization, etc... */ - ret = server_setup("sssd[nss]", 0, NSS_SRV_CONFIG, &main_ctx); + ret = server_setup("sssd[nss]", 0, NSS_SRV_CONFIG, NULL, &main_ctx); if (ret != EOK) return 2; ret = nss_process_init(main_ctx, diff --git a/server/responder/pam/pamsrv.c b/server/responder/pam/pamsrv.c index 2f74a4a..c5955ec 100644 --- a/server/responder/pam/pamsrv.c +++ b/server/responder/pam/pamsrv.c @@ -205,7 +205,7 @@ int main(int argc, const char *argv[]) poptFreeContext(pc); /* set up things like debug , signals, daemonization, etc... */ - ret = server_setup("sssd[pam]", 0, PAM_SRV_CONFIG, &main_ctx); + ret = server_setup("sssd[pam]", 0, PAM_SRV_CONFIG, NULL, &main_ctx); if (ret != EOK) return 2; pam_dp_methods = register_pam_dp_methods(); diff --git a/server/sbus/sssd_dbus_connection.c b/server/sbus/sssd_dbus_connection.c index 1a3f107..cd9d5a1 100644 --- a/server/sbus/sssd_dbus_connection.c +++ b/server/sbus/sssd_dbus_connection.c @@ -573,6 +573,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *conn, ctx = talloc_get_type(user_data, struct sbus_message_handler_ctx); method = dbus_message_get_member(message); + DEBUG(9, ("Received SBUS method [%s]\n", method)); path = dbus_message_get_path(message); msg_interface = dbus_message_get_interface(message); diff --git a/server/tools/tools_util.c b/server/tools/tools_util.c index a366900..9cb4baa 100644 --- a/server/tools/tools_util.c +++ b/server/tools/tools_util.c @@ -60,7 +60,7 @@ int setup_db(struct tools_ctx **tools_ctx) } /* Connect to the conf db */ - ret = confdb_init(ctx, ctx->ev, &ctx->confdb, confdb_path); + ret = confdb_init(ctx, ctx->ev, &ctx->confdb, confdb_path, CONFDB_DEFAULT_CONFIG_FILE); if (ret != EOK) { DEBUG(1, ("Could not initialize connection to the confdb")); talloc_free(ctx); diff --git a/server/util/server.c b/server/util/server.c index b2d6a3c..9e76eb4 100644 --- a/server/util/server.c +++ b/server/util/server.c @@ -41,7 +41,7 @@ static void close_low_fds(bool stderr_too) int i; close(0); - close(1); + close(1); if (stderr_too) close(2); @@ -226,6 +226,7 @@ static void server_stdin_handler(struct tevent_context *event_ctx, */ int server_setup(const char *name, int flags, const char *conf_entry, + const char *config_file, struct main_context **main_ctx) { struct tevent_context *event_ctx; @@ -284,7 +285,7 @@ int server_setup(const char *name, int flags, } DEBUG(3, ("CONFDB: %s\n", conf_db)); - ret = confdb_init(ctx, event_ctx, &ctx->confdb_ctx, conf_db); + ret = confdb_init(ctx, event_ctx, &ctx->confdb_ctx, conf_db, config_file); if (ret != EOK) { DEBUG(0,("The confdb initialization failed\n")); return ret; diff --git a/server/util/util.h b/server/util/util.h index b3a7c72..bc74c87 100644 --- a/server/util/util.h +++ b/server/util/util.h @@ -57,6 +57,7 @@ struct main_context { /* from server.c */ int server_setup(const char *name, int flags, const char *conf_entry, + const char *config_file, struct main_context **main_ctx); void server_loop(struct main_context *main_ctx); -- 1.6.0.6