/* SSSD Configuration Database Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "config.h" #include <sys/stat.h> #include "util/util.h" #include "db/sysdb.h" #include "confdb.h" #include "confdb_private.h" #include "confdb_setup.h" #include "collection.h" #include "collection_tools.h" #include "ini_config.h" int confdb_test(struct confdb_ctx *cdb) { char **values; int ret; ret = confdb_get_param(cdb, cdb, "config", "version", &values); if (ret != EOK) { return ret; } if (values[0] == NULL) { /* empty database, will need to init */ talloc_free(values); return ENOENT; } if (values[1] != NULL) { /* more than 1 value ?? */ talloc_free(values); return EIO; } if (strcmp(values[0], CONFDB_VERSION) != 0) { /* bad version get out */ talloc_free(values); return EIO; } talloc_free(values); return EOK; } static int confdb_purge(struct confdb_ctx *cdb) { int ret, i; TALLOC_CTX *tmp_ctx; struct ldb_result *res; struct ldb_dn *dn; const char *attrs[] = { "dn", NULL }; tmp_ctx = talloc_new(NULL); dn = ldb_dn_new(tmp_ctx, cdb->ldb, "cn=config"); /* Get the list of all DNs */ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, attrs, NULL); if (ret != LDB_SUCCESS) { ret = sysdb_error_to_errno(ret); goto done; } for(i=0; i<res->count; i++) { /* Delete this DN */ ret = ldb_delete(cdb->ldb, res->msgs[i]->dn); if (ret != LDB_SUCCESS) { ret = sysdb_error_to_errno(ret); goto done; } } done: talloc_free(tmp_ctx); return ret; } int confdb_create_base(struct confdb_ctx *cdb) { int ret; struct ldb_ldif *ldif; const char *base_ldif = CONFDB_BASE_LDIF; while ((ldif = ldb_ldif_read_string(cdb->ldb, &base_ldif))) { ret = ldb_add(cdb->ldb, ldif->msg); if (ret != LDB_SUCCESS) { DEBUG(0, ("Failed to initialize DB (%d,[%s]), aborting!\n", ret, ldb_errstring(cdb->ldb))); return EIO; } ldb_ldif_read_free(cdb->ldb, ldif); } return EOK; } static int confdb_create_ldif(TALLOC_CTX *mem_ctx, struct collection_item *sssd_config, char **config_ldif) { int ret, i, j; char *ldif; char *tmp_ldif; char *writer; char **sections; int section_count; char *dn; char *tmp_dn; char *sec_dn; char **attrs; int attr_count; char *ldif_attr; struct collection_item *attr; TALLOC_CTX *tmp_ctx; size_t dn_size; size_t ldif_len; size_t attr_len; ldif_len = strlen(CONFDB_INTERNAL_LDIF); ldif = talloc_array(mem_ctx, char, ldif_len+1); if (!ldif) return ENOMEM; tmp_ctx = talloc_new(ldif); if (!tmp_ctx) { ret = ENOMEM; goto error; } memcpy(ldif, CONFDB_INTERNAL_LDIF, ldif_len); writer = ldif+ldif_len; /* Read in the collection and convert it to an LDIF */ /* Get the list of sections */ sections = get_section_list(sssd_config, §ion_count, &ret); if (ret != EOK) { goto error; } for(i = 0; i < section_count; i++) { const char *rdn = NULL; DEBUG(6,("Processing config section [%s]\n", sections[i])); ret = parse_section(tmp_ctx, sections[i], &sec_dn, &rdn); if (ret != EOK) { goto error; } dn = talloc_asprintf(tmp_ctx, "dn: %s,cn=config\n" "cn: %s\n", sec_dn, rdn); if(!dn) { ret = ENOMEM; free_section_list(sections); goto error; } dn_size = strlen(dn); /* Get all of the attributes and their values as LDIF */ attrs = get_attribute_list(sssd_config, sections[i], &attr_count, &ret); if (ret != EOK) { free_section_list(sections); goto error; } for(j = 0; j < attr_count; j++) { DEBUG(6, ("Processing attribute [%s]\n", attrs[j])); ret = get_config_item(sections[i], attrs[j], sssd_config, &attr); if (ret != EOK) goto error; const char *value = get_const_string_config_value(attr, &ret); if (ret != EOK) goto error; ldif_attr = talloc_asprintf(tmp_ctx, "%s: %s\n", attrs[j], value); DEBUG(9, ("%s", ldif_attr)); attr_len = strlen(ldif_attr); tmp_dn = talloc_realloc(tmp_ctx, dn, char, dn_size+attr_len+1); if(!tmp_dn) { ret = ENOMEM; free_attribute_list(attrs); free_section_list(sections); goto error; } dn = tmp_dn; memcpy(dn+dn_size, ldif_attr, attr_len+1); dn_size += attr_len; } dn_size ++; tmp_dn = talloc_realloc(tmp_ctx, dn, char, dn_size+1); if(!tmp_dn) { ret = ENOMEM; free_attribute_list(attrs); free_section_list(sections); goto error; } dn = tmp_dn; dn[dn_size-1] = '\n'; dn[dn_size] = '\0'; DEBUG(9, ("Section dn\n%s", dn)); tmp_ldif = talloc_realloc(mem_ctx, ldif, char, ldif_len+dn_size+1); if(!tmp_ldif) { ret = ENOMEM; free_attribute_list(attrs); free_section_list(sections); goto error; } ldif = tmp_ldif; memcpy(ldif+ldif_len, dn, dn_size); ldif_len += dn_size; free_attribute_list(attrs); talloc_free(dn); } ldif[ldif_len] = '\0'; free_section_list(sections); *config_ldif = ldif; talloc_free(tmp_ctx); return EOK; error: talloc_free(ldif); return ret; } int confdb_init_db(const char *config_file, struct confdb_ctx *cdb) { int ret, i; struct collection_item *sssd_config = NULL; struct collection_item *error_list = NULL; char *config_ldif; struct ldb_ldif *ldif; TALLOC_CTX *tmp_ctx; char *lasttimestr, timestr[21]; const char *vals[2] = { timestr, NULL }; struct stat cstat; tmp_ctx = talloc_new(cdb); if (tmp_ctx == NULL) return ENOMEM; /* ok, first of all stat conf file */ ret = stat(config_file, &cstat); if (ret != 0) { DEBUG(0, ("Unable to stat config file [%s]! (%d [%s])\n", config_file, errno, strerror(errno))); return errno; } ret = snprintf(timestr, 21, "%llu", (long long unsigned)cstat.st_mtime); if (ret <= 0 || ret >= 21) { DEBUG(0, ("Failed to convert time_t to string ??\n")); return errno ? errno: EFAULT; } /* check if we need to re-init the db */ ret = confdb_get_string(cdb, tmp_ctx, "config", "lastUpdate", NULL, &lasttimestr); if (ret == EOK && lasttimestr != NULL) { /* now check if we lastUpdate and last file modification change differ*/ if (strcmp(lasttimestr, timestr) == 0) { /* not changed, get out, nothing more to do */ return EOK; } } /* Set up a transaction to replace the configuration */ ret = ldb_transaction_start(cdb->ldb); if (ret != LDB_SUCCESS) { DEBUG(0, ("Failed to start a transaction for updating the configuration\n")); talloc_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 initialize DB (%d,[%s]), aborting!\n", ret, ldb_errstring(cdb->ldb))); ret = EIO; goto done; } ldb_ldif_read_free(cdb->ldb, ldif); } /* now store the lastUpdate time so that we do not re-init if nothing * changed on restart */ ret = confdb_add_param(cdb, true, "config", "lastUpdate", vals); if (ret != EOK) { DEBUG(1, ("Failed to set last update time on db!\n")); } ret = EOK; done: ret == EOK ? ldb_transaction_commit(cdb->ldb) : ldb_transaction_cancel(cdb->ldb); talloc_free(tmp_ctx); return ret; }