From b8e9773e9316bf09401c1c3296659e7dead1baf4 Mon Sep 17 00:00:00 2001 From: William Brown Date: Aug 21 2020 00:06:56 +0000 Subject: Ticket 51177 - on upgrade configuration handlers Bug Description: 389 to function in docker and other environments such as restore-from-backup, needs to be able to upgrade it's configuration on startup. This lets us ship-and-enable new features, upgrade plugins and more (similar to libglobs upgrades) Previously we had only basic machinery for this (IE make sure this entry exists like this) which would always write the content. This caused problems where plugins would re-enable on restart, or couldn't be removed. Fix Description: This adds an upgrade processor and an exists_or_add so that we can do stateful creates of entries, but without trampling user modifications IE disabling plugins. https://pagure.io/389-ds-base/issue/51177 fixes: #51177 Author: William Brown Review by: tbordaz, mreynolds (Thanks!) --- diff --git a/Makefile.am b/Makefile.am index 0c15072..2ccee17 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1544,6 +1544,7 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ ldap/servers/slapd/thread_data.c \ ldap/servers/slapd/uniqueid.c \ ldap/servers/slapd/uniqueidgen.c \ + ldap/servers/slapd/upgrade.c \ ldap/servers/slapd/utf8.c \ ldap/servers/slapd/utf8compare.c \ ldap/servers/slapd/util.c \ diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c index 52c64fa..0839d05 100644 --- a/ldap/servers/slapd/add.c +++ b/ldap/servers/slapd/add.c @@ -369,6 +369,72 @@ slapi_add_entry_internal_set_pb(Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl ** slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity); } +int +slapi_exists_or_add_internal( + Slapi_DN *dn, const char *filter, const char *entry, const char *modifier_name +) { + /* Search */ + Slapi_PBlock *search_pb = slapi_pblock_new(); + int search_result = 0; + int search_nentries = 0; + + slapi_search_internal_set_pb_ext(search_pb, + dn, + LDAP_SCOPE_BASE, + filter, + NULL, + 0, + NULL, + NULL, + NULL, + 0); + + slapi_search_internal_pb(search_pb); + + slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result); + if (search_result == LDAP_SUCCESS) { + slapi_pblock_get(search_pb, SLAPI_NENTRIES, &search_nentries); + } + slapi_pblock_destroy(search_pb); + + slapi_log_error(SLAPI_LOG_DEBUG, "slapi_exists_or_add_internal", "search_internal result -> %d, %d\n", search_result, search_nentries); + + if (search_result != LDAP_SUCCESS) { + return search_result; + } + + /* Did it exist? */ + if (search_nentries == 0) { + int create_result = 0; + /* begin the create */ + slapi_log_error(SLAPI_LOG_DEBUG, "slapi_exists_or_add_internal", "creating entry:\n%s\n", entry); + Slapi_Entry *s_entry = slapi_str2entry((char *)entry, 0); + + if (s_entry == NULL) { + slapi_log_error(SLAPI_LOG_ERR, "slapi_exists_or_add_internal", "failed to parse entry\n"); + return -1; + } + + /* Set modifiers name */ + slapi_entry_attr_set_charptr(s_entry, "internalModifiersname", modifier_name); + + /* do the add */ + Slapi_PBlock *add_pb = slapi_pblock_new(); + + slapi_add_entry_internal_set_pb(add_pb, s_entry, NULL, NULL, 0); + slapi_add_internal_pb(add_pb); + + slapi_pblock_get(add_pb, SLAPI_PLUGIN_INTOP_RESULT, &create_result); + slapi_pblock_destroy(add_pb); + + slapi_log_error(SLAPI_LOG_DEBUG, "slapi_exists_or_add_internal", "add_internal result -> %d\n", create_result); + + return create_result; + } + /* No action was taken */ + return LDAP_SUCCESS; +} + /* Helper functions */ static int diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c index 2af3f38..e3e97f3 100644 --- a/ldap/servers/slapd/dn.c +++ b/ldap/servers/slapd/dn.c @@ -2009,6 +2009,10 @@ slapi_sdn_new_dn_byval(const char *dn) return sdn; } +/* This is a much clearer name for what we want to achieve. */ +Slapi_DN * +slapi_sdn_new_from_char_dn(const char *dn) __attribute__((weak, alias("slapi_sdn_new_dn_byval"))); + Slapi_DN * slapi_sdn_new_ndn_byval(const char *ndn) { diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index ec4d863..ddefbad 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -60,6 +60,8 @@ union semun #include "fe.h" #include +#include + #ifdef LINUX /* For mallopt. Should be removed soon. */ #include @@ -1022,6 +1024,20 @@ main(int argc, char **argv) task_cleanup(); /* + * This step checks for any updates and changes on upgrade + * specifically, it manages assumptions about what plugins should exist, and their + * configurations, and potentially even the state of configurations on the server + * and their removal and deprecation. + * + * Has to be after uuid + dse to change config, but before password and plugins + * so we can adjust these configurations. + */ + if (upgrade_server() != UPGRADE_SUCCESS) { + return_value = 1; + goto cleanup; + } + + /* * Initialize password storage in entry extension. * Need to be initialized before plugin_startall in case stucked * changes are replicated as soon as the replication plugin is started. diff --git a/ldap/servers/slapd/pw_verify.c b/ldap/servers/slapd/pw_verify.c index 4ff1fa2..2615aa1 100644 --- a/ldap/servers/slapd/pw_verify.c +++ b/ldap/servers/slapd/pw_verify.c @@ -26,6 +26,10 @@ #include "slap.h" #include "fe.h" +#ifdef RUST_ENABLE +#include +#endif + int pw_verify_root_dn(const char *dn, const Slapi_Value *cred) { diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 7e5dfb9..1b2b65c 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -12,6 +12,8 @@ * See LICENSE for details. * END COPYRIGHT BLOCK **/ +#pragma once + #ifdef HAVE_CONFIG_H #include #endif @@ -2729,5 +2731,14 @@ extern char *attr_dataversion; #define _SEC_PER_DAY 86400 #define _MAX_SHADOW 99999 +/* + * SERVER UPGRADE INTERNALS + */ +typedef enum _upgrade_status { + UPGRADE_SUCCESS = 0, + UPGRADE_FAILURE = 1, +} upgrade_status; + +upgrade_status upgrade_server(void); #endif /* _slap_h_ */ diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 713aaee..fa79a49 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -2380,6 +2380,8 @@ Slapi_DN *slapi_sdn_new(void); */ Slapi_DN *slapi_sdn_new_dn_byval(const char *dn); +Slapi_DN *slapi_sdn_new_from_char_dn(const char *dn); + /** * Creates a new \c Slapi_DN structure and intializes it's normalized DN to a requested value. * diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h index e00f559..f356857 100644 --- a/ldap/servers/slapd/slapi-private.h +++ b/ldap/servers/slapd/slapi-private.h @@ -1,12 +1,15 @@ /** BEGIN COPYRIGHT BLOCK * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. * Copyright (C) 2005 Red Hat, Inc. + * Copyright (C) 2020 William Brown * All rights reserved. * * License: GPL (version 3 or any later version). * See LICENSE for details. * END COPYRIGHT BLOCK **/ +#pragma once + #ifdef HAVE_CONFIG_H #include #endif diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c new file mode 100644 index 0000000..47d608e --- /dev/null +++ b/ldap/servers/slapd/upgrade.c @@ -0,0 +1,81 @@ +/* BEGIN COPYRIGHT BLOCK + * Copyright (C) 2017 Red Hat, Inc. + * Copyright (C) 2020 William Brown + * All rights reserved. + * + * License: GPL (version 3 or any later version). + * See LICENSE for details. + * END COPYRIGHT BLOCK */ + +#include +#include + +/* + * This is called on server startup *before* plugins start + * but after config dse is read for operations. This allows + * us to make internal assertions about the state of the configuration + * at start up, enable plugins, and more. + * + * The functions in this file are named as: + * upgrade_xxx_yyy, where xxx is the minimum version of the project + * and yyy is the feature that is having it's configuration upgrade + * or altered. + */ + +static char *modifier_name = "cn=upgrade internal,cn=config"; + +static upgrade_status +upgrade_entry_exists_or_create(char *upgrade_id, char *filter, char *dn, char *entry) { + upgrade_status uresult = UPGRADE_SUCCESS; + char *dupentry = strdup(entry); + + Slapi_DN *base_sdn = slapi_sdn_new_from_char_dn(dn); + /* If not, create it. */ + int result = slapi_exists_or_add_internal(base_sdn, filter, dupentry, modifier_name); + + if (result != 0) { + slapi_log_error(SLAPI_LOG_FATAL, upgrade_id, "Failed to create entry: %"PRId32": %s\n", result); + uresult = UPGRADE_FAILURE; + } + slapi_ch_free_string(&dupentry); + slapi_sdn_free(&base_sdn); + return uresult; +} + +#ifdef RUST_ENABLE +static upgrade_status +upgrade_143_entryuuid_exists(void) { + char *entry = "dn: cn=entryuuid,cn=plugins,cn=config\n" + "objectclass: top\n" + "objectclass: nsSlapdPlugin\n" + "cn: entryuuid\n" + "nsslapd-pluginpath: libentryuuid-plugin\n" + "nsslapd-plugininitfunc: entryuuid_plugin_init\n" + "nsslapd-plugintype: betxnpreoperation\n" + "nsslapd-pluginenabled: on\n" + "nsslapd-pluginId: entryuuid\n" + "nsslapd-pluginVersion: none\n" + "nsslapd-pluginVendor: 389 Project\n" + "nsslapd-pluginDescription: entryuuid\n"; + + return upgrade_entry_exists_or_create( + "upgrade_143_entryuuid_exists", + "(cn=entryuuid)", + "cn=entryuuid,cn=plugins,cn=config", + entry + ); +} +#endif + +upgrade_status +upgrade_server(void) { +#ifdef RUST_ENABLE + if (upgrade_143_entryuuid_exists() != UPGRADE_SUCCESS) { + return UPGRADE_FAILURE; + } +#endif + + return UPGRADE_SUCCESS; +} + +