From 9f62d0c15795ca9fca0c64a8b4bd1b09540b47f1 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Feb 21 2014 09:26:02 +0000 Subject: Teach ipa-pwd-extop to respect global ipaUserAuthType settings https://fedorahosted.org/freeipa/ticket/4105 Reviewed-By: Alexander Bokovoy --- diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am index b8d9878..4cf80ec 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am @@ -40,6 +40,7 @@ plugindir = $(libdir)/dirsrv/plugins plugin_LTLIBRARIES = libipa_pwd_extop.la libipa_pwd_extop_la_LIBADD = $(builddir)/../libotp/libotp.la libipa_pwd_extop_la_SOURCES = \ + authcfg.c \ common.c \ encoding.c \ prepost.c \ diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c new file mode 100644 index 0000000..3ab5668 --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c @@ -0,0 +1,280 @@ +/** BEGIN COPYRIGHT BLOCK + * 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 . + * + * Additional permission under GPLv3 section 7: + * + * In the following paragraph, "GPL" means the GNU General Public + * License, version 3 or any later version, and "Non-GPL Code" means + * code that is governed neither by the GPL nor a license + * compatible with the GPL. + * + * You may link the code of this Program with Non-GPL Code and convey + * linked combinations including the two, provided that such Non-GPL + * Code only links to the code of this Program through those well + * defined interfaces identified in the file named EXCEPTION found in + * the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline + * functions from the Approved Interfaces without causing the resulting + * work to be covered by the GPL. Only the copyright holders of this + * Program may make changes or additions to the list of Approved + * Interfaces. + * + * Authors: + * Nathaniel McCallum + * + * Copyright (C) 2014 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include "authcfg.h" +#include "ipapwd.h" + +#include "pratom.h" + +static struct config { + struct config *next; + Slapi_DN *suffix; + uint32_t config; +} *config; + +static uint32_t string_to_config(const char *str) +{ + static const struct { + const char *string; + uint32_t config; + } map[] = { + { "disabled", AUTHCFG_AUTH_TYPE_DISABLED }, + { "password", AUTHCFG_AUTH_TYPE_PASSWORD }, + { "otp", AUTHCFG_AUTH_TYPE_OTP }, + { "pkinit", AUTHCFG_AUTH_TYPE_PKINIT }, + { "radius", AUTHCFG_AUTH_TYPE_RADIUS }, + {} + }; + + for (uint32_t i = 0; map[i].string != NULL; i++) { + if (strcasecmp(map[i].string, str) == 0) + return map[i].config; + } + + return AUTHCFG_AUTH_TYPE_NONE; +} + +static uint32_t entry_to_config(Slapi_Entry *e) +{ + char **auth_types = NULL; + + if (e == NULL) + return AUTHCFG_AUTH_TYPE_NONE; + + /* Fetch the auth type values from the config entry. */ + auth_types = slapi_entry_attr_get_charray(e, "ipaUserAuthType"); + if (auth_types == NULL) + return AUTHCFG_AUTH_TYPE_NONE; + + uint32_t types = AUTHCFG_AUTH_TYPE_NONE; + for (uint32_t i = 0; auth_types[i] != NULL; i++) + types |= string_to_config(auth_types[i]); + + slapi_ch_array_free(auth_types); + + return types; +} + +static Slapi_DN *suffix_to_config_dn(Slapi_DN *suffix) +{ + Slapi_DN *sdn = NULL; + char *dn = NULL; + + if (suffix == NULL) + return NULL; + + dn = PR_smprintf("cn=ipaConfig,cn=etc,%s", slapi_sdn_get_dn(suffix)); + if (dn == NULL) + return NULL; + + sdn = slapi_sdn_new_dn_byval(dn); + PR_smprintf_free(dn); + return sdn; +} + +static uint32_t suffix_to_config(Slapi_DN *suffix) +{ + static char *attrs[] = { "ipaUserAuthType", NULL }; + Slapi_Entry *entry = NULL; + Slapi_DN *sdn = NULL; + uint32_t types; + int ret; + + sdn = suffix_to_config_dn(suffix); + if (sdn == NULL) + return AUTHCFG_AUTH_TYPE_NONE; + + ret = slapi_search_internal_get_entry(sdn, attrs, &entry, + ipapwd_get_plugin_id()); + slapi_sdn_free(&sdn); + if (ret != LDAP_SUCCESS) + return AUTHCFG_AUTH_TYPE_NONE; + + types = entry_to_config(entry); + slapi_entry_free(entry); + + return types; +} + +static Slapi_DN *sdn_to_suffix(Slapi_DN *sdn) +{ + Slapi_DN *suffix = NULL; + void *node = NULL; + + if (sdn == NULL) + return NULL; + + for (suffix = slapi_get_first_suffix(&node, 0); suffix != NULL; + suffix = slapi_get_next_suffix(&node, 0)) { + if (slapi_sdn_issuffix(sdn, suffix)) + return suffix; + } + + return NULL; +} + +static bool sdn_is_config(Slapi_DN *sdn) +{ + Slapi_DN *sfx = NULL; + Slapi_DN *cfg = NULL; + int cmp; + + if (sdn == NULL) + return false; + + sfx = sdn_to_suffix(sdn); + if (sfx == NULL) + return false; + + cfg = suffix_to_config_dn(sfx); + if (cfg == NULL) + return false; + + cmp = slapi_sdn_compare(cfg, sdn); + slapi_sdn_free(&cfg); + return cmp == 0; +} + +void cache_free(struct config **cfg) +{ + if (cfg == NULL || *cfg == NULL) + return; + + cache_free(&(*cfg)->next); + free(*cfg); + *cfg = NULL; +} + +bool authcfg_init(void) +{ + struct config *cfg = NULL; + Slapi_DN *sfx = NULL; + void *node = NULL; + + /* If we are already initialized, return true. */ + if (config != NULL) + return true; + + /* Look up the config for each suffix. */ + for (sfx = slapi_get_first_suffix(&node, 0); sfx != NULL; + sfx = slapi_get_next_suffix(&node, 0)) { + cfg = calloc(1, sizeof(*cfg)); + if (cfg == NULL) { + authcfg_fini(); + return false; + } + + cfg->suffix = sfx; + cfg->config = suffix_to_config(sfx); + cfg->next = config; + config = cfg; + } + + return true; +} + +void authcfg_fini(void) +{ + cache_free(&config); +} + +uint32_t authcfg_get_auth_types(Slapi_Entry *user_entry) +{ + uint32_t glbl = AUTHCFG_AUTH_TYPE_NONE; + uint32_t user = AUTHCFG_AUTH_TYPE_NONE; + Slapi_DN *sfx = NULL; + Slapi_DN *sdn = NULL; + + /* Find the root suffix. */ + sdn = slapi_entry_get_sdn(user_entry); + sfx = sdn_to_suffix(sdn); + + /* Find the global config. */ + if (sfx != NULL) { + for (struct config *cfg = config; cfg && sfx; cfg = cfg->next) { + if (slapi_sdn_compare(sfx, cfg->suffix) == 0) { + glbl = PR_ATOMIC_ADD(&cfg->config, 0); + break; + } + } + } + + /* Global disabled overrides user settings. */ + if (glbl & AUTHCFG_AUTH_TYPE_DISABLED) + return AUTHCFG_AUTH_TYPE_DISABLED; + + /* Get the user's config. */ + user = entry_to_config(user_entry); + + if (user == AUTHCFG_AUTH_TYPE_NONE) { + if (glbl == AUTHCFG_AUTH_TYPE_NONE) + return AUTHCFG_AUTH_TYPE_PASSWORD; + return glbl; + } + + return user & ~AUTHCFG_AUTH_TYPE_DISABLED; +} + +void authcfg_reload_global_config(Slapi_DN *sdn, Slapi_Entry *config_entry) +{ + uint32_t glbl = AUTHCFG_AUTH_TYPE_NONE; + Slapi_DN *sfx = NULL; + Slapi_DN *dest; + + /* Get the destination DN. */ + dest = config_entry == NULL ? NULL : slapi_entry_get_sdn(config_entry); + + /* Added, modified, moved into place. */ + if (sdn_is_config(dest)) { + sfx = sdn_to_suffix(dest); + glbl = entry_to_config(config_entry); + + /* Deleted, moved out of place. */ + } else if (sdn_is_config(sdn)) { + sfx = sdn_to_suffix(sdn); + } + + /* Reload config. */ + for (struct config *cfg = config; cfg && sfx; cfg = cfg->next) { + if (slapi_sdn_compare(sfx, cfg->suffix) == 0) { + PR_ATOMIC_SET(&cfg->config, glbl); + break; + } + } +} diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h new file mode 100644 index 0000000..c2fc246 --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h @@ -0,0 +1,82 @@ +/** BEGIN COPYRIGHT BLOCK + * 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 . + * + * Additional permission under GPLv3 section 7: + * + * In the following paragraph, "GPL" means the GNU General Public + * License, version 3 or any later version, and "Non-GPL Code" means + * code that is governed neither by the GPL nor a license + * compatible with the GPL. + * + * You may link the code of this Program with Non-GPL Code and convey + * linked combinations including the two, provided that such Non-GPL + * Code only links to the code of this Program through those well + * defined interfaces identified in the file named EXCEPTION found in + * the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline + * functions from the Approved Interfaces without causing the resulting + * work to be covered by the GPL. Only the copyright holders of this + * Program may make changes or additions to the list of Approved + * Interfaces. + * + * Authors: + * Nathaniel McCallum + * + * Copyright (C) 2014 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + + +#ifndef AUTHCFG_H_ +#define AUTHCFG_H_ + +#include +#include + +#define AUTHCFG_AUTH_TYPE_NONE 0 +#define AUTHCFG_AUTH_TYPE_DISABLED 1 +#define AUTHCFG_AUTH_TYPE_PASSWORD 2 +#define AUTHCFG_AUTH_TYPE_OTP 4 +#define AUTHCFG_AUTH_TYPE_PKINIT 8 +#define AUTHCFG_AUTH_TYPE_RADIUS 16 + +/* Initialize authentication configuration. + * + * Thread Safety: NO + */ +bool authcfg_init(void); + +/* Free global authentication configuration resources. + * + * Thread Safety: NO + */ +void authcfg_fini(void); + +/* Gets the permitted authentication types for the given user entry. + * + * The entry should be queried for the "ipaUserAuthType" attribute. + * + * Thread Safety: YES + */ +uint32_t authcfg_get_auth_types(Slapi_Entry *user_entry); + +/* Reloads configuration from the specified global config entry. + * + * If the provided entry isn't a global config entry, this is a no-op. + * + * Thread Safety: YES + */ +void authcfg_reload_global_config(Slapi_DN *sdn, Slapi_Entry *config_entry); + +#endif /* AUTHCFG_H_ */ diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c index ef20c4c..1a8ef47 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c @@ -70,133 +70,6 @@ static const char *ipapwd_def_encsalts[] = { NULL }; -static PRInt32 g_allowed_auth_types = 0; - -/* - * Checks if an authentication type is allowed. A NULL terminated - * list of allowed auth type values is passed in along with the flag - * for the auth type you are inquiring about. If auth_type_list is - * NULL, the global config will be consulted. - */ -bool ipapwd_is_auth_type_allowed(char **auth_type_list, int auth_type) -{ - char *auth_type_value = NULL; - int i = 0; - - /* Get the string value for the authentication type we are checking for. */ - switch (auth_type) { - case IPA_OTP_AUTH_TYPE_OTP: - auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_OTP; - break; - case IPA_OTP_AUTH_TYPE_PASSWORD: - auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_PASSWORD; - break; - case IPA_OTP_AUTH_TYPE_PKINIT: - auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_PKINIT; - break; - default: /* Unknown type.*/ - return false; - } - - if (auth_type_list == NULL) { - /* Check if the requested authentication type is in the global list. */ - PRInt32 auth_type_flags; - - /* Do an atomic read of the allowed auth types bit field. */ - auth_type_flags = PR_ATOMIC_ADD(&g_allowed_auth_types, 0); - - /* Check if the flag for the desired auth type is set. */ - return auth_type_flags & auth_type; - } - - /* Check if the requested authentication type is in the user list. */ - for (i = 0; auth_type_list[i]; i++) { - if (strcasecmp(auth_type_list[i], auth_type_value) == 0) { - return true; - } - } - - return false; -} - -/* - * Parses and validates an OTP config entry. If apply is non-zero, then - * we will load and start using the new config. You can simply - * validate config without making any changes by setting apply to false. - */ -bool ipapwd_parse_otp_config_entry(Slapi_Entry * e, bool apply) -{ - PRInt32 allowed_auth_types = 0; - PRInt32 default_auth_types = 0; - char **auth_types = NULL; - - /* If no auth types are set, we default to only allowing password - * authentication. Other authentication types can be allowed at the - * user level. */ - default_auth_types |= IPA_OTP_AUTH_TYPE_PASSWORD; - - if (e == NULL) { - /* There is no config entry, so just set the defaults. */ - allowed_auth_types = default_auth_types; - goto done; - } - - /* Parse and validate the config entry. We currently tolerate invalid - * config settings, so there is no real validation performed. We will - * likely want to reject invalid config as we expand the plug-in - * functionality, so the validation logic is here for us to use later. */ - - /* Fetch the auth type values from the config entry. */ - auth_types = slapi_entry_attr_get_charray(e, IPA_OTP_USER_AUTH_TYPE); - if (auth_types == NULL) { - /* No allowed auth types are specified, so set the defaults. */ - allowed_auth_types = default_auth_types; - goto done; - } - - /* Check each type to see if it is set. */ - if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_DISABLED)) { - allowed_auth_types |= IPA_OTP_AUTH_TYPE_DISABLED; - } - - if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_PASSWORD)) { - allowed_auth_types |= IPA_OTP_AUTH_TYPE_PASSWORD; - } - - if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_OTP)) { - allowed_auth_types |= IPA_OTP_AUTH_TYPE_OTP; - } - - if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_PKINIT)) { - allowed_auth_types |= IPA_OTP_AUTH_TYPE_PKINIT; - } - - if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_RADIUS)) { - allowed_auth_types |= IPA_OTP_AUTH_TYPE_RADIUS; - } - - slapi_ch_array_free(auth_types); - -done: - if (apply) { - /* Atomically set the global allowed types. */ - PR_ATOMIC_SET(&g_allowed_auth_types, allowed_auth_types); - } - - return true; -} - -bool ipapwd_otp_is_disabled(void) -{ - PRInt32 auth_type_flags; - - /* Do an atomic read of the allowed auth types bit field. */ - auth_type_flags = PR_ATOMIC_ADD(&g_allowed_auth_types, 0); - - /* Check if the disabled bit is set. */ - return auth_type_flags & IPA_OTP_AUTH_TYPE_DISABLED; -} - static struct ipapwd_krbcfg *ipapwd_getConfig(void) { krb5_error_code krberr; diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c index 688d699..d8af391 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c @@ -39,6 +39,7 @@ #include "ipapwd.h" #include "util.h" +#include "authcfg.h" /* * Password Modify - LDAP Extended Operation. @@ -87,30 +88,11 @@ Slapi_PluginDesc ipapwd_plugin_desc = { void *ipapwd_plugin_id; static int usetxn = 0; -static Slapi_DN *_ConfigAreaDN = NULL; -static Slapi_DN *_PluginDN = NULL; -static bool g_plugin_started = false; - void *ipapwd_get_plugin_id(void) { return ipapwd_plugin_id; } -Slapi_DN *ipapwd_get_otp_config_area(void) -{ - return _ConfigAreaDN; -} - -Slapi_DN *ipapwd_get_plugin_sdn(void) -{ - return _PluginDN; -} - -bool ipapwd_get_plugin_started(void) -{ - return g_plugin_started; -} - static int filter_keys(struct ipapwd_krbcfg *krbcfg, struct ipapwd_keyset *kset) { @@ -1222,40 +1204,6 @@ Slapi_Filter *ipapwd_string2filter(char *strfilter) return ret; } -/* Loads the OTP config entry, parses it, and applies it. */ -static bool ipapwd_load_otp_config(void) -{ - char *config_attrs[] = { IPA_USER_AUTH_TYPE, NULL }; - Slapi_Entry *config_entry = NULL; - Slapi_DN *config_sdn = NULL; - int ret; - - /* If we are using an alternate config area, check it for our - * configuration, otherwise we just use our main plug-in config - * entry. */ - if ((config_sdn = ipapwd_get_otp_config_area()) == NULL) { - config_sdn = ipapwd_get_plugin_sdn(); - } - - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "Looking for config settings in \"%s\".\n", - config_sdn ? slapi_sdn_get_ndn(config_sdn) : "null"); - - /* Fetch the config entry. */ - ret = slapi_search_internal_get_entry(config_sdn, config_attrs, - &config_entry, ipapwd_plugin_id); - if (ret != LDAP_SUCCESS) { - LOG_TRACE("Search for OTP config failed, err (%d)\n", ret); - /* fall through, defaults will be set */ - } - - /* Parse and apply the config. */ - ipapwd_parse_otp_config_entry(config_entry, true); - - slapi_entry_free(config_entry); - return true; -} - /* Init data structs */ static int ipapwd_start( Slapi_PBlock *pb ) { @@ -1264,35 +1212,16 @@ static int ipapwd_start( Slapi_PBlock *pb ) char *realm = NULL; char *config_dn; Slapi_Entry *config_entry = NULL; - Slapi_DN *plugindn = NULL; - char *config_area = NULL; int ret; - /* Check if we're already started */ - if (g_plugin_started) { - return LDAP_SUCCESS; - } - - /* Get the plug-in target dn from the system and store for future use. */ - slapi_pblock_get(pb, SLAPI_TARGET_SDN, &plugindn); - if (plugindn == NULL || slapi_sdn_get_ndn_len(plugindn) == 0) { - LOG_FATAL("No plugin dn?\n"); - return LDAP_OPERATIONS_ERROR; - } - _PluginDN = slapi_sdn_dup(plugindn); - - /* Set the alternate config area if one is defined. */ - slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area); - if (config_area != NULL) { - _ConfigAreaDN = slapi_sdn_new_normdn_byval(config_area); - } - - /* - * Load the config. + /* NOTE: We never call authcfg_fini() from a destructor. This is because + * it may race with threaded requests at shutdown. This leak should + * only occur when the DS is exiting, so it isn't a big deal. */ - if (!ipapwd_load_otp_config()) { - LOG_FATAL("Unable to load plug-in config\n"); - return LDAP_OPERATIONS_ERROR; + if (!authcfg_init()) { + LOG_FATAL("AuthConf initialization failed!\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; } krberr = krb5_init_context(&krbctx); @@ -1363,35 +1292,15 @@ static int ipapwd_start( Slapi_PBlock *pb ) } ret = LDAP_SUCCESS; - g_plugin_started = true; done: free(realm); krb5_free_context(krbctx); if (config_entry) slapi_entry_free(config_entry); + if (ret != LDAP_SUCCESS) authcfg_fini(); return ret; } -/* Clean up any resources allocated at startup. */ -static int ipapwd_close(Slapi_PBlock * pb) -{ - if (!g_plugin_started) { - goto done; - } - - g_plugin_started = false; - - /* We are not guaranteed that other threads are finished accessing - * PluginDN or ConfigAreaDN, so we don't want to free them. This is - * only a one-time leak at shutdown, so it should be fine. - * slapi_sdn_free(&_PluginDN); - * slapi_sdn_free(&_ConfigAreaDN); - */ - -done: - return 0; -} - static char *ipapwd_oid_list[] = { EXOP_PASSWD_OID, KEYTAB_SET_OID, @@ -1443,7 +1352,6 @@ int ipapwd_init( Slapi_PBlock *pb ) if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, ipapwd_oid_list); if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, ipapwd_name_list); if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)ipapwd_extop); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)ipapwd_close); if (ret) { LOG("Failed to set plug-in version, function, and OID.\n" ); return -1; diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h index 1ef3627..e18bf7b 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h @@ -76,30 +76,6 @@ #define IPA_CHANGETYPE_ADMIN 1 #define IPA_CHANGETYPE_DSMGR 2 -/* - * Attribute type defines - */ -#define IPA_USER_AUTH_TYPE "ipaUserAuthType" -#define IPA_OTP_TOKEN_OWNER_TYPE "ipaTokenOwner" -#define IPA_OTP_TOKEN_LENGTH_TYPE "ipaTokenOTPDigits" -#define IPA_OTP_TOKEN_KEY_TYPE "ipaTokenOTPKey" -#define IPA_OTP_TOKEN_ALGORITHM_TYPE "ipaTokenOTPAlgorithm" -#define IPA_OTP_TOKEN_OFFSET_TYPE "ipaTokenTOTPClockOffset" -#define IPA_OTP_TOKEN_STEP_TYPE "ipaTokenTOTPTimeStep" - -/* Authentication type defines */ -#define IPA_OTP_AUTH_TYPE_NONE 0 -#define IPA_OTP_AUTH_TYPE_DISABLED 1 -#define IPA_OTP_AUTH_TYPE_PASSWORD 2 -#define IPA_OTP_AUTH_TYPE_OTP 4 -#define IPA_OTP_AUTH_TYPE_PKINIT 8 -#define IPA_OTP_AUTH_TYPE_RADIUS 16 -#define IPA_OTP_AUTH_TYPE_VALUE_DISABLED "DISABLED" -#define IPA_OTP_AUTH_TYPE_VALUE_PASSWORD "PASSWORD" -#define IPA_OTP_AUTH_TYPE_VALUE_OTP "OTP" -#define IPA_OTP_AUTH_TYPE_VALUE_PKINIT "PKINIT" -#define IPA_OTP_AUTH_TYPE_VALUE_RADIUS "RADIUS" - struct ipapwd_data { Slapi_Entry *target; char *dn; @@ -135,9 +111,6 @@ struct ipapwd_krbcfg { bool allow_nt_hash; }; -bool ipapwd_is_auth_type_allowed(char **auth_type_list, int auth_type); -bool ipapwd_parse_otp_config_entry(Slapi_Entry * e, bool apply); -bool ipapwd_otp_is_disabled(void); int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e, int *is_root, int *is_krb, int *is_smb, int *is_ipant, char *attr, int access); @@ -184,6 +157,3 @@ int ipapwd_post_init_betxn(Slapi_PBlock *pb); /* from ipa_pwd_extop.c */ void *ipapwd_get_plugin_id(void); -Slapi_DN *ipapwd_get_otp_config_area(void); -Slapi_DN *ipapwd_get_plugin_sdn(void); -bool ipapwd_get_plugin_started(void); diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c index 850cdeb..c6e7509 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c @@ -63,6 +63,7 @@ #include "ipapwd.h" #include "util.h" #include "syncreq.h" +#include "authcfg.h" #define IPAPWD_OP_NULL 0 #define IPAPWD_OP_ADD 1 @@ -966,73 +967,23 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods, return ret; } -/* - * Check if we want to process this operation. We need to be - * sure that the operation succeeded. - */ -static bool ipapwd_otp_oktodo(Slapi_PBlock *pb) -{ - bool ok = false; - int oprc = 0; - int ret = 1; - - ret = slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc); - if (ret != 0) { - LOG_FATAL("Could not get parameters\n"); - goto done; - } - - /* This plugin should only execute if the operation succeeded. */ - ok = oprc == 0; - -done: - return ok; -} - -static bool ipapwd_dn_is_otp_config(Slapi_DN *sdn) -{ - bool ret = false; - Slapi_DN *dn; - - /* If an alternate config area is configured, it is considered to be - * the config entry, otherwise the main plug-in config entry is used. */ - if (sdn != NULL) { - dn = ipapwd_get_otp_config_area(); - if (dn == NULL) - dn = ipapwd_get_plugin_sdn(); - - ret = slapi_sdn_compare(sdn, dn) == 0; - } - - return ret; -} - -static int ipapwd_post_modadd_otp(Slapi_PBlock *pb) +static int ipapwd_post_authcfg(Slapi_PBlock *pb) { Slapi_Entry *config_entry = NULL; Slapi_DN *sdn = NULL; + int oprc = 0; - /* Just bail if we are not started yet, or if the operation failed. */ - if (!ipapwd_get_plugin_started() || !ipapwd_otp_oktodo(pb)) { - goto done; - } + /* Just bail if the operation failed. */ + if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0) + return 0; - /* Check if a change affected our config entry and reload the - * in-memory config settings if needed. */ - slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); - if (ipapwd_dn_is_otp_config(sdn)) { - /* The config entry was added or modified, so reload it from - * the post-op entry. */ - slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &config_entry); - if (config_entry == NULL) { - LOG_FATAL("Unable to retrieve config entry.\n"); - goto done; - } + if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn) != 0) + return 0; - ipapwd_parse_otp_config_entry(config_entry, true); - } + /* Ignore the error here (delete operations). */ + slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &config_entry); -done: + authcfg_reload_global_config(sdn, config_entry); return 0; } @@ -1052,10 +1003,8 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb) LOG_TRACE("=>\n"); - ret = ipapwd_post_modadd_otp(pb); - if (ret != 0) { - return ret; - } + /* Ignore error when parsing configuration. */ + ipapwd_post_authcfg(pb); /* time to get the operation handler */ ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op); @@ -1177,70 +1126,6 @@ done: return 0; } -static int ipapwd_post_modrdn_otp(Slapi_PBlock *pb) -{ - Slapi_Entry *config_entry = NULL; - Slapi_DN *new_sdn = NULL; - Slapi_DN *sdn = NULL; - - /* Just bail if we are not started yet, or if the operation failed. */ - if (!ipapwd_get_plugin_started() || !ipapwd_otp_oktodo(pb)) { - goto done; - } - - /* Check if a change affected our config entry and reload the - * in-memory config settings if needed. */ - slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); - if (ipapwd_dn_is_otp_config(sdn)) { - /* Our config entry was renamed. We treat this like the entry - * was deleted, so just set the defaults. */ - ipapwd_parse_otp_config_entry(NULL, true); - } else { - /* Check if an entry was renamed such that it has become our - * config entry. If so, reload the config from this new entry. */ - slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &config_entry); - if (config_entry == NULL) { - LOG_FATAL("Unable to retrieve renamed entry.\n"); - goto done; - } - - new_sdn = slapi_entry_get_sdn(config_entry); - if (new_sdn == NULL) { - LOG_FATAL("Unable to retrieve DN of renamed entry.\n"); - goto done; - } - - if (ipapwd_dn_is_otp_config(new_sdn)) { - ipapwd_parse_otp_config_entry(config_entry, true); - } - } - -done: - return 0; -} - -static int ipapwd_post_del_otp(Slapi_PBlock *pb) -{ - Slapi_DN *sdn = NULL; - int ret = 0; - - /* Just bail if we are not started yet, or if the operation failed. */ - if (!ipapwd_get_plugin_started() || !ipapwd_otp_oktodo(pb)) { - goto done; - } - - /* Check if a change affected our config entry and reload the - * in-memory config settings if needed. */ - slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); - if (ipapwd_dn_is_otp_config(sdn)) { - /* The config entry was deleted, so this just sets the defaults. */ - ipapwd_parse_otp_config_entry(NULL, true); - } - -done: - return ret; -} - /* * Authenticates creds against OTP tokens. Returns true when authentication * completed successfully against a token OR when a user has no active tokens. @@ -1302,16 +1187,13 @@ static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry, static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry, struct berval *creds) { - char **auth_types = NULL; - bool otpauth; - bool pwdauth; + uint32_t auth_types; - /* If we didn't start successfully, bail. */ - if (!ipapwd_get_plugin_started()) - return true; + /* Get the configured authentication types. */ + auth_types = authcfg_get_auth_types(entry); /* If global disabled flag is set, just punt. */ - if (ipapwd_otp_is_disabled()) + if (auth_types & AUTHCFG_AUTH_TYPE_DISABLED) return true; /* @@ -1323,19 +1205,15 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry, * 1. If OTP is enabled, validate OTP. * 2. If PWD is enabled or OTP succeeded, fall through to PWD validation. */ - auth_types = slapi_entry_attr_get_charray(entry, IPA_USER_AUTH_TYPE); - otpauth = ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_OTP); - pwdauth = ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_PASSWORD); - slapi_ch_array_free(auth_types); - if (otpauth) { + if (auth_types & AUTHCFG_AUTH_TYPE_OTP) { LOG_PLUGIN_NAME(IPAPWD_PLUGIN_NAME, "Attempting OTP authentication for '%s'.\n", bind_dn); if (ipapwd_do_otp_auth(bind_dn, entry, creds)) return true; } - return pwdauth; + return auth_types & AUTHCFG_AUTH_TYPE_PASSWORD; } static int ipapwd_authenticate(const char *dn, Slapi_Entry *entry, @@ -1501,7 +1379,7 @@ done: static int ipapwd_pre_bind(Slapi_PBlock *pb) { static const char *attrs_list[] = { - SLAPI_USERPWD_ATTR, IPA_USER_AUTH_TYPE, "krbprincipalkey", "uid", + SLAPI_USERPWD_ATTR, "ipaUserAuthType", "krbprincipalkey", "uid", "krbprincipalname", "objectclass", "passwordexpirationtime", "passwordhistory", NULL @@ -1599,9 +1477,9 @@ int ipapwd_post_init(Slapi_PBlock *pb) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *)ipapwd_post_modadd); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_del_otp); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_authcfg); if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *)ipapwd_post_modadd); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_modrdn_otp); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_authcfg); return ret; } @@ -1612,10 +1490,10 @@ int ipapwd_intpost_init(Slapi_PBlock *pb) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03); if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_modadd_otp); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_del_otp); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_modadd_otp); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_modrdn_otp); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_authcfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_authcfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_authcfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_authcfg); return ret; }