diff options
| author | Nathaniel McCallum <npmccallum@redhat.com> | 2014-11-10 22:46:44 -0500 |
|---|---|---|
| committer | Martin Kosek <mkosek@redhat.com> | 2014-12-03 08:48:56 +0100 |
| commit | 953c6846b7cb8d75253538ab92a1360fceee0c3c (patch) | |
| tree | 66df5362c6d8d6453b14f5f363d146dc6ac66e65 /daemons/ipa-slapi-plugins/libotp | |
| parent | bdccb0c721283f17a48423ab562ab5515ecd7f8e (diff) | |
| download | freeipa-953c6846b7cb8d75253538ab92a1360fceee0c3c.tar.gz freeipa-953c6846b7cb8d75253538ab92a1360fceee0c3c.tar.xz freeipa-953c6846b7cb8d75253538ab92a1360fceee0c3c.zip | |
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 <tbordaz@redhat.com>
Diffstat (limited to 'daemons/ipa-slapi-plugins/libotp')
| -rw-r--r-- | daemons/ipa-slapi-plugins/libotp/Makefile.am | 2 | ||||
| -rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_config.c | 274 | ||||
| -rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_config.h | 65 | ||||
| -rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_token.c | 58 | ||||
| -rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_token.h | 11 |
5 files changed, 366 insertions, 44 deletions
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 <http://www.gnu.org/licenses/>. + * + * 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 <npmccallum@redhat.com> + * + * Copyright (C) 2014 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include "otp_config.h" + +#include <pratom.h> +#include <plstr.h> + +#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 <http://www.gnu.org/licenses/>. + * + * 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 <npmccallum@redhat.com> + * + * Copyright (C) 2014 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#pragma once + +#include <dirsrv/slapi-plugin.h> + +#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 <dirsrv/slapi-plugin.h> +#include "otp_config.h" #include <stdbool.h> #include <stdlib.h> 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); |
