From 953c6846b7cb8d75253538ab92a1360fceee0c3c Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Mon, 10 Nov 2014 22:46:44 -0500 Subject: Move authentication configuration cache into libotp This enables plugins to share authentication configuration cache code. Additionally, update the caching mechanism to be declarative and faster. Reviewed-By: Thierry Bordaz --- .../ipa-slapi-plugins/ipa-pwd-extop/Makefile.am | 1 - daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c | 280 --------------------- daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h | 82 ------ .../ipa-pwd-extop/ipa_pwd_extop.c | 21 +- daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 50 ++-- daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c | 4 +- daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h | 4 +- daemons/ipa-slapi-plugins/libotp/Makefile.am | 2 +- daemons/ipa-slapi-plugins/libotp/otp_config.c | 274 ++++++++++++++++++++ daemons/ipa-slapi-plugins/libotp/otp_config.h | 65 +++++ daemons/ipa-slapi-plugins/libotp/otp_token.c | 58 ++--- daemons/ipa-slapi-plugins/libotp/otp_token.h | 11 +- 12 files changed, 395 insertions(+), 457 deletions(-) delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_config.c create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_config.h (limited to 'daemons') diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am index eeb352611..1ab6c6704 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am @@ -44,7 +44,6 @@ libipa_pwd_extop_la_LIBADD = \ $(ASN1_UTIL_DIR)/libipaasn1.la \ $(NULL) 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 deleted file mode 100644 index 3ab5668ed..000000000 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c +++ /dev/null @@ -1,280 +0,0 @@ -/** 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 deleted file mode 100644 index c2fc24605..000000000 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h +++ /dev/null @@ -1,82 +0,0 @@ -/** 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/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c index ceea49cab..09c877f70 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,7 +39,7 @@ #include "ipapwd.h" #include "util.h" -#include "authcfg.h" +#include "../libotp/otp_config.h" #include "ipa_asn1.h" /* @@ -89,6 +89,8 @@ Slapi_PluginDesc ipapwd_plugin_desc = { void *ipapwd_plugin_id; static int usetxn = 0; +extern struct otp_config *otp_config; + void *ipapwd_get_plugin_id(void) { return ipapwd_plugin_id; @@ -1792,16 +1794,6 @@ static int ipapwd_start( Slapi_PBlock *pb ) Slapi_Entry *config_entry = NULL; int ret; - /* 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 (!authcfg_init()) { - LOG_FATAL("AuthConf initialization failed!\n"); - ret = LDAP_OPERATIONS_ERROR; - goto done; - } - krberr = krb5_init_context(&krbctx); if (krberr) { LOG_FATAL("krb5_init_context failed\n"); @@ -1871,11 +1863,16 @@ static int ipapwd_start( Slapi_PBlock *pb ) ret = LDAP_SUCCESS; + /* NOTE: We never call otp_config_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. + */ + otp_config = otp_config_init(ipapwd_plugin_id); + done: free(realm); krb5_free_context(krbctx); if (config_entry) slapi_entry_free(config_entry); - if (ret != LDAP_SUCCESS) authcfg_fini(); return ret; } diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c index 1dff6db1a..96c55f39b 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c @@ -63,7 +63,6 @@ #include "ipapwd.h" #include "util.h" #include "syncreq.h" -#include "authcfg.h" #define IPAPWD_OP_NULL 0 #define IPAPWD_OP_ADD 1 @@ -75,6 +74,8 @@ extern Slapi_PluginDesc ipapwd_plugin_desc; extern void *ipapwd_plugin_id; extern const char *ipa_realm_tree; +struct otp_config *otp_config = NULL; + /* structure with information for each extension */ struct ipapwd_op_ext { char *object_name; /* name of the object extended */ @@ -967,23 +968,9 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods, return ret; } -static int ipapwd_post_authcfg(Slapi_PBlock *pb) +static int ipapwd_post_updatecfg(Slapi_PBlock *pb) { - Slapi_Entry *config_entry = NULL; - Slapi_DN *sdn = NULL; - int oprc = 0; - - /* Just bail if the operation failed. */ - if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0) - return 0; - - if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn) != 0) - return 0; - - /* Ignore the error here (delete operations). */ - slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &config_entry); - - authcfg_reload_global_config(sdn, config_entry); + otp_config_update(otp_config, pb); return 0; } @@ -1003,8 +990,7 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb) LOG_TRACE("=>\n"); - /* Ignore error when parsing configuration. */ - ipapwd_post_authcfg(pb); + otp_config_update(otp_config, pb); /* time to get the operation handler */ ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op); @@ -1144,7 +1130,7 @@ static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry, bool success = false; /* Find all of the user's active tokens. */ - tokens = otp_token_find(ipapwd_plugin_id, dn, NULL, true, NULL); + tokens = otp_token_find(otp_config, dn, NULL, true, NULL); if (tokens == NULL) { slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME, "%s: can't find tokens for '%s'.\n", __func__, dn); @@ -1190,11 +1176,7 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry, uint32_t auth_types; /* Get the configured authentication types. */ - auth_types = authcfg_get_auth_types(entry); - - /* If global disabled flag is set, just punt. */ - if (auth_types & AUTHCFG_AUTH_TYPE_DISABLED) - return true; + auth_types = otp_config_auth_types(otp_config, entry); /* * IMPORTANT SECTION! @@ -1206,14 +1188,14 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry, * 2. If PWD is enabled or OTP succeeded, fall through to PWD validation. */ - if (auth_types & AUTHCFG_AUTH_TYPE_OTP) { + if (auth_types & OTP_CONFIG_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 auth_types & AUTHCFG_AUTH_TYPE_PASSWORD; + return auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD; } static int ipapwd_authenticate(const char *dn, Slapi_Entry *entry, @@ -1461,7 +1443,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) } /* Attempt to handle a token synchronization request. */ - if (syncreq && !sync_request_handle(ipapwd_get_plugin_id(), pb, dn)) + if (syncreq && !sync_request_handle(otp_config, pb, dn)) goto invalid_creds; /* Attempt to write out kerberos keys for the user. */ @@ -1513,9 +1495,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_authcfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_updatecfg); 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_authcfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg); return ret; } @@ -1526,10 +1508,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_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); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_updatecfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_updatecfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_updatecfg); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg); return ret; } diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c index 10c49b724..0aef43802 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c @@ -52,7 +52,7 @@ bool sync_request_present(Slapi_PBlock *pb) return ldap_control_find(OTP_SYNC_REQUEST_OID, controls, NULL) != NULL; } -bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, +bool sync_request_handle(const struct otp_config *cfg, Slapi_PBlock *pb, const char *user_dn) { struct otp_token **tokens = NULL; @@ -90,7 +90,7 @@ bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, /* Process the synchronization. */ success = false; if (ber_scanf(ber, "}") != LBER_ERROR) { - tokens = otp_token_find(plugin_id, user_dn, token_dn, true, NULL); + tokens = otp_token_find(cfg, user_dn, token_dn, true, NULL); if (tokens != NULL) { success = otp_token_sync_berval(tokens, OTP_SYNC_MAX_STEPS, first, second); otp_token_free_array(tokens); diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h index 34235901b..98a97c4c9 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h @@ -41,7 +41,7 @@ #ifndef SYNCREQ_H_ #define SYNCREQ_H_ -#include +#include "../libotp/otp_config.h" #include /* @@ -57,7 +57,7 @@ bool sync_request_present(Slapi_PBlock *pb); -bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, +bool sync_request_handle(const struct otp_config *cfg, Slapi_PBlock *pb, const char *user_dn); #endif /* SYNCREQ_H_ */ diff --git a/daemons/ipa-slapi-plugins/libotp/Makefile.am b/daemons/ipa-slapi-plugins/libotp/Makefile.am index 012c83391..4428f6bdc 100644 --- a/daemons/ipa-slapi-plugins/libotp/Makefile.am +++ b/daemons/ipa-slapi-plugins/libotp/Makefile.am @@ -3,7 +3,7 @@ AM_CPPFLAGS = -I/usr/include/dirsrv noinst_LTLIBRARIES = libhotp.la libotp.la libhotp_la_SOURCES = hotp.c hotp.h -libotp_la_SOURCES = otp_token.c otp_token.h +libotp_la_SOURCES = otp_config.c otp_config.h otp_token.c otp_token.h libotp_la_LIBADD = libhotp.la check_PROGRAMS = t_hotp diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.c b/daemons/ipa-slapi-plugins/libotp/otp_config.c new file mode 100644 index 000000000..1b7c1e658 --- /dev/null +++ b/daemons/ipa-slapi-plugins/libotp/otp_config.c @@ -0,0 +1,274 @@ +/** 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 "otp_config.h" + +#include +#include + +#define OTP_CONFIG_AUTH_TYPE_DISABLED (1 << 31) + +struct spec { + uint32_t (*func)(Slapi_Entry *, const char *attr); + const char *prefix; + const char *attr; + uint32_t dflt; +}; + +struct record { + struct record *next; + const struct spec *spec; + Slapi_DN *sdn; + uint32_t value; +}; + +struct otp_config { + Slapi_ComponentId *plugin_id; + struct record *records; +}; + +static uint32_t string_to_types(const char *str) +{ + static const struct { + const char *string; + uint32_t config; + } map[] = { + { "disabled", OTP_CONFIG_AUTH_TYPE_DISABLED }, + { "password", OTP_CONFIG_AUTH_TYPE_PASSWORD }, + { "otp", OTP_CONFIG_AUTH_TYPE_OTP }, + { "pkinit", OTP_CONFIG_AUTH_TYPE_PKINIT }, + { "radius", OTP_CONFIG_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 OTP_CONFIG_AUTH_TYPE_NONE; +} + +static uint32_t entry_to_authtypes(Slapi_Entry *e, const char *attr) +{ + char **auth_types = NULL; + + if (e == NULL) + return OTP_CONFIG_AUTH_TYPE_NONE; + + /* Fetch the auth type values from the config entry. */ + auth_types = slapi_entry_attr_get_charray(e, attr); + if (auth_types == NULL) + return OTP_CONFIG_AUTH_TYPE_NONE; + + uint32_t types = OTP_CONFIG_AUTH_TYPE_NONE; + for (uint32_t i = 0; auth_types[i] != NULL; i++) + types |= string_to_types(auth_types[i]); + + slapi_ch_array_free(auth_types); + return types; +} + +static const struct spec authtypes = { + entry_to_authtypes, + "cn=ipaConfig,cn=etc,%s", + "ipaUserAuthType", + OTP_CONFIG_AUTH_TYPE_PASSWORD +}; + +static Slapi_DN *make_sdn(const char *prefix, const Slapi_DN *suffix) +{ + char *dn = slapi_ch_smprintf(prefix, slapi_sdn_get_dn(suffix)); + return slapi_sdn_new_dn_passin(dn); +} + +static uint32_t find_value(const struct otp_config *cfg, + const Slapi_DN *suffix, const struct spec *spec) +{ + uint32_t value = 0; + Slapi_DN *sdn; + + sdn = make_sdn(spec->prefix, suffix); + for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) { + if (rec->spec == spec) { + value = PR_ATOMIC_ADD(&rec->value, 0); + break; + } + } + + slapi_sdn_free(&sdn); + return value; +} + +static void update(const struct otp_config *cfg, Slapi_DN *src, + Slapi_Entry *entry) +{ + Slapi_DN *dst = entry == NULL ? NULL : slapi_entry_get_sdn(entry); + + for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) { + uint32_t val = rec->spec->dflt; + + /* If added, modified or moved into place... */ + if (dst != NULL && slapi_sdn_compare(rec->sdn, dst) == 0) { + Slapi_Attr *attr = NULL; + if (slapi_entry_attr_find(entry, rec->spec->attr, &attr) == 0) + val = rec->spec->func(entry, rec->spec->attr); + + /* If NOT deleted or moved out of place... */ + } else if (slapi_sdn_compare(rec->sdn, src) != 0) + continue; + + PR_ATOMIC_SET(&rec->value, val); + } +} + +struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id) +{ + static const struct spec *specs[] = { + &authtypes, + NULL + }; + + struct otp_config *cfg = NULL; + void *node = NULL; + + cfg = (typeof(cfg)) slapi_ch_calloc(1, sizeof(*cfg)); + cfg->plugin_id = plugin_id; + + /* Build the config table. */ + for (Slapi_DN *sfx = slapi_get_first_suffix(&node, 0); + sfx != NULL; + sfx = slapi_get_next_suffix(&node, 0)) { + for (size_t i = 0; specs[i] != NULL; i++) { + Slapi_Entry *entry = NULL; + struct record *rec; + + /* Create the config entry. */ + rec = (typeof(rec)) slapi_ch_calloc(1, sizeof(*rec)); + rec->spec = specs[i]; + rec->sdn = make_sdn(rec->spec->prefix, sfx); + + /* Add config to the list. */ + rec->next = cfg->records; + cfg->records = rec; + + /* Load the specified entry. */ + slapi_search_internal_get_entry(rec->sdn, NULL, &entry, plugin_id); + update(cfg, rec->sdn, entry); + slapi_entry_free(entry); + } + } + + return cfg; +} + +static void record_fini(struct record **rec) +{ + if (rec == NULL || *rec == NULL) + return; + + record_fini(&(*rec)->next); + slapi_sdn_free(&(*rec)->sdn); + slapi_ch_free((void **) rec); +} + +void otp_config_fini(struct otp_config **cfg) +{ + if (cfg == NULL || *cfg == NULL) + return; + + record_fini(&(*cfg)->records); + slapi_ch_free((void **) cfg); +} + +void otp_config_update(struct otp_config *cfg, Slapi_PBlock *pb) +{ + Slapi_Entry *entry = NULL; + Slapi_DN *src = NULL; + int oprc = 0; + + /* Just bail if the operation failed. */ + if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0) + return; + + /* Get the source SDN. */ + if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &src) != 0) + return; + + /* Ignore the error here (delete operations). */ + (void) slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &entry); + + update(cfg, src, entry); +} + +Slapi_ComponentId *otp_config_plugin_id(const struct otp_config *cfg) +{ + if (cfg == NULL) + return NULL; + + return cfg->plugin_id; +} + +uint32_t otp_config_auth_types(const struct otp_config *cfg, + Slapi_Entry *user_entry) +{ + uint32_t glbl = OTP_CONFIG_AUTH_TYPE_NONE; + uint32_t user = OTP_CONFIG_AUTH_TYPE_NONE; + const Slapi_DN *sfx; + + /* Load the global value. */ + sfx = slapi_get_suffix_by_dn(slapi_entry_get_sdn(user_entry)); + glbl = find_value(cfg, sfx, &authtypes); + + /* Load the user value if not disabled. */ + if ((glbl & OTP_CONFIG_AUTH_TYPE_DISABLED) == 0) + user = entry_to_authtypes(user_entry, authtypes.attr); + + /* Filter out the disabled flag. */ + glbl &= ~OTP_CONFIG_AUTH_TYPE_DISABLED; + user &= ~OTP_CONFIG_AUTH_TYPE_DISABLED; + + if (user != OTP_CONFIG_AUTH_TYPE_NONE) + return user; + + if (glbl != OTP_CONFIG_AUTH_TYPE_NONE) + return glbl; + + return OTP_CONFIG_AUTH_TYPE_PASSWORD; +} diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.h b/daemons/ipa-slapi-plugins/libotp/otp_config.h new file mode 100644 index 000000000..bfd514bd5 --- /dev/null +++ b/daemons/ipa-slapi-plugins/libotp/otp_config.h @@ -0,0 +1,65 @@ +/** 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 **/ + +#pragma once + +#include + +#define OTP_CONFIG_AUTH_TYPE_NONE 0 +#define OTP_CONFIG_AUTH_TYPE_PASSWORD (1 << 0) +#define OTP_CONFIG_AUTH_TYPE_OTP (1 << 1) +#define OTP_CONFIG_AUTH_TYPE_PKINIT (1 << 2) +#define OTP_CONFIG_AUTH_TYPE_RADIUS (1 << 3) + +struct otp_config; + +struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id); + +void otp_config_fini(struct otp_config **cfg); + +void otp_config_update(struct otp_config *cfg, Slapi_PBlock *pb); + +Slapi_ComponentId *otp_config_plugin_id(const struct otp_config *cfg); + +/* Gets the permitted authentication types for the given user entry. + * + * The entry should be queried for the "ipaUserAuthType" attribute. + */ +uint32_t otp_config_auth_types(const struct otp_config *cfg, + Slapi_Entry *user_entry); diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c index 7860c8aba..eef072685 100644 --- a/daemons/ipa-slapi-plugins/libotp/otp_token.c +++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c @@ -59,7 +59,7 @@ enum type { }; struct otp_token { - Slapi_ComponentId *plugin_id; + const struct otp_config *cfg; Slapi_DN *sdn; struct hotp_token token; enum type type; @@ -75,21 +75,6 @@ struct otp_token { }; }; -static const char *get_basedn(Slapi_DN *dn) -{ - Slapi_DN *suffix = NULL; - void *node = NULL; - - for (suffix = slapi_get_first_suffix(&node, 0); - suffix != NULL; - suffix = slapi_get_next_suffix(&node, 0)) { - if (slapi_sdn_issuffix(dn, suffix)) - return (char *) slapi_sdn_get_dn(suffix); - } - - return NULL; -} - static inline bool is_algo_valid(const char *algo) { static const char *valid_algos[] = { "sha1", "sha256", "sha384", @@ -142,8 +127,8 @@ static bool writeattr(const struct otp_token *token, const char *attr, snprintf(value, sizeof(value), "%lld", val); pb = slapi_pblock_new(); - slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn), - mods, NULL, NULL, token->plugin_id, 0); + slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn), mods, NULL, + NULL, otp_config_plugin_id(token->cfg), 0); if (slapi_modify_internal_pb(pb) != 0) goto error; if (slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret) != 0) @@ -251,7 +236,7 @@ void otp_token_free_array(struct otp_token **tokens) free(tokens); } -static struct otp_token *otp_token_new(Slapi_ComponentId *id, +static struct otp_token *otp_token_new(const struct otp_config *cfg, Slapi_Entry *entry) { const struct berval *tmp; @@ -261,7 +246,7 @@ static struct otp_token *otp_token_new(Slapi_ComponentId *id, token = calloc(1, sizeof(struct otp_token)); if (token == NULL) return NULL; - token->plugin_id = id; + token->cfg = cfg; /* Get the token type. */ vals = slapi_entry_attr_get_charray(entry, "objectClass"); @@ -333,16 +318,16 @@ error: return NULL; } -static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, +static struct otp_token **find(const struct otp_config *cfg, const char *user_dn, const char *token_dn, const char *intfilter, const char *extfilter) { struct otp_token **tokens = NULL; + const Slapi_DN *basedn = NULL; Slapi_Entry **entries = NULL; Slapi_PBlock *pb = NULL; Slapi_DN *sdn = NULL; char *filter = NULL; - const char *basedn = NULL; size_t count = 0; int result = -1; @@ -367,20 +352,19 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, if (token_dn != NULL) { /* Find only the token specified. */ slapi_search_internal_set_pb(pb, token_dn, LDAP_SCOPE_BASE, filter, - NULL, 0, NULL, NULL, id, 0); + NULL, 0, NULL, NULL, + otp_config_plugin_id(cfg), 0); } else { sdn = slapi_sdn_new_dn_byval(user_dn); - if (sdn == NULL) - goto error; - - basedn = get_basedn(sdn); + basedn = slapi_get_suffix_by_dn(sdn); + slapi_sdn_free(&sdn); if (basedn == NULL) goto error; /* Find all user tokens. */ - slapi_search_internal_set_pb(pb, basedn, - LDAP_SCOPE_SUBTREE, filter, NULL, - 0, NULL, NULL, id, 0); + slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(basedn), + LDAP_SCOPE_SUBTREE, filter, NULL, 0, + NULL, NULL, otp_config_plugin_id(cfg), 0); } slapi_search_internal_pb(pb); slapi_ch_free_string(&filter); @@ -402,7 +386,7 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, if (tokens == NULL) goto error; for (count = 0; entries[count] != NULL; count++) { - tokens[count] = otp_token_new(id, entries[count]); + tokens[count] = otp_token_new(cfg, entries[count]); if (tokens[count] == NULL) { otp_token_free_array(tokens); tokens = NULL; @@ -411,15 +395,13 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, } error: - if (sdn != NULL) - slapi_sdn_free(&sdn); slapi_pblock_destroy(pb); return tokens; } -struct otp_token ** -otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn, - bool active, const char *filter) +struct otp_token **otp_token_find(const struct otp_config *cfg, + const char *user_dn, const char *token_dn, + bool active, const char *filter) { static const char template[] = "(|(ipatokenNotBefore<=%04d%02d%02d%02d%02d%02dZ)(!(ipatokenNotBefore=*)))" @@ -430,7 +412,7 @@ otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn, time_t now; if (!active) - return find(id, user_dn, token_dn, NULL, filter); + return find(cfg, user_dn, token_dn, NULL, filter); /* Get the current time. */ if (time(&now) == (time_t) -1) @@ -446,7 +428,7 @@ otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn, tm.tm_hour, tm.tm_min, tm.tm_sec) < 0) return NULL; - return find(id, user_dn, token_dn, actfilt, filter); + return find(cfg, user_dn, token_dn, actfilt, filter); } int otp_token_get_digits(struct otp_token *token) diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.h b/daemons/ipa-slapi-plugins/libotp/otp_token.h index 2f3367806..4b159077d 100644 --- a/daemons/ipa-slapi-plugins/libotp/otp_token.h +++ b/daemons/ipa-slapi-plugins/libotp/otp_token.h @@ -39,14 +39,15 @@ #pragma once -#include +#include "otp_config.h" #include #include struct otp_token; /* Frees the token array. */ -void otp_token_free_array(struct otp_token **tokens); +void +otp_token_free_array(struct otp_token **tokens); /* Find tokens. * @@ -65,9 +66,9 @@ void otp_token_free_array(struct otp_token **tokens); * Returns NULL on error. If no tokens are found, an empty array is returned. * The array is NULL terminated. */ -struct otp_token **otp_token_find(Slapi_ComponentId *id, const char *user_dn, - const char *token_dn, bool active, - const char *filter); +struct otp_token **otp_token_find(const struct otp_config *cfg, + const char *user_dn, const char *token_dn, + bool active, const char *filter); /* Get the length of the token code. */ int otp_token_get_digits(struct otp_token *token); -- cgit