pgreco / rpms / ipa

Forked from forks/areguera/rpms/ipa 4 years ago
Clone

Blame SOURCES/0071-Move-authentication-configuration-cache-into-libotp.patch

e3ffab
From d19a011c84949c323194fe389f1e84d0dcc61c70 Mon Sep 17 00:00:00 2001
e3ffab
From: Nathaniel McCallum <npmccallum@redhat.com>
e3ffab
Date: Mon, 10 Nov 2014 22:46:44 -0500
e3ffab
Subject: [PATCH] Move authentication configuration cache into libotp
e3ffab
e3ffab
This enables plugins to share authentication configuration cache code.
e3ffab
e3ffab
Additionally, update the caching mechanism to be declarative and faster.
e3ffab
e3ffab
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
e3ffab
---
e3ffab
 .../ipa-slapi-plugins/ipa-pwd-extop/Makefile.am    |   1 -
e3ffab
 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c  | 280 ---------------------
e3ffab
 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h  |  82 ------
e3ffab
 .../ipa-pwd-extop/ipa_pwd_extop.c                  |  21 +-
e3ffab
 daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c  |  50 ++--
e3ffab
 daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c  |   4 +-
e3ffab
 daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h  |   4 +-
e3ffab
 daemons/ipa-slapi-plugins/libotp/Makefile.am       |   2 +-
e3ffab
 daemons/ipa-slapi-plugins/libotp/otp_config.c      | 274 ++++++++++++++++++++
e3ffab
 daemons/ipa-slapi-plugins/libotp/otp_config.h      |  65 +++++
e3ffab
 daemons/ipa-slapi-plugins/libotp/otp_token.c       |  58 ++---
e3ffab
 daemons/ipa-slapi-plugins/libotp/otp_token.h       |  11 +-
e3ffab
 12 files changed, 395 insertions(+), 457 deletions(-)
e3ffab
 delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c
e3ffab
 delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h
e3ffab
 create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_config.c
e3ffab
 create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_config.h
e3ffab
e3ffab
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
e3ffab
index eeb352611e5b67a2f6803b59414fb31c37f39f33..1ab6c6704e401810772a5ababc7cc5eec19d2c83 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
e3ffab
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
e3ffab
@@ -44,7 +44,6 @@ libipa_pwd_extop_la_LIBADD  = \
e3ffab
 	$(ASN1_UTIL_DIR)/libipaasn1.la  \
e3ffab
 	$(NULL)
e3ffab
 libipa_pwd_extop_la_SOURCES = 		\
e3ffab
-	authcfg.c			\
e3ffab
 	common.c			\
e3ffab
 	encoding.c			\
e3ffab
 	prepost.c			\
e3ffab
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c
e3ffab
deleted file mode 100644
e3ffab
index 3ab5668edd7edcb9eaf247c18b964f6584c9d439..0000000000000000000000000000000000000000
e3ffab
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c
e3ffab
+++ /dev/null
e3ffab
@@ -1,280 +0,0 @@
e3ffab
-/** BEGIN COPYRIGHT BLOCK
e3ffab
- * This program is free software; you can redistribute it and/or modify
e3ffab
- * it under the terms of the GNU General Public License as published by
e3ffab
- * the Free Software Foundation, either version 3 of the License, or
e3ffab
- * (at your option) any later version.
e3ffab
- *
e3ffab
- * This program is distributed in the hope that it will be useful,
e3ffab
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
e3ffab
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
e3ffab
- * GNU General Public License for more details.
e3ffab
- *
e3ffab
- * You should have received a copy of the GNU General Public License
e3ffab
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
e3ffab
- *
e3ffab
- * Additional permission under GPLv3 section 7:
e3ffab
- *
e3ffab
- * In the following paragraph, "GPL" means the GNU General Public
e3ffab
- * License, version 3 or any later version, and "Non-GPL Code" means
e3ffab
- * code that is governed neither by the GPL nor a license
e3ffab
- * compatible with the GPL.
e3ffab
- *
e3ffab
- * You may link the code of this Program with Non-GPL Code and convey
e3ffab
- * linked combinations including the two, provided that such Non-GPL
e3ffab
- * Code only links to the code of this Program through those well
e3ffab
- * defined interfaces identified in the file named EXCEPTION found in
e3ffab
- * the source code files (the "Approved Interfaces"). The files of
e3ffab
- * Non-GPL Code may instantiate templates or use macros or inline
e3ffab
- * functions from the Approved Interfaces without causing the resulting
e3ffab
- * work to be covered by the GPL. Only the copyright holders of this
e3ffab
- * Program may make changes or additions to the list of Approved
e3ffab
- * Interfaces.
e3ffab
- *
e3ffab
- * Authors:
e3ffab
- * Nathaniel McCallum <npmccallum@redhat.com>
e3ffab
- *
e3ffab
- * Copyright (C) 2014 Red Hat, Inc.
e3ffab
- * All rights reserved.
e3ffab
- * END COPYRIGHT BLOCK **/
e3ffab
-
e3ffab
-#include "authcfg.h"
e3ffab
-#include "ipapwd.h"
e3ffab
-
e3ffab
-#include "pratom.h"
e3ffab
-
e3ffab
-static struct config {
e3ffab
-    struct config *next;
e3ffab
-    Slapi_DN *suffix;
e3ffab
-    uint32_t config;
e3ffab
-} *config;
e3ffab
-
e3ffab
-static uint32_t string_to_config(const char *str)
e3ffab
-{
e3ffab
-    static const struct {
e3ffab
-        const char *string;
e3ffab
-        uint32_t config;
e3ffab
-    } map[] = {
e3ffab
-        { "disabled", AUTHCFG_AUTH_TYPE_DISABLED },
e3ffab
-        { "password", AUTHCFG_AUTH_TYPE_PASSWORD },
e3ffab
-        { "otp",      AUTHCFG_AUTH_TYPE_OTP },
e3ffab
-        { "pkinit",   AUTHCFG_AUTH_TYPE_PKINIT },
e3ffab
-        { "radius",   AUTHCFG_AUTH_TYPE_RADIUS },
e3ffab
-        {}
e3ffab
-    };
e3ffab
-
e3ffab
-    for (uint32_t i = 0; map[i].string != NULL; i++) {
e3ffab
-        if (strcasecmp(map[i].string, str) == 0)
e3ffab
-            return map[i].config;
e3ffab
-    }
e3ffab
-
e3ffab
-    return AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-}
e3ffab
-
e3ffab
-static uint32_t entry_to_config(Slapi_Entry *e)
e3ffab
-{
e3ffab
-    char **auth_types = NULL;
e3ffab
-
e3ffab
-    if (e == NULL)
e3ffab
-        return AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-
e3ffab
-    /* Fetch the auth type values from the config entry. */
e3ffab
-    auth_types = slapi_entry_attr_get_charray(e, "ipaUserAuthType");
e3ffab
-    if (auth_types == NULL)
e3ffab
-        return AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-
e3ffab
-    uint32_t types = AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-    for (uint32_t i = 0; auth_types[i] != NULL; i++)
e3ffab
-        types |= string_to_config(auth_types[i]);
e3ffab
-
e3ffab
-    slapi_ch_array_free(auth_types);
e3ffab
-
e3ffab
-    return types;
e3ffab
-}
e3ffab
-
e3ffab
-static Slapi_DN *suffix_to_config_dn(Slapi_DN *suffix)
e3ffab
-{
e3ffab
-    Slapi_DN *sdn = NULL;
e3ffab
-    char *dn = NULL;
e3ffab
-
e3ffab
-    if (suffix == NULL)
e3ffab
-        return NULL;
e3ffab
-
e3ffab
-    dn = PR_smprintf("cn=ipaConfig,cn=etc,%s", slapi_sdn_get_dn(suffix));
e3ffab
-    if (dn == NULL)
e3ffab
-        return NULL;
e3ffab
-
e3ffab
-    sdn = slapi_sdn_new_dn_byval(dn);
e3ffab
-    PR_smprintf_free(dn);
e3ffab
-    return sdn;
e3ffab
-}
e3ffab
-
e3ffab
-static uint32_t suffix_to_config(Slapi_DN *suffix)
e3ffab
-{
e3ffab
-    static char *attrs[] = { "ipaUserAuthType", NULL };
e3ffab
-    Slapi_Entry *entry = NULL;
e3ffab
-    Slapi_DN *sdn = NULL;
e3ffab
-    uint32_t types;
e3ffab
-    int ret;
e3ffab
-
e3ffab
-    sdn = suffix_to_config_dn(suffix);
e3ffab
-    if (sdn == NULL)
e3ffab
-        return AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-
e3ffab
-    ret = slapi_search_internal_get_entry(sdn, attrs, &entry,
e3ffab
-                                          ipapwd_get_plugin_id());
e3ffab
-    slapi_sdn_free(&sdn;;
e3ffab
-    if (ret != LDAP_SUCCESS)
e3ffab
-        return AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-
e3ffab
-    types = entry_to_config(entry);
e3ffab
-    slapi_entry_free(entry);
e3ffab
-
e3ffab
-    return types;
e3ffab
-}
e3ffab
-
e3ffab
-static Slapi_DN *sdn_to_suffix(Slapi_DN *sdn)
e3ffab
-{
e3ffab
-    Slapi_DN *suffix = NULL;
e3ffab
-    void *node = NULL;
e3ffab
-
e3ffab
-    if (sdn == NULL)
e3ffab
-        return NULL;
e3ffab
-
e3ffab
-    for (suffix = slapi_get_first_suffix(&node, 0); suffix != NULL;
e3ffab
-         suffix = slapi_get_next_suffix(&node, 0)) {
e3ffab
-        if (slapi_sdn_issuffix(sdn, suffix))
e3ffab
-            return suffix;
e3ffab
-    }
e3ffab
-
e3ffab
-    return NULL;
e3ffab
-}
e3ffab
-
e3ffab
-static bool sdn_is_config(Slapi_DN *sdn)
e3ffab
-{
e3ffab
-    Slapi_DN *sfx = NULL;
e3ffab
-    Slapi_DN *cfg = NULL;
e3ffab
-    int cmp;
e3ffab
-
e3ffab
-    if (sdn == NULL)
e3ffab
-        return false;
e3ffab
-
e3ffab
-    sfx = sdn_to_suffix(sdn);
e3ffab
-    if (sfx == NULL)
e3ffab
-        return false;
e3ffab
-
e3ffab
-    cfg = suffix_to_config_dn(sfx);
e3ffab
-    if (cfg == NULL)
e3ffab
-        return false;
e3ffab
-
e3ffab
-    cmp = slapi_sdn_compare(cfg, sdn);
e3ffab
-    slapi_sdn_free(&cfg;;
e3ffab
-    return cmp == 0;
e3ffab
-}
e3ffab
-
e3ffab
-void cache_free(struct config **cfg)
e3ffab
-{
e3ffab
-    if (cfg == NULL || *cfg == NULL)
e3ffab
-        return;
e3ffab
-
e3ffab
-    cache_free(&(*cfg)->next);
e3ffab
-    free(*cfg);
e3ffab
-    *cfg = NULL;
e3ffab
-}
e3ffab
-
e3ffab
-bool authcfg_init(void)
e3ffab
-{
e3ffab
-    struct config *cfg = NULL;
e3ffab
-    Slapi_DN *sfx = NULL;
e3ffab
-    void *node = NULL;
e3ffab
-
e3ffab
-    /* If we are already initialized, return true. */
e3ffab
-    if (config != NULL)
e3ffab
-        return true;
e3ffab
-
e3ffab
-    /* Look up the config for each suffix. */
e3ffab
-    for (sfx = slapi_get_first_suffix(&node, 0); sfx != NULL;
e3ffab
-         sfx = slapi_get_next_suffix(&node, 0)) {
e3ffab
-        cfg = calloc(1, sizeof(*cfg));
e3ffab
-        if (cfg == NULL) {
e3ffab
-            authcfg_fini();
e3ffab
-            return false;
e3ffab
-        }
e3ffab
-
e3ffab
-        cfg->suffix = sfx;
e3ffab
-        cfg->config = suffix_to_config(sfx);
e3ffab
-        cfg->next = config;
e3ffab
-        config = cfg;
e3ffab
-    }
e3ffab
-
e3ffab
-    return true;
e3ffab
-}
e3ffab
-
e3ffab
-void authcfg_fini(void)
e3ffab
-{
e3ffab
-    cache_free(&config);
e3ffab
-}
e3ffab
-
e3ffab
-uint32_t authcfg_get_auth_types(Slapi_Entry *user_entry)
e3ffab
-{
e3ffab
-    uint32_t glbl = AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-    uint32_t user = AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-    Slapi_DN *sfx = NULL;
e3ffab
-    Slapi_DN *sdn = NULL;
e3ffab
-
e3ffab
-    /* Find the root suffix. */
e3ffab
-    sdn = slapi_entry_get_sdn(user_entry);
e3ffab
-    sfx = sdn_to_suffix(sdn);
e3ffab
-
e3ffab
-    /* Find the global config. */
e3ffab
-    if (sfx != NULL) {
e3ffab
-        for (struct config *cfg = config; cfg && sfx; cfg = cfg->next) {
e3ffab
-            if (slapi_sdn_compare(sfx, cfg->suffix) == 0) {
e3ffab
-                glbl = PR_ATOMIC_ADD(&cfg->config, 0);
e3ffab
-                break;
e3ffab
-            }
e3ffab
-        }
e3ffab
-    }
e3ffab
-
e3ffab
-    /* Global disabled overrides user settings. */
e3ffab
-    if (glbl & AUTHCFG_AUTH_TYPE_DISABLED)
e3ffab
-        return AUTHCFG_AUTH_TYPE_DISABLED;
e3ffab
-
e3ffab
-    /* Get the user's config. */
e3ffab
-    user = entry_to_config(user_entry);
e3ffab
-
e3ffab
-    if (user == AUTHCFG_AUTH_TYPE_NONE) {
e3ffab
-        if (glbl == AUTHCFG_AUTH_TYPE_NONE)
e3ffab
-            return AUTHCFG_AUTH_TYPE_PASSWORD;
e3ffab
-        return glbl;
e3ffab
-    }
e3ffab
-
e3ffab
-    return user & ~AUTHCFG_AUTH_TYPE_DISABLED;
e3ffab
-}
e3ffab
-
e3ffab
-void authcfg_reload_global_config(Slapi_DN *sdn, Slapi_Entry *config_entry)
e3ffab
-{
e3ffab
-    uint32_t glbl = AUTHCFG_AUTH_TYPE_NONE;
e3ffab
-    Slapi_DN *sfx = NULL;
e3ffab
-    Slapi_DN *dest;
e3ffab
-
e3ffab
-    /* Get the destination DN. */
e3ffab
-    dest = config_entry == NULL ? NULL : slapi_entry_get_sdn(config_entry);
e3ffab
-
e3ffab
-    /* Added, modified, moved into place. */
e3ffab
-    if (sdn_is_config(dest)) {
e3ffab
-        sfx = sdn_to_suffix(dest);
e3ffab
-        glbl = entry_to_config(config_entry);
e3ffab
-
e3ffab
-    /* Deleted, moved out of place. */
e3ffab
-    } else if (sdn_is_config(sdn)) {
e3ffab
-        sfx = sdn_to_suffix(sdn);
e3ffab
-    }
e3ffab
-
e3ffab
-    /* Reload config. */
e3ffab
-    for (struct config *cfg = config; cfg && sfx; cfg = cfg->next) {
e3ffab
-        if (slapi_sdn_compare(sfx, cfg->suffix) == 0) {
e3ffab
-            PR_ATOMIC_SET(&cfg->config, glbl);
e3ffab
-            break;
e3ffab
-        }
e3ffab
-    }
e3ffab
-}
e3ffab
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h
e3ffab
deleted file mode 100644
e3ffab
index c2fc24605c0f915261a57967c43c35ab6e773263..0000000000000000000000000000000000000000
e3ffab
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h
e3ffab
+++ /dev/null
e3ffab
@@ -1,82 +0,0 @@
e3ffab
-/** BEGIN COPYRIGHT BLOCK
e3ffab
- * This program is free software; you can redistribute it and/or modify
e3ffab
- * it under the terms of the GNU General Public License as published by
e3ffab
- * the Free Software Foundation, either version 3 of the License, or
e3ffab
- * (at your option) any later version.
e3ffab
- *
e3ffab
- * This program is distributed in the hope that it will be useful,
e3ffab
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
e3ffab
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
e3ffab
- * GNU General Public License for more details.
e3ffab
- *
e3ffab
- * You should have received a copy of the GNU General Public License
e3ffab
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
e3ffab
- *
e3ffab
- * Additional permission under GPLv3 section 7:
e3ffab
- *
e3ffab
- * In the following paragraph, "GPL" means the GNU General Public
e3ffab
- * License, version 3 or any later version, and "Non-GPL Code" means
e3ffab
- * code that is governed neither by the GPL nor a license
e3ffab
- * compatible with the GPL.
e3ffab
- *
e3ffab
- * You may link the code of this Program with Non-GPL Code and convey
e3ffab
- * linked combinations including the two, provided that such Non-GPL
e3ffab
- * Code only links to the code of this Program through those well
e3ffab
- * defined interfaces identified in the file named EXCEPTION found in
e3ffab
- * the source code files (the "Approved Interfaces"). The files of
e3ffab
- * Non-GPL Code may instantiate templates or use macros or inline
e3ffab
- * functions from the Approved Interfaces without causing the resulting
e3ffab
- * work to be covered by the GPL. Only the copyright holders of this
e3ffab
- * Program may make changes or additions to the list of Approved
e3ffab
- * Interfaces.
e3ffab
- *
e3ffab
- * Authors:
e3ffab
- * Nathaniel McCallum <npmccallum@redhat.com>
e3ffab
- *
e3ffab
- * Copyright (C) 2014 Red Hat, Inc.
e3ffab
- * All rights reserved.
e3ffab
- * END COPYRIGHT BLOCK **/
e3ffab
-
e3ffab
-
e3ffab
-#ifndef AUTHCFG_H_
e3ffab
-#define AUTHCFG_H_
e3ffab
-
e3ffab
-#include <dirsrv/slapi-plugin.h>
e3ffab
-#include <stdbool.h>
e3ffab
-
e3ffab
-#define AUTHCFG_AUTH_TYPE_NONE     0
e3ffab
-#define AUTHCFG_AUTH_TYPE_DISABLED 1
e3ffab
-#define AUTHCFG_AUTH_TYPE_PASSWORD 2
e3ffab
-#define AUTHCFG_AUTH_TYPE_OTP      4
e3ffab
-#define AUTHCFG_AUTH_TYPE_PKINIT   8
e3ffab
-#define AUTHCFG_AUTH_TYPE_RADIUS   16
e3ffab
-
e3ffab
-/* Initialize authentication configuration.
e3ffab
- *
e3ffab
- * Thread Safety: NO
e3ffab
- */
e3ffab
-bool authcfg_init(void);
e3ffab
-
e3ffab
-/* Free global authentication configuration resources.
e3ffab
- *
e3ffab
- * Thread Safety: NO
e3ffab
- */
e3ffab
-void authcfg_fini(void);
e3ffab
-
e3ffab
-/* Gets the permitted authentication types for the given user entry.
e3ffab
- *
e3ffab
- * The entry should be queried for the "ipaUserAuthType" attribute.
e3ffab
- *
e3ffab
- * Thread Safety: YES
e3ffab
- */
e3ffab
-uint32_t authcfg_get_auth_types(Slapi_Entry *user_entry);
e3ffab
-
e3ffab
-/* Reloads configuration from the specified global config entry.
e3ffab
- *
e3ffab
- * If the provided entry isn't a global config entry, this is a no-op.
e3ffab
- *
e3ffab
- * Thread Safety: YES
e3ffab
- */
e3ffab
-void authcfg_reload_global_config(Slapi_DN *sdn, Slapi_Entry *config_entry);
e3ffab
-
e3ffab
-#endif /* AUTHCFG_H_ */
e3ffab
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
e3ffab
index ceea49cab50b0836c882240f210339e60d26729b..09c877f7010d3cc252c9f38e827cd33b63dea3b6 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
e3ffab
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
e3ffab
@@ -39,7 +39,7 @@
e3ffab
 
e3ffab
 #include "ipapwd.h"
e3ffab
 #include "util.h"
e3ffab
-#include "authcfg.h"
e3ffab
+#include "../libotp/otp_config.h"
e3ffab
 #include "ipa_asn1.h"
e3ffab
 
e3ffab
 /*
e3ffab
@@ -89,6 +89,8 @@ Slapi_PluginDesc ipapwd_plugin_desc = {
e3ffab
 void *ipapwd_plugin_id;
e3ffab
 static int usetxn = 0;
e3ffab
 
e3ffab
+extern struct otp_config *otp_config;
e3ffab
+
e3ffab
 void *ipapwd_get_plugin_id(void)
e3ffab
 {
e3ffab
     return ipapwd_plugin_id;
e3ffab
@@ -1792,16 +1794,6 @@ static int ipapwd_start( Slapi_PBlock *pb )
e3ffab
     Slapi_Entry *config_entry = NULL;
e3ffab
     int ret;
e3ffab
 
e3ffab
-    /* NOTE: We never call authcfg_fini() from a destructor. This is because
e3ffab
-     *       it may race with threaded requests at shutdown. This leak should
e3ffab
-     *       only occur when the DS is exiting, so it isn't a big deal.
e3ffab
-     */
e3ffab
-    if (!authcfg_init()) {
e3ffab
-        LOG_FATAL("AuthConf initialization failed!\n");
e3ffab
-        ret = LDAP_OPERATIONS_ERROR;
e3ffab
-        goto done;
e3ffab
-    }
e3ffab
-
e3ffab
     krberr = krb5_init_context(&krbctx);
e3ffab
     if (krberr) {
e3ffab
         LOG_FATAL("krb5_init_context failed\n");
e3ffab
@@ -1871,11 +1863,16 @@ static int ipapwd_start( Slapi_PBlock *pb )
e3ffab
 
e3ffab
     ret = LDAP_SUCCESS;
e3ffab
 
e3ffab
+    /* NOTE: We never call otp_config_fini() from a destructor. This is because
e3ffab
+     *       it may race with threaded requests at shutdown. This leak should
e3ffab
+     *       only occur when the DS is exiting, so it isn't a big deal.
e3ffab
+     */
e3ffab
+    otp_config = otp_config_init(ipapwd_plugin_id);
e3ffab
+
e3ffab
 done:
e3ffab
     free(realm);
e3ffab
     krb5_free_context(krbctx);
e3ffab
     if (config_entry) slapi_entry_free(config_entry);
e3ffab
-    if (ret != LDAP_SUCCESS) authcfg_fini();
e3ffab
     return ret;
e3ffab
 }
e3ffab
 
e3ffab
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
e3ffab
index 1dff6db1a8cfcc295ba43d1c29d8887e3cf37fec..96c55f39ba2a9dc1e9fc80d5f7d46787803ece47 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
e3ffab
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
e3ffab
@@ -63,7 +63,6 @@
e3ffab
 #include "ipapwd.h"
e3ffab
 #include "util.h"
e3ffab
 #include "syncreq.h"
e3ffab
-#include "authcfg.h"
e3ffab
 
e3ffab
 #define IPAPWD_OP_NULL 0
e3ffab
 #define IPAPWD_OP_ADD 1
e3ffab
@@ -75,6 +74,8 @@ extern Slapi_PluginDesc ipapwd_plugin_desc;
e3ffab
 extern void *ipapwd_plugin_id;
e3ffab
 extern const char *ipa_realm_tree;
e3ffab
 
e3ffab
+struct otp_config *otp_config = NULL;
e3ffab
+
e3ffab
 /* structure with information for each extension */
e3ffab
 struct ipapwd_op_ext {
e3ffab
     char *object_name;   /* name of the object extended   */
e3ffab
@@ -967,23 +968,9 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
e3ffab
     return ret;
e3ffab
 }
e3ffab
 
e3ffab
-static int ipapwd_post_authcfg(Slapi_PBlock *pb)
e3ffab
+static int ipapwd_post_updatecfg(Slapi_PBlock *pb)
e3ffab
 {
e3ffab
-    Slapi_Entry *config_entry = NULL;
e3ffab
-    Slapi_DN *sdn = NULL;
e3ffab
-    int oprc = 0;
e3ffab
-
e3ffab
-    /* Just bail if the operation failed. */
e3ffab
-    if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0)
e3ffab
-        return 0;
e3ffab
-
e3ffab
-    if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn) != 0)
e3ffab
-        return 0;
e3ffab
-
e3ffab
-    /* Ignore the error here (delete operations). */
e3ffab
-    slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &config_entry);
e3ffab
-
e3ffab
-    authcfg_reload_global_config(sdn, config_entry);
e3ffab
+    otp_config_update(otp_config, pb);
e3ffab
     return 0;
e3ffab
 }
e3ffab
 
e3ffab
@@ -1003,8 +990,7 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
e3ffab
 
e3ffab
     LOG_TRACE("=>\n");
e3ffab
 
e3ffab
-    /* Ignore error when parsing configuration. */
e3ffab
-    ipapwd_post_authcfg(pb);
e3ffab
+    otp_config_update(otp_config, pb);
e3ffab
 
e3ffab
     /* time to get the operation handler */
e3ffab
     ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op);
e3ffab
@@ -1144,7 +1130,7 @@ static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry,
e3ffab
     bool success = false;
e3ffab
 
e3ffab
     /* Find all of the user's active tokens. */
e3ffab
-    tokens = otp_token_find(ipapwd_plugin_id, dn, NULL, true, NULL);
e3ffab
+    tokens = otp_token_find(otp_config, dn, NULL, true, NULL);
e3ffab
     if (tokens == NULL) {
e3ffab
         slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME,
e3ffab
                         "%s: can't find tokens for '%s'.\n", __func__, dn);
e3ffab
@@ -1190,11 +1176,7 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
e3ffab
     uint32_t auth_types;
e3ffab
 
e3ffab
     /* Get the configured authentication types. */
e3ffab
-    auth_types = authcfg_get_auth_types(entry);
e3ffab
-
e3ffab
-    /* If global disabled flag is set, just punt. */
e3ffab
-    if (auth_types & AUTHCFG_AUTH_TYPE_DISABLED)
e3ffab
-        return true;
e3ffab
+    auth_types = otp_config_auth_types(otp_config, entry);
e3ffab
 
e3ffab
     /*
e3ffab
      * IMPORTANT SECTION!
e3ffab
@@ -1206,14 +1188,14 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
e3ffab
      * 2. If PWD is enabled or OTP succeeded, fall through to PWD validation.
e3ffab
      */
e3ffab
 
e3ffab
-    if (auth_types & AUTHCFG_AUTH_TYPE_OTP) {
e3ffab
+    if (auth_types & OTP_CONFIG_AUTH_TYPE_OTP) {
e3ffab
         LOG_PLUGIN_NAME(IPAPWD_PLUGIN_NAME,
e3ffab
                         "Attempting OTP authentication for '%s'.\n", bind_dn);
e3ffab
         if (ipapwd_do_otp_auth(bind_dn, entry, creds))
e3ffab
             return true;
e3ffab
     }
e3ffab
 
e3ffab
-    return auth_types & AUTHCFG_AUTH_TYPE_PASSWORD;
e3ffab
+    return auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD;
e3ffab
 }
e3ffab
 
e3ffab
 static int ipapwd_authenticate(const char *dn, Slapi_Entry *entry,
e3ffab
@@ -1461,7 +1443,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
e3ffab
     }
e3ffab
 
e3ffab
     /* Attempt to handle a token synchronization request. */
e3ffab
-    if (syncreq && !sync_request_handle(ipapwd_get_plugin_id(), pb, dn))
e3ffab
+    if (syncreq && !sync_request_handle(otp_config, pb, dn))
e3ffab
         goto invalid_creds;
e3ffab
 
e3ffab
     /* Attempt to write out kerberos keys for the user. */
e3ffab
@@ -1513,9 +1495,9 @@ int ipapwd_post_init(Slapi_PBlock *pb)
e3ffab
     ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
e3ffab
     if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
e3ffab
     if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *)ipapwd_post_modadd);
e3ffab
-    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_authcfg);
e3ffab
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_updatecfg);
e3ffab
     if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *)ipapwd_post_modadd);
e3ffab
-    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_authcfg);
e3ffab
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg);
e3ffab
 
e3ffab
     return ret;
e3ffab
 }
e3ffab
@@ -1526,10 +1508,10 @@ int ipapwd_intpost_init(Slapi_PBlock *pb)
e3ffab
 
e3ffab
     ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
e3ffab
     if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
e3ffab
-    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_authcfg);
e3ffab
-    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_authcfg);
e3ffab
-    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_authcfg);
e3ffab
-    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_authcfg);
e3ffab
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_updatecfg);
e3ffab
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_updatecfg);
e3ffab
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_updatecfg);
e3ffab
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg);
e3ffab
     return ret;
e3ffab
 }
e3ffab
 
e3ffab
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c
e3ffab
index 10c49b724ee276d2b1fb89891a6eb4ee8eaa8fab..0aef438023e7f23d7219273e9f5efd5572e73c3f 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c
e3ffab
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c
e3ffab
@@ -52,7 +52,7 @@ bool sync_request_present(Slapi_PBlock *pb)
e3ffab
     return ldap_control_find(OTP_SYNC_REQUEST_OID, controls, NULL) != NULL;
e3ffab
 }
e3ffab
 
e3ffab
-bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb,
e3ffab
+bool sync_request_handle(const struct otp_config *cfg, Slapi_PBlock *pb,
e3ffab
                          const char *user_dn)
e3ffab
 {
e3ffab
     struct otp_token **tokens = NULL;
e3ffab
@@ -90,7 +90,7 @@ bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb,
e3ffab
         /* Process the synchronization. */
e3ffab
         success = false;
e3ffab
         if (ber_scanf(ber, "}") != LBER_ERROR) {
e3ffab
-            tokens = otp_token_find(plugin_id, user_dn, token_dn, true, NULL);
e3ffab
+            tokens = otp_token_find(cfg, user_dn, token_dn, true, NULL);
e3ffab
             if (tokens != NULL) {
e3ffab
                 success = otp_token_sync_berval(tokens, OTP_SYNC_MAX_STEPS, first, second);
e3ffab
                 otp_token_free_array(tokens);
e3ffab
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h
e3ffab
index 34235901b7b2e49cc6e79423a92e0e4930c0b8cb..98a97c4c9f6d2e6bf74f97fc93053b3aebbc7821 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h
e3ffab
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h
e3ffab
@@ -41,7 +41,7 @@
e3ffab
 #ifndef SYNCREQ_H_
e3ffab
 #define SYNCREQ_H_
e3ffab
 
e3ffab
-#include <dirsrv/slapi-plugin.h>
e3ffab
+#include "../libotp/otp_config.h"
e3ffab
 #include <stdbool.h>
e3ffab
 
e3ffab
 /*
e3ffab
@@ -57,7 +57,7 @@
e3ffab
 
e3ffab
 bool sync_request_present(Slapi_PBlock *pb);
e3ffab
 
e3ffab
-bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb,
e3ffab
+bool sync_request_handle(const struct otp_config *cfg, Slapi_PBlock *pb,
e3ffab
                          const char *user_dn);
e3ffab
 
e3ffab
 #endif /* SYNCREQ_H_ */
e3ffab
diff --git a/daemons/ipa-slapi-plugins/libotp/Makefile.am b/daemons/ipa-slapi-plugins/libotp/Makefile.am
e3ffab
index 012c8339199af5f63e6434b94109af2d93a38b45..4428f6bdc38a4e4ec224d1fa70744d8381f7e0b1 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/libotp/Makefile.am
e3ffab
+++ b/daemons/ipa-slapi-plugins/libotp/Makefile.am
e3ffab
@@ -3,7 +3,7 @@ AM_CPPFLAGS = -I/usr/include/dirsrv
e3ffab
 
e3ffab
 noinst_LTLIBRARIES = libhotp.la libotp.la
e3ffab
 libhotp_la_SOURCES = hotp.c hotp.h
e3ffab
-libotp_la_SOURCES = otp_token.c otp_token.h
e3ffab
+libotp_la_SOURCES = otp_config.c otp_config.h otp_token.c otp_token.h
e3ffab
 libotp_la_LIBADD = libhotp.la
e3ffab
 
e3ffab
 check_PROGRAMS = t_hotp
e3ffab
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.c b/daemons/ipa-slapi-plugins/libotp/otp_config.c
e3ffab
new file mode 100644
e3ffab
index 0000000000000000000000000000000000000000..1b7c1e658f126e3d1e8eabd129bb69dc5c4ce970
e3ffab
--- /dev/null
e3ffab
+++ b/daemons/ipa-slapi-plugins/libotp/otp_config.c
e3ffab
@@ -0,0 +1,274 @@
e3ffab
+/** BEGIN COPYRIGHT BLOCK
e3ffab
+ * This program is free software; you can redistribute it and/or modify
e3ffab
+ * it under the terms of the GNU General Public License as published by
e3ffab
+ * the Free Software Foundation, either version 3 of the License, or
e3ffab
+ * (at your option) any later version.
e3ffab
+ *
e3ffab
+ * This program is distributed in the hope that it will be useful,
e3ffab
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
e3ffab
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
e3ffab
+ * GNU General Public License for more details.
e3ffab
+ *
e3ffab
+ * You should have received a copy of the GNU General Public License
e3ffab
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
e3ffab
+ *
e3ffab
+ * Additional permission under GPLv3 section 7:
e3ffab
+ *
e3ffab
+ * In the following paragraph, "GPL" means the GNU General Public
e3ffab
+ * License, version 3 or any later version, and "Non-GPL Code" means
e3ffab
+ * code that is governed neither by the GPL nor a license
e3ffab
+ * compatible with the GPL.
e3ffab
+ *
e3ffab
+ * You may link the code of this Program with Non-GPL Code and convey
e3ffab
+ * linked combinations including the two, provided that such Non-GPL
e3ffab
+ * Code only links to the code of this Program through those well
e3ffab
+ * defined interfaces identified in the file named EXCEPTION found in
e3ffab
+ * the source code files (the "Approved Interfaces"). The files of
e3ffab
+ * Non-GPL Code may instantiate templates or use macros or inline
e3ffab
+ * functions from the Approved Interfaces without causing the resulting
e3ffab
+ * work to be covered by the GPL. Only the copyright holders of this
e3ffab
+ * Program may make changes or additions to the list of Approved
e3ffab
+ * Interfaces.
e3ffab
+ *
e3ffab
+ * Authors:
e3ffab
+ * Nathaniel McCallum <npmccallum@redhat.com>
e3ffab
+ *
e3ffab
+ * Copyright (C) 2014 Red Hat, Inc.
e3ffab
+ * All rights reserved.
e3ffab
+ * END COPYRIGHT BLOCK **/
e3ffab
+
e3ffab
+#include "otp_config.h"
e3ffab
+
e3ffab
+#include <pratom.h>
e3ffab
+#include <plstr.h>
e3ffab
+
e3ffab
+#define OTP_CONFIG_AUTH_TYPE_DISABLED (1 << 31)
e3ffab
+
e3ffab
+struct spec {
e3ffab
+    uint32_t (*func)(Slapi_Entry *, const char *attr);
e3ffab
+    const char *prefix;
e3ffab
+    const char *attr;
e3ffab
+    uint32_t dflt;
e3ffab
+};
e3ffab
+
e3ffab
+struct record {
e3ffab
+    struct record *next;
e3ffab
+    const struct spec *spec;
e3ffab
+    Slapi_DN *sdn;
e3ffab
+    uint32_t value;
e3ffab
+};
e3ffab
+
e3ffab
+struct otp_config {
e3ffab
+    Slapi_ComponentId *plugin_id;
e3ffab
+    struct record *records;
e3ffab
+};
e3ffab
+
e3ffab
+static uint32_t string_to_types(const char *str)
e3ffab
+{
e3ffab
+    static const struct {
e3ffab
+        const char *string;
e3ffab
+        uint32_t config;
e3ffab
+    } map[] = {
e3ffab
+        { "disabled", OTP_CONFIG_AUTH_TYPE_DISABLED },
e3ffab
+        { "password", OTP_CONFIG_AUTH_TYPE_PASSWORD },
e3ffab
+        { "otp",      OTP_CONFIG_AUTH_TYPE_OTP },
e3ffab
+        { "pkinit",   OTP_CONFIG_AUTH_TYPE_PKINIT },
e3ffab
+        { "radius",   OTP_CONFIG_AUTH_TYPE_RADIUS },
e3ffab
+        {}
e3ffab
+    };
e3ffab
+
e3ffab
+    for (uint32_t i = 0; map[i].string != NULL; i++) {
e3ffab
+        if (strcasecmp(map[i].string, str) == 0)
e3ffab
+            return map[i].config;
e3ffab
+    }
e3ffab
+
e3ffab
+    return OTP_CONFIG_AUTH_TYPE_NONE;
e3ffab
+}
e3ffab
+
e3ffab
+static uint32_t entry_to_authtypes(Slapi_Entry *e, const char *attr)
e3ffab
+{
e3ffab
+    char **auth_types = NULL;
e3ffab
+
e3ffab
+    if (e == NULL)
e3ffab
+        return OTP_CONFIG_AUTH_TYPE_NONE;
e3ffab
+
e3ffab
+    /* Fetch the auth type values from the config entry. */
e3ffab
+    auth_types = slapi_entry_attr_get_charray(e, attr);
e3ffab
+    if (auth_types == NULL)
e3ffab
+        return OTP_CONFIG_AUTH_TYPE_NONE;
e3ffab
+
e3ffab
+    uint32_t types = OTP_CONFIG_AUTH_TYPE_NONE;
e3ffab
+    for (uint32_t i = 0; auth_types[i] != NULL; i++)
e3ffab
+        types |= string_to_types(auth_types[i]);
e3ffab
+
e3ffab
+    slapi_ch_array_free(auth_types);
e3ffab
+    return types;
e3ffab
+}
e3ffab
+
e3ffab
+static const struct spec authtypes = {
e3ffab
+    entry_to_authtypes,
e3ffab
+    "cn=ipaConfig,cn=etc,%s",
e3ffab
+    "ipaUserAuthType",
e3ffab
+    OTP_CONFIG_AUTH_TYPE_PASSWORD
e3ffab
+};
e3ffab
+
e3ffab
+static Slapi_DN *make_sdn(const char *prefix, const Slapi_DN *suffix)
e3ffab
+{
e3ffab
+    char *dn = slapi_ch_smprintf(prefix, slapi_sdn_get_dn(suffix));
e3ffab
+    return slapi_sdn_new_dn_passin(dn);
e3ffab
+}
e3ffab
+
e3ffab
+static uint32_t find_value(const struct otp_config *cfg,
e3ffab
+                           const Slapi_DN *suffix, const struct spec *spec)
e3ffab
+{
e3ffab
+    uint32_t value = 0;
e3ffab
+    Slapi_DN *sdn;
e3ffab
+
e3ffab
+    sdn = make_sdn(spec->prefix, suffix);
e3ffab
+    for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) {
e3ffab
+        if (rec->spec == spec) {
e3ffab
+            value = PR_ATOMIC_ADD(&rec->value, 0);
e3ffab
+            break;
e3ffab
+        }
e3ffab
+    }
e3ffab
+
e3ffab
+    slapi_sdn_free(&sdn;;
e3ffab
+    return value;
e3ffab
+}
e3ffab
+
e3ffab
+static void update(const struct otp_config *cfg, Slapi_DN *src,
e3ffab
+                   Slapi_Entry *entry)
e3ffab
+{
e3ffab
+    Slapi_DN *dst = entry == NULL ? NULL : slapi_entry_get_sdn(entry);
e3ffab
+
e3ffab
+    for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) {
e3ffab
+        uint32_t val = rec->spec->dflt;
e3ffab
+
e3ffab
+        /* If added, modified or moved into place... */
e3ffab
+        if (dst != NULL && slapi_sdn_compare(rec->sdn, dst) == 0) {
e3ffab
+            Slapi_Attr *attr = NULL;
e3ffab
+            if (slapi_entry_attr_find(entry, rec->spec->attr, &attr) == 0)
e3ffab
+                val = rec->spec->func(entry, rec->spec->attr);
e3ffab
+
e3ffab
+        /* If NOT deleted or moved out of place... */
e3ffab
+        } else if (slapi_sdn_compare(rec->sdn, src) != 0)
e3ffab
+            continue;
e3ffab
+
e3ffab
+        PR_ATOMIC_SET(&rec->value, val);
e3ffab
+    }
e3ffab
+}
e3ffab
+
e3ffab
+struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id)
e3ffab
+{
e3ffab
+    static const struct spec *specs[] = {
e3ffab
+        &authtypes,
e3ffab
+        NULL
e3ffab
+    };
e3ffab
+
e3ffab
+    struct otp_config *cfg = NULL;
e3ffab
+    void *node = NULL;
e3ffab
+
e3ffab
+    cfg = (typeof(cfg)) slapi_ch_calloc(1, sizeof(*cfg));
e3ffab
+    cfg->plugin_id = plugin_id;
e3ffab
+
e3ffab
+    /* Build the config table. */
e3ffab
+    for (Slapi_DN *sfx = slapi_get_first_suffix(&node, 0);
e3ffab
+         sfx != NULL;
e3ffab
+         sfx = slapi_get_next_suffix(&node, 0)) {
e3ffab
+        for (size_t i = 0; specs[i] != NULL; i++) {
e3ffab
+            Slapi_Entry *entry = NULL;
e3ffab
+            struct record *rec;
e3ffab
+
e3ffab
+            /* Create the config entry. */
e3ffab
+            rec = (typeof(rec)) slapi_ch_calloc(1, sizeof(*rec));
e3ffab
+            rec->spec = specs[i];
e3ffab
+            rec->sdn = make_sdn(rec->spec->prefix, sfx);
e3ffab
+
e3ffab
+            /* Add config to the list. */
e3ffab
+            rec->next = cfg->records;
e3ffab
+            cfg->records = rec;
e3ffab
+
e3ffab
+            /* Load the specified entry. */
e3ffab
+            slapi_search_internal_get_entry(rec->sdn, NULL, &entry, plugin_id);
e3ffab
+            update(cfg, rec->sdn, entry);
e3ffab
+            slapi_entry_free(entry);
e3ffab
+        }
e3ffab
+    }
e3ffab
+
e3ffab
+    return cfg;
e3ffab
+}
e3ffab
+
e3ffab
+static void record_fini(struct record **rec)
e3ffab
+{
e3ffab
+    if (rec == NULL || *rec == NULL)
e3ffab
+        return;
e3ffab
+
e3ffab
+    record_fini(&(*rec)->next);
e3ffab
+    slapi_sdn_free(&(*rec)->sdn);
e3ffab
+    slapi_ch_free((void **) rec);
e3ffab
+}
e3ffab
+
e3ffab
+void otp_config_fini(struct otp_config **cfg)
e3ffab
+{
e3ffab
+    if (cfg == NULL || *cfg == NULL)
e3ffab
+        return;
e3ffab
+
e3ffab
+    record_fini(&(*cfg)->records);
e3ffab
+    slapi_ch_free((void **) cfg);
e3ffab
+}
e3ffab
+
e3ffab
+void otp_config_update(struct otp_config *cfg, Slapi_PBlock *pb)
e3ffab
+{
e3ffab
+    Slapi_Entry *entry = NULL;
e3ffab
+    Slapi_DN *src = NULL;
e3ffab
+    int oprc = 0;
e3ffab
+
e3ffab
+    /* Just bail if the operation failed. */
e3ffab
+    if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0)
e3ffab
+        return;
e3ffab
+
e3ffab
+    /* Get the source SDN. */
e3ffab
+    if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &src) != 0)
e3ffab
+        return;
e3ffab
+
e3ffab
+    /* Ignore the error here (delete operations). */
e3ffab
+    (void) slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &entry);
e3ffab
+
e3ffab
+    update(cfg, src, entry);
e3ffab
+}
e3ffab
+
e3ffab
+Slapi_ComponentId *otp_config_plugin_id(const struct otp_config *cfg)
e3ffab
+{
e3ffab
+    if (cfg == NULL)
e3ffab
+        return NULL;
e3ffab
+
e3ffab
+    return cfg->plugin_id;
e3ffab
+}
e3ffab
+
e3ffab
+uint32_t otp_config_auth_types(const struct otp_config *cfg,
e3ffab
+                               Slapi_Entry *user_entry)
e3ffab
+{
e3ffab
+    uint32_t glbl = OTP_CONFIG_AUTH_TYPE_NONE;
e3ffab
+    uint32_t user = OTP_CONFIG_AUTH_TYPE_NONE;
e3ffab
+    const Slapi_DN *sfx;
e3ffab
+
e3ffab
+    /* Load the global value. */
e3ffab
+    sfx = slapi_get_suffix_by_dn(slapi_entry_get_sdn(user_entry));
e3ffab
+    glbl = find_value(cfg, sfx, &authtypes);
e3ffab
+
e3ffab
+    /* Load the user value if not disabled. */
e3ffab
+    if ((glbl & OTP_CONFIG_AUTH_TYPE_DISABLED) == 0)
e3ffab
+        user = entry_to_authtypes(user_entry, authtypes.attr);
e3ffab
+
e3ffab
+    /* Filter out the disabled flag. */
e3ffab
+    glbl &= ~OTP_CONFIG_AUTH_TYPE_DISABLED;
e3ffab
+    user &= ~OTP_CONFIG_AUTH_TYPE_DISABLED;
e3ffab
+
e3ffab
+    if (user != OTP_CONFIG_AUTH_TYPE_NONE)
e3ffab
+        return user;
e3ffab
+
e3ffab
+    if (glbl != OTP_CONFIG_AUTH_TYPE_NONE)
e3ffab
+        return glbl;
e3ffab
+
e3ffab
+    return OTP_CONFIG_AUTH_TYPE_PASSWORD;
e3ffab
+}
e3ffab
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.h b/daemons/ipa-slapi-plugins/libotp/otp_config.h
e3ffab
new file mode 100644
e3ffab
index 0000000000000000000000000000000000000000..bfd514bd542b7d707e9eab4a9cdf31a4f6839ae5
e3ffab
--- /dev/null
e3ffab
+++ b/daemons/ipa-slapi-plugins/libotp/otp_config.h
e3ffab
@@ -0,0 +1,65 @@
e3ffab
+/** BEGIN COPYRIGHT BLOCK
e3ffab
+ * This program is free software; you can redistribute it and/or modify
e3ffab
+ * it under the terms of the GNU General Public License as published by
e3ffab
+ * the Free Software Foundation, either version 3 of the License, or
e3ffab
+ * (at your option) any later version.
e3ffab
+ *
e3ffab
+ * This program is distributed in the hope that it will be useful,
e3ffab
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
e3ffab
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
e3ffab
+ * GNU General Public License for more details.
e3ffab
+ *
e3ffab
+ * You should have received a copy of the GNU General Public License
e3ffab
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
e3ffab
+ *
e3ffab
+ * Additional permission under GPLv3 section 7:
e3ffab
+ *
e3ffab
+ * In the following paragraph, "GPL" means the GNU General Public
e3ffab
+ * License, version 3 or any later version, and "Non-GPL Code" means
e3ffab
+ * code that is governed neither by the GPL nor a license
e3ffab
+ * compatible with the GPL.
e3ffab
+ *
e3ffab
+ * You may link the code of this Program with Non-GPL Code and convey
e3ffab
+ * linked combinations including the two, provided that such Non-GPL
e3ffab
+ * Code only links to the code of this Program through those well
e3ffab
+ * defined interfaces identified in the file named EXCEPTION found in
e3ffab
+ * the source code files (the "Approved Interfaces"). The files of
e3ffab
+ * Non-GPL Code may instantiate templates or use macros or inline
e3ffab
+ * functions from the Approved Interfaces without causing the resulting
e3ffab
+ * work to be covered by the GPL. Only the copyright holders of this
e3ffab
+ * Program may make changes or additions to the list of Approved
e3ffab
+ * Interfaces.
e3ffab
+ *
e3ffab
+ * Authors:
e3ffab
+ * Nathaniel McCallum <npmccallum@redhat.com>
e3ffab
+ *
e3ffab
+ * Copyright (C) 2014 Red Hat, Inc.
e3ffab
+ * All rights reserved.
e3ffab
+ * END COPYRIGHT BLOCK **/
e3ffab
+
e3ffab
+#pragma once
e3ffab
+
e3ffab
+#include <dirsrv/slapi-plugin.h>
e3ffab
+
e3ffab
+#define OTP_CONFIG_AUTH_TYPE_NONE     0
e3ffab
+#define OTP_CONFIG_AUTH_TYPE_PASSWORD (1 << 0)
e3ffab
+#define OTP_CONFIG_AUTH_TYPE_OTP      (1 << 1)
e3ffab
+#define OTP_CONFIG_AUTH_TYPE_PKINIT   (1 << 2)
e3ffab
+#define OTP_CONFIG_AUTH_TYPE_RADIUS   (1 << 3)
e3ffab
+
e3ffab
+struct otp_config;
e3ffab
+
e3ffab
+struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id);
e3ffab
+
e3ffab
+void otp_config_fini(struct otp_config **cfg);
e3ffab
+
e3ffab
+void otp_config_update(struct otp_config *cfg, Slapi_PBlock *pb);
e3ffab
+
e3ffab
+Slapi_ComponentId *otp_config_plugin_id(const struct otp_config *cfg);
e3ffab
+
e3ffab
+/* Gets the permitted authentication types for the given user entry.
e3ffab
+ *
e3ffab
+ * The entry should be queried for the "ipaUserAuthType" attribute.
e3ffab
+ */
e3ffab
+uint32_t otp_config_auth_types(const struct otp_config *cfg,
e3ffab
+                               Slapi_Entry *user_entry);
e3ffab
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c
e3ffab
index 7860c8aba6e12e319d633ee8e165403289a7528b..eef07268507444897d50509a54f2877866b9c07a 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/libotp/otp_token.c
e3ffab
+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c
e3ffab
@@ -59,7 +59,7 @@ enum type {
e3ffab
 };
e3ffab
 
e3ffab
 struct otp_token {
e3ffab
-    Slapi_ComponentId *plugin_id;
e3ffab
+    const struct otp_config *cfg;
e3ffab
     Slapi_DN *sdn;
e3ffab
     struct hotp_token token;
e3ffab
     enum type type;
e3ffab
@@ -75,21 +75,6 @@ struct otp_token {
e3ffab
     };
e3ffab
 };
e3ffab
 
e3ffab
-static const char *get_basedn(Slapi_DN *dn)
e3ffab
-{
e3ffab
-    Slapi_DN *suffix = NULL;
e3ffab
-    void *node = NULL;
e3ffab
-
e3ffab
-    for (suffix = slapi_get_first_suffix(&node, 0);
e3ffab
-         suffix != NULL;
e3ffab
-         suffix = slapi_get_next_suffix(&node, 0)) {
e3ffab
-        if (slapi_sdn_issuffix(dn, suffix))
e3ffab
-            return (char *) slapi_sdn_get_dn(suffix);
e3ffab
-    }
e3ffab
-
e3ffab
-    return NULL;
e3ffab
-}
e3ffab
-
e3ffab
 static inline bool is_algo_valid(const char *algo)
e3ffab
 {
e3ffab
     static const char *valid_algos[] = { "sha1", "sha256", "sha384",
e3ffab
@@ -142,8 +127,8 @@ static bool writeattr(const struct otp_token *token, const char *attr,
e3ffab
     snprintf(value, sizeof(value), "%lld", val);
e3ffab
 
e3ffab
     pb = slapi_pblock_new();
e3ffab
-    slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn),
e3ffab
-                                 mods, NULL, NULL, token->plugin_id, 0);
e3ffab
+    slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn), mods, NULL,
e3ffab
+                                 NULL, otp_config_plugin_id(token->cfg), 0);
e3ffab
     if (slapi_modify_internal_pb(pb) != 0)
e3ffab
         goto error;
e3ffab
     if (slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret) != 0)
e3ffab
@@ -251,7 +236,7 @@ void otp_token_free_array(struct otp_token **tokens)
e3ffab
     free(tokens);
e3ffab
 }
e3ffab
 
e3ffab
-static struct otp_token *otp_token_new(Slapi_ComponentId *id,
e3ffab
+static struct otp_token *otp_token_new(const struct otp_config *cfg,
e3ffab
                                        Slapi_Entry *entry)
e3ffab
 {
e3ffab
     const struct berval *tmp;
e3ffab
@@ -261,7 +246,7 @@ static struct otp_token *otp_token_new(Slapi_ComponentId *id,
e3ffab
     token = calloc(1, sizeof(struct otp_token));
e3ffab
     if (token == NULL)
e3ffab
         return NULL;
e3ffab
-    token->plugin_id = id;
e3ffab
+    token->cfg = cfg;
e3ffab
 
e3ffab
     /* Get the token type. */
e3ffab
     vals = slapi_entry_attr_get_charray(entry, "objectClass");
e3ffab
@@ -333,16 +318,16 @@ error:
e3ffab
     return NULL;
e3ffab
 }
e3ffab
 
e3ffab
-static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn,
e3ffab
+static struct otp_token **find(const struct otp_config *cfg, const char *user_dn,
e3ffab
                                const char *token_dn, const char *intfilter,
e3ffab
                                const char *extfilter)
e3ffab
 {
e3ffab
     struct otp_token **tokens = NULL;
e3ffab
+    const Slapi_DN *basedn = NULL;
e3ffab
     Slapi_Entry **entries = NULL;
e3ffab
     Slapi_PBlock *pb = NULL;
e3ffab
     Slapi_DN *sdn = NULL;
e3ffab
     char *filter = NULL;
e3ffab
-    const char *basedn = NULL;
e3ffab
     size_t count = 0;
e3ffab
     int result = -1;
e3ffab
 
e3ffab
@@ -367,20 +352,19 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn,
e3ffab
     if (token_dn != NULL) {
e3ffab
         /* Find only the token specified. */
e3ffab
         slapi_search_internal_set_pb(pb, token_dn, LDAP_SCOPE_BASE, filter,
e3ffab
-                                     NULL, 0, NULL, NULL, id, 0);
e3ffab
+                                     NULL, 0, NULL, NULL,
e3ffab
+                                     otp_config_plugin_id(cfg), 0);
e3ffab
     } else {
e3ffab
         sdn = slapi_sdn_new_dn_byval(user_dn);
e3ffab
-        if (sdn == NULL)
e3ffab
-            goto error;
e3ffab
-
e3ffab
-        basedn = get_basedn(sdn);
e3ffab
+        basedn = slapi_get_suffix_by_dn(sdn);
e3ffab
+        slapi_sdn_free(&sdn;;
e3ffab
         if (basedn == NULL)
e3ffab
             goto error;
e3ffab
 
e3ffab
         /* Find all user tokens. */
e3ffab
-        slapi_search_internal_set_pb(pb, basedn,
e3ffab
-                                     LDAP_SCOPE_SUBTREE, filter, NULL,
e3ffab
-                                     0, NULL, NULL, id, 0);
e3ffab
+        slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(basedn),
e3ffab
+                                     LDAP_SCOPE_SUBTREE, filter, NULL, 0,
e3ffab
+                                     NULL, NULL, otp_config_plugin_id(cfg), 0);
e3ffab
     }
e3ffab
     slapi_search_internal_pb(pb);
e3ffab
     slapi_ch_free_string(&filter);
e3ffab
@@ -402,7 +386,7 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn,
e3ffab
     if (tokens == NULL)
e3ffab
         goto error;
e3ffab
     for (count = 0; entries[count] != NULL; count++) {
e3ffab
-        tokens[count] = otp_token_new(id, entries[count]);
e3ffab
+        tokens[count] = otp_token_new(cfg, entries[count]);
e3ffab
         if (tokens[count] == NULL) {
e3ffab
             otp_token_free_array(tokens);
e3ffab
             tokens = NULL;
e3ffab
@@ -411,15 +395,13 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn,
e3ffab
     }
e3ffab
 
e3ffab
 error:
e3ffab
-    if (sdn != NULL)
e3ffab
-        slapi_sdn_free(&sdn;;
e3ffab
     slapi_pblock_destroy(pb);
e3ffab
     return tokens;
e3ffab
 }
e3ffab
 
e3ffab
-struct otp_token **
e3ffab
-otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn,
e3ffab
-               bool active, const char *filter)
e3ffab
+struct otp_token **otp_token_find(const struct otp_config *cfg,
e3ffab
+                                  const char *user_dn, const char *token_dn,
e3ffab
+                                  bool active, const char *filter)
e3ffab
 {
e3ffab
     static const char template[] =
e3ffab
     "(|(ipatokenNotBefore<=%04d%02d%02d%02d%02d%02dZ)(!(ipatokenNotBefore=*)))"
e3ffab
@@ -430,7 +412,7 @@ otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn,
e3ffab
     time_t now;
e3ffab
 
e3ffab
     if (!active)
e3ffab
-        return find(id, user_dn, token_dn, NULL, filter);
e3ffab
+        return find(cfg, user_dn, token_dn, NULL, filter);
e3ffab
 
e3ffab
     /* Get the current time. */
e3ffab
     if (time(&now) == (time_t) -1)
e3ffab
@@ -446,7 +428,7 @@ otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn,
e3ffab
                  tm.tm_hour, tm.tm_min, tm.tm_sec) < 0)
e3ffab
         return NULL;
e3ffab
 
e3ffab
-    return find(id, user_dn, token_dn, actfilt, filter);
e3ffab
+    return find(cfg, user_dn, token_dn, actfilt, filter);
e3ffab
 }
e3ffab
 
e3ffab
 int otp_token_get_digits(struct otp_token *token)
e3ffab
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.h b/daemons/ipa-slapi-plugins/libotp/otp_token.h
e3ffab
index 2f336780682b5ea2838b558079e2ae85f6e2afba..4b159077d933555d18e804174e29e22f1e8f0110 100644
e3ffab
--- a/daemons/ipa-slapi-plugins/libotp/otp_token.h
e3ffab
+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.h
e3ffab
@@ -39,14 +39,15 @@
e3ffab
 
e3ffab
 #pragma once
e3ffab
 
e3ffab
-#include <dirsrv/slapi-plugin.h>
e3ffab
+#include "otp_config.h"
e3ffab
 #include <stdbool.h>
e3ffab
 #include <stdlib.h>
e3ffab
 
e3ffab
 struct otp_token;
e3ffab
 
e3ffab
 /* Frees the token array. */
e3ffab
-void otp_token_free_array(struct otp_token **tokens);
e3ffab
+void
e3ffab
+otp_token_free_array(struct otp_token **tokens);
e3ffab
 
e3ffab
 /* Find tokens.
e3ffab
  *
e3ffab
@@ -65,9 +66,9 @@ void otp_token_free_array(struct otp_token **tokens);
e3ffab
  * Returns NULL on error. If no tokens are found, an empty array is returned.
e3ffab
  * The array is NULL terminated.
e3ffab
  */
e3ffab
-struct otp_token **otp_token_find(Slapi_ComponentId *id, const char *user_dn,
e3ffab
-                                  const char *token_dn, bool active,
e3ffab
-                                  const char *filter);
e3ffab
+struct otp_token **otp_token_find(const struct otp_config *cfg,
e3ffab
+                                  const char *user_dn, const char *token_dn,
e3ffab
+                                  bool active, const char *filter);
e3ffab
 
e3ffab
 /* Get the length of the token code. */
e3ffab
 int otp_token_get_digits(struct otp_token *token);
e3ffab
-- 
e3ffab
2.1.0
e3ffab