diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2009-04-11 10:20:48 -0400 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2009-04-13 09:06:49 -0400 |
commit | 4626af1ad1141291f226382f3569e4dd0486cd08 (patch) | |
tree | f35309c400cd028482750e0469db218e6eb02d49 | |
parent | c1d6bffe9ba81c265042859dddf3b39be87c161b (diff) | |
download | sssd-4626af1ad1141291f226382f3569e4dd0486cd08.tar.gz sssd-4626af1ad1141291f226382f3569e4dd0486cd08.tar.xz sssd-4626af1ad1141291f226382f3569e4dd0486cd08.zip |
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 <file> at the command line.
-rw-r--r-- | server/Makefile.in | 19 | ||||
-rw-r--r-- | server/confdb/confdb.c | 314 | ||||
-rw-r--r-- | server/confdb/confdb.h | 12 | ||||
-rw-r--r-- | server/confdb/confdb_private.h | 42 | ||||
-rw-r--r-- | server/configure.ac | 2 | ||||
-rw-r--r-- | server/examples/config.ldif | 88 | ||||
-rw-r--r-- | server/examples/db.ldif | 71 | ||||
-rw-r--r-- | server/examples/sssd.conf | 51 | ||||
-rw-r--r-- | server/monitor/monitor.c | 353 | ||||
-rw-r--r-- | server/monitor/monitor.h | 7 | ||||
-rw-r--r-- | server/sbus/sssd_dbus_connection.c | 1 |
11 files changed, 686 insertions, 274 deletions
diff --git a/server/Makefile.in b/server/Makefile.in index d7d114c3d..8aabd2f07 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) diff --git a/server/confdb/confdb.c b/server/confdb/confdb.c index 88700e301..4256418a6 100644 --- a/server/confdb/confdb.c +++ b/server/confdb/confdb.c @@ -20,6 +20,10 @@ */ #define _GNU_SOURCE + +#include "talloc.h" +#include "tevent.h" +#include "config.h" #include "ldb.h" #include "ldb_errors.h" #include "util/util.h" @@ -27,8 +31,13 @@ #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" + +#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" @@ -487,7 +496,7 @@ failed: return ret; } -static int confdb_test(struct confdb_ctx *cdb) +int confdb_test(struct confdb_ctx *cdb) { char **values; int ret; @@ -522,23 +531,254 @@ 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; i<res->count; i++) { + /* Delete this DN */ + ret = ldb_delete(cdb->ldb, res->msgs[i]->dn); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + goto done; + } + } + +done: + talloc_free(tmp_ctx); + return ret; +} + +int confdb_create_base(struct confdb_ctx *cdb) { - 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; + free_section_list(sections); + goto error; + } + dn_size = strlen(dn); + + /* Get all of the attributes and their values as LDIF */ + attrs = get_attribute_list(sssd_config, sections[i], + &attr_count, &ret); + if (ret != EOK) { + free_section_list(sections); + goto error; + } + + for(j = 0; j < attr_count; j++) { + DEBUG(6, ("Processing attribute [%s]\n", attrs[j])); + ret = get_config_item(sections[i], attrs[j], sssd_config, + &attr); + if (ret != EOK) goto error; + + const char *value = get_const_string_config_value(attr, &ret); + if (ret != EOK) goto error; + + ldif_attr = talloc_asprintf(tmp_ctx, + "%s: %s\n", attrs[j], value); + DEBUG(9, ("%s", ldif_attr)); + + attr_len = strlen(ldif_attr); + + tmp_dn = talloc_realloc(tmp_ctx, dn, char, + dn_size+attr_len+1); + if(!tmp_dn) { + ret = ENOMEM; + free_attribute_list(attrs); + free_section_list(sections); + goto error; + } + dn = tmp_dn; + memcpy(dn+dn_size, ldif_attr, attr_len+1); + dn_size += attr_len; + } + + dn_size ++; + tmp_dn = talloc_realloc(tmp_ctx, dn, char, + dn_size+1); + if(!tmp_dn) { + ret = ENOMEM; + free_attribute_list(attrs); + free_section_list(sections); + goto error; + } + dn = tmp_dn; + dn[dn_size-1] = '\n'; + dn[dn_size] = '\0'; + + DEBUG(9, ("Section dn\n%s", dn)); + + tmp_ldif = talloc_realloc(mem_ctx, ldif, char, + ldif_len+dn_size+1); + if(!tmp_ldif) { + ret = ENOMEM; + free_attribute_list(attrs); + free_section_list(sections); + goto error; + } + ldif = tmp_ldif; + memcpy(ldif+ldif_len, dn, dn_size); + ldif_len += dn_size; + + free_attribute_list(attrs); + talloc_free(dn); + } + + ldif[ldif_len] = '\0'; + + free_section_list(sections); + + *config_ldif = ldif; + talloc_free(tmp_ctx); + return EOK; + +error: + talloc_free(ldif); + return ret; +} + +int confdb_init_db(const char *config_file, struct confdb_ctx *cdb) +{ + int ret, i; + 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", config_file, &sssd_config, + INI_STOP_ON_ANY, &error_list); + if (ret != EOK) { + DEBUG(0, ("Parse error reading configuration file [%s]\n", + config_file)); + print_file_parsing_errors(stderr, error_list); + destroy_collection(error_list); + destroy_collection(sssd_config); + goto done; + } + + ret = confdb_create_ldif(tmp_ctx, sssd_config, &config_ldif); + destroy_collection(sssd_config); + if (ret != EOK) { + DEBUG(0, ("Could not create LDIF for confdb\n")); + goto done; + } + + DEBUG(7, ("LDIF file to import: \n%s", config_ldif)); + + i=0; + while ((ldif = ldb_ldif_read_string(cdb->ldb, (const char **)&config_ldif))) { ret = ldb_add(cdb->ldb, ldif->msg); if (ret != LDB_SUCCESS) { - DEBUG(0, ("Failed to 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 +786,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; } @@ -595,7 +802,7 @@ int confdb_init(TALLOC_CTX *mem_ctx, char *confdb_location) { struct confdb_ctx *cdb; - int ret; + int ret = EOK; cdb = talloc_zero(mem_ctx, struct confdb_ctx); if (!cdb) @@ -626,15 +833,6 @@ int confdb_init(TALLOC_CTX *mem_ctx, return EIO; } - ret = confdb_test(cdb); - if (ret == ENOENT) { - ret = confdb_init_db(cdb); - } - if (ret != EOK) { - talloc_free(cdb); - return ret; - } - *cdb_ctx = cdb; return EOK; diff --git a/server/confdb/confdb.h b/server/confdb/confdb.h index b366d60d5..ae66807ae 100644 --- a/server/confdb/confdb.h +++ b/server/confdb/confdb.h @@ -26,10 +26,16 @@ #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 +struct confdb_ctx; + +typedef int (*confdb_reconf_fn) (struct confdb_ctx *cdb, void *pvt); + struct sss_domain_info { char *name; char *provider; @@ -44,8 +50,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, @@ -80,4 +84,8 @@ int confdb_get_domains(struct confdb_ctx *cdb, TALLOC_CTX *mem_ctx, struct sss_domain_info **domains); +int confdb_create_base(struct confdb_ctx *cdb); +int confdb_test(struct confdb_ctx *cdb); +int confdb_init_db(const char *config_file, struct confdb_ctx *cdb); + #endif diff --git a/server/confdb/confdb_private.h b/server/confdb/confdb_private.h index c632f97de..f37919537 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 b37388027..fade762d4 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/examples/config.ldif b/server/examples/config.ldif deleted file mode 100644 index b9eb33407..000000000 --- a/server/examples/config.ldif +++ /dev/null @@ -1,88 +0,0 @@ -# editing 4 records -# record 1 -dn: cn=config -cn: config -version: 0.1 - -dn: cn=services,cn=config -cn: services -description: Local service configuration -activeServices: nss -activeServices: dp -activeServices: pam -activeServices: info - -dn: cn=nss,cn=services,cn=config -cn: nss -description: NSS Responder Configuration -filterGroups: root -filterGroups: foo@TEST -filterUsers: root -filterUsers: bar@TEST - -dn: cn=dp,cn=services,cn=config -cn: dp -description: Data Provider Configuration - -dn: cn=monitor,cn=services,cn=config -cn: monitor -description: Monitor Configuration -sbusTimeout: 10 -servicePingTime: 10 - -dn: cn=pam,cn=services,cn=config -cn: pam -description: PAM Responder Configuration - -dn: cn=info,cn=services,cn=config -cn: info -description: InfoPipe Configuration - -dn: cn=domains,cn=config -cn: domains -description: Domains served by SSSD -domains: LOCAL, EXAMPLE.COM, TEST - -dn: cn=LOCAL,cn=domains,cn=config -cn: 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 - -dn: cn=TEST,cn=domains,cn=config -cn: TEST -description: TEST Ldap domain -libName: ldap -libPath: /usr/lib64/libnss_ldap.so.2 -legacy: TRUE -enumerate: 3 -useFullyQualifiedNames: TRUE -minId: 1000 -provider: proxy -auth-module: proxy -pam-target: sssdproxytest - -dn: cn=LDAPTEST,cn=domains,cn=config -cn: LDAPTEST -basedn: cn=LDAPTEST,sn=sysdb -command: /usr/libexec/sssd/sssd_be --provider ldap --domain LDAPTEST -description: TEST PAM Ldap domain -provider: ldap -userSearchBase: ou=user,dc=my-domain,dc=com - -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 -legacy: FALSE -enumerate: 0 diff --git a/server/examples/db.ldif b/server/examples/db.ldif deleted file mode 100644 index 9ded6c794..000000000 --- a/server/examples/db.ldif +++ /dev/null @@ -1,71 +0,0 @@ -dn: @ATTRIBUTES -userPrincipalName: CASE_INSENSITIVE -cn: CASE_INSENSITIVE -dc: CASE_INSENSITIVE -dn: CASE_INSENSITIVE -name: CASE_INSENSITIVE -objectclass: CASE_INSENSITIVE - -dn: @INDEXLIST -@IDXATTR: cn -@IDXATTR: objectclass -@IDXATTR: member -@IDXATTR: memberof -@IDXATTR: memberUid -@IDXATTR: uid -@IDXATTR: gid -@IDXATTR: uidNumber -@IDXATTR: gidNumber -@IDXATTR: lastUpdate - -dn: @MODULES -@LIST: asq,memberof - -dn: cn=sysdb -cn: sysdb -version: 0.1 -description: base object - -dn: cn=local,cn=sysdb -cn: local -description: Local system data - -dn: cn=groups,cn=local,cn=sysdb -cn: groups -description: Local POSIX groups - -dn: gid=foousers,cn=groups,cn=local,cn=sysdb -gid: foousers -description: Local user accounts -member: uid=foobar,cn=users,cn=local,cn=sysdb -objectclass: group -gidNumber: 10101 - -dn: cn=users,cn=local,cn=sysdb -cn: users -description: Local POSIX users - -dn: uid=foobar,cn=users,cn=local,cn=sysdb -uid: foobar -objectClass: user -description: User Foo Bar -uidNumber: 10101 -gidNumber: 10101 -legacy: false -primaryGroup: cn=foousers,cn=groups,cn=local,cn=sysdb -userPassword: !@#$%#@#@!FOOBAR -homeDirectory: /home/foobar -fullName: Foo Bar -loginShell: /bin/bash -accountExpires: 20500101000000Z -biometricSignature: <binary> -disabled: false -failedLoginAttempts: 0 -keyboardLayout: it_IT -lastPasswordChange: 20080912142034Z -passwordHint: Favorite pasta sauce -passwordHistory: foo,bar,baz -preferredLanguage: IT -preferredSession: GNOME -memberOf: cn=foousers,cn=groups,cn=local,cn=sysdb - diff --git a/server/examples/sssd.conf b/server/examples/sssd.conf new file mode 100644 index 000000000..b15e92ff1 --- /dev/null +++ b/server/examples/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/monitor/monitor.c b/server/monitor/monitor.c index 65664ca61..168112242 100644 --- a/server/monitor/monitor.c +++ b/server/monitor/monitor.c @@ -24,6 +24,14 @@ #include <sys/wait.h> #include <sys/time.h> #include <time.h> +#include "config.h" +#ifdef HAVE_SYS_INOTIFY_H +#include <sys/inotify.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> #include "util/util.h" #include "popt.h" #include "tevent.h" @@ -79,6 +87,17 @@ struct mt_ctx { int service_id_timeout; }; +struct config_file_ctx { + TALLOC_CTX *parent_ctx; + struct confdb_ctx *cdb; + struct tevent_context *ev; + int fd; + char *filename; + time_t modified; + confdb_reconf_fn reconf_fn; + void *reconf_pvt; +}; + static int start_service(struct mt_svc *mt_svc); static int dbus_service_init(struct sbus_conn_ctx *conn_ctx, void *data); @@ -97,8 +116,11 @@ static int get_service_config(struct mt_ctx *ctx, const char *name, struct mt_svc **svc_cfg); static int get_provider_config(struct mt_ctx *ctx, const char *name, struct mt_svc **svc_cfg); -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 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 */ @@ -474,6 +496,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 +542,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 +555,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 +677,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 +774,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; @@ -958,9 +1031,233 @@ static void monitor_hup(struct tevent_context *ev, update_monitor_config(ctx); } +#ifdef HAVE_SYS_INOTIFY_H +static void 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, total_len; + ssize_t event_size = sizeof(struct inotify_event); + struct config_file_ctx *file_ctx = + talloc_get_type(data, struct config_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; + } + + total_len = 0; + while (total_len < event_size) { + len = read(file_ctx->fd, &buf+total_len, event_size-total_len); + if (len == -1 && errno != EINTR) { + DEBUG(0, ("Critical error reading inotify file descriptor.\n")); + talloc_free(tmp_ctx); + return; + } + total_len += len; + } + + 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); + total_len = 0; + while (total_len < in_event->len) { + len = read(file_ctx->fd, &name, in_event->len); + if (len == -1 && errno != EINTR) { + DEBUG(0, ("Critical error reading inotify file descriptor.\n")); + talloc_free(tmp_ctx); + return; + } + total_len += len; + } + } + + /* Parse the configuration file */ + ret = confdb_init_db(file_ctx->filename, 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); +} +#endif + +static void 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 tevent_timer *timer; + struct config_file_ctx *file_ctx = + talloc_get_type(ptr,struct config_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->filename, 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; + timer = tevent_add_timer(ev, file_ctx->parent_ctx, tv, + poll_config_file, file_ctx); + if (!timer) { + DEBUG(0, ("Error: Config file no longer monitored for changes!")); + } +} + +static int try_inotify(struct config_file_ctx *file_ctx) +{ +#ifdef HAVE_SYS_INOTIFY_H + int fd, wd, err, fd_args, ret; + struct tevent_fd *tfd; + + /* 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; + } + + fd_args = fcntl(fd, F_GETFL, NULL); + if (fd_args < 0) { + /* Could not set nonblocking */ + close(fd); + return EINVAL; + } + + fd_args |= O_NONBLOCK; + ret = fcntl(fd, F_SETFL, fd_args); + if (ret < 0) { + /* Could not set nonblocking */ + close(fd); + return EINVAL; + } + + wd = inotify_add_watch(fd, file_ctx->filename, IN_MODIFY); + if (wd < 0) { + err = errno; + DEBUG(0, ("Could not add inotify watch for file [%s]. Error [%d:%s]\n", + file_ctx->filename, err, strerror(err))); + close(fd); + return err; + } + + /* Add the inotify file descriptor to the TEvent context */ + file_ctx->fd = fd; + + tfd = tevent_add_fd(file_ctx->ev, file_ctx, fd, TEVENT_FD_READ, + config_file_changed, file_ctx); + if (!tfd) { + inotify_rm_watch(fd, wd); + close(fd); + return EIO; + } + return EOK; +#else + return EINVAL; +#endif +} + +static int monitor_config_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, err; + struct timeval tv; + + struct stat file_stat; + struct config_file_ctx *file_ctx; + + struct tevent_timer *timer; + + 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 config_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; + file_ctx->ev = ev; + + ret = try_inotify(file_ctx); + if (ret != EOK) { + /* Could not monitor file with inotify, fall back to polling */ + gettimeofday(&tv, NULL); + tv.tv_sec += CONFIG_FILE_POLL_INTERVAL; + tv.tv_usec = 0; + timer = tevent_add_timer(ev, mem_ctx, tv, poll_config_file, file_ctx); + if (!timer) { + talloc_free(file_ctx); + return EIO; + } + } + + return EOK; +} + 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; @@ -976,10 +1273,37 @@ int monitor_process_init(TALLOC_CTX *mem_ctx, ctx->ev = event_ctx; ctx->cdb = cdb; + /* Initialize the CDB from the configuration file */ + ret = confdb_test(ctx->cdb); + if (ret == ENOENT) { + /* First-time setup + * Load special entries + */ + ret = confdb_create_base(cdb); + if (ret != EOK) { + talloc_free(ctx); + return ret; + } + } + + ret = confdb_init_db(config_file, cdb); + if (ret != EOK) { + talloc_free(cdb); + DEBUG(0, ("ConfDB initialization has failed [%s]\n", + strerror(ret))); + talloc_free(ctx); + return ret; + } + + /* Read in the monitor's configuration */ ret = get_monitor_config(ctx); if (ret != EOK) return ret; + /* Watch for changes to the confdb config file */ + ret = monitor_config_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 +1489,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 +1872,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 +1884,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,6 +1910,7 @@ 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; @@ -1591,7 +1921,8 @@ int main(int argc, const char *argv[]) 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 77b6e781d..2a5218b14 100644 --- a/server/monitor/monitor.h +++ b/server/monitor/monitor.h @@ -1,4 +1,4 @@ -/* +/* SSSD Service monitor @@ -22,8 +22,11 @@ #ifndef _MONITOR_H_ #define _MONITOR_H_ +#define CONFIG_FILE_POLL_INTERVAL 5 /* seconds */ + 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/sbus/sssd_dbus_connection.c b/server/sbus/sssd_dbus_connection.c index 1a3f107c9..cd9d5a182 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); |