[Freeipa-devel] [PATCHES] OTP Patches

Alexander Bokovoy abokovoy at redhat.com
Mon Feb 17 17:44:49 UTC 2014


On Mon, 17 Feb 2014, Nathaniel McCallum wrote:
>>From 357cc6a40c58f3f88f8e86c5224f2c042ab974d8 Mon Sep 17 00:00:00 2001
>From: Nathaniel McCallum <npmccallum at redhat.com>
>Date: Mon, 16 Dec 2013 16:19:08 -0500
>Subject: [PATCH 2/4] Add OTP last token plugin
>
>This plugin prevents the deletion or deactivation of the last
>valid token for a user. This prevents the user from migrating
>back to single factor authentication once OTP has been enabled.
>
>Thanks to Mark Reynolds for helping me with this patch.
>---
> daemons/configure.ac                               |   1 +
> daemons/ipa-slapi-plugins/Makefile.am              |   1 +
> .../ipa-otp-lasttoken/Makefile.am                  |  28 ++++
> .../ipa-otp-lasttoken/ipa-otp-lasttoken.sym        |   1 +
> .../ipa-otp-lasttoken/ipa_otp_lasttoken.c          | 183 +++++++++++++++++++++
> .../ipa-otp-lasttoken/otp-lasttoken-conf.ldif      |  15 ++
> freeipa.spec.in                                    |   2 +
> ipaserver/install/dsinstance.py                    |   4 +
> 8 files changed, 235 insertions(+)
> create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am
> create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa-otp-lasttoken.sym
> create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c
> create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-lasttoken/otp-lasttoken-conf.ldif
>
>diff --git a/daemons/configure.ac b/daemons/configure.ac
>index e5bf7f552c0d85acc7ae14e3da05ab8c948daa93..b4507a6d972f854331925e72869898576bdfd76f 100644
>--- a/daemons/configure.ac
>+++ b/daemons/configure.ac
>@@ -314,6 +314,7 @@ AC_CONFIG_FILES([
>     ipa-slapi-plugins/ipa-dns/Makefile
>     ipa-slapi-plugins/ipa-enrollment/Makefile
>     ipa-slapi-plugins/ipa-lockout/Makefile
>+    ipa-slapi-plugins/ipa-otp-lasttoken/Makefile
>     ipa-slapi-plugins/ipa-pwd-extop/Makefile
>     ipa-slapi-plugins/ipa-extdom-extop/Makefile
>     ipa-slapi-plugins/ipa-winsync/Makefile
>diff --git a/daemons/ipa-slapi-plugins/Makefile.am b/daemons/ipa-slapi-plugins/Makefile.am
>index 40725d2259d09010d2f82381543fc77d84435040..06e6ee8b86f138cce05f2184ac98c39ffaf9757f 100644
>--- a/daemons/ipa-slapi-plugins/Makefile.am
>+++ b/daemons/ipa-slapi-plugins/Makefile.am
>@@ -7,6 +7,7 @@ SUBDIRS =			\
> 	ipa-enrollment		\
> 	ipa-lockout		\
> 	ipa-modrdn		\
>+	ipa-otp-lasttoken	\
> 	ipa-pwd-extop		\
> 	ipa-extdom-extop	\
> 	ipa-uuid		\
>diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am
>new file mode 100644
>index 0000000000000000000000000000000000000000..1e3869bfda9f8fd14cd4d93d0d466780932ac40f
>--- /dev/null
>+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am
>@@ -0,0 +1,28 @@
>+MAINTAINERCLEANFILES = *~ Makefile.in
>+PLUGIN_COMMON_DIR = ../common
>+AM_CPPFLAGS =							\
>+	-I.							\
>+	-I$(srcdir)						\
>+	-I$(srcdir)/../libotp					\
>+	-I$(PLUGIN_COMMON_DIR)					\
>+	-I/usr/include/dirsrv					\
>+	-DPREFIX=\""$(prefix)"\" 				\
>+	-DBINDIR=\""$(bindir)"\"				\
>+	-DLIBDIR=\""$(libdir)"\" 				\
>+	-DLIBEXECDIR=\""$(libexecdir)"\"			\
>+	-DDATADIR=\""$(datadir)"\"				\
>+	$(AM_CFLAGS)						\
>+	$(LDAP_CFLAGS)						\
>+	$(WARN_CFLAGS)
>+
>+plugindir = $(libdir)/dirsrv/plugins
>+plugin_LTLIBRARIES = libipa_otp_lasttoken.la
>+libipa_otp_lasttoken_la_SOURCES = ipa_otp_lasttoken.c
>+libipa_otp_lasttoken_la_LDFLAGS = -avoid-version -export-symbols ipa-otp-lasttoken.sym
>+libipa_otp_lasttoken_la_LIBADD =		\
>+	$(LDAP_LIBS)				\
>+	$(builddir)/../libotp/libotp.la
>+
>+appdir = $(IPA_DATA_DIR)
>+app_DATA = otp-lasttoken-conf.ldif
>+EXTRA_DIST = $(app_DATA)
>diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa-otp-lasttoken.sym b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa-otp-lasttoken.sym
>new file mode 100644
>index 0000000000000000000000000000000000000000..e32dc32f5693547bf604480490f42511368fdb81
>--- /dev/null
>+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa-otp-lasttoken.sym
>@@ -0,0 +1 @@
>+ipa_otp_lasttoken_init
>diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c
>new file mode 100644
>index 0000000000000000000000000000000000000000..4abeb671e29b40cdf9b005ff5bc6b12c6d91bb30
>--- /dev/null
>+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c
>@@ -0,0 +1,183 @@
>+/** 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 at redhat.com>
>+ *
>+ * Copyright (C) 2013 Red Hat, Inc.
>+ * All rights reserved.
>+ * END COPYRIGHT BLOCK **/
>+
>+#ifdef HAVE_CONFIG_H
>+#  include <config.h>
>+#endif
>+
>+#include <libotp.h>
>+#include <time.h>
>+
>+#define PLUGIN_NAME               "ipa-otp-lasttoken"
>+#define LOG(sev, ...) \
>+    slapi_log_error(SLAPI_LOG_ ## sev, PLUGIN_NAME, \
>+                    "%s: %s\n", __func__, __VA_ARGS__), -1
>+
>+static void *plugin_id;
>+static const Slapi_PluginDesc preop_desc = {
>+    PLUGIN_NAME,
>+    "FreeIPA",
>+    "FreeIPA/1.0",
>+    "Protect the user's last active token"
>+};
>+
>+static bool
>+target_is_only_enabled_token(Slapi_PBlock *pb)
>+{
>+    Slapi_DN *target_sdn = NULL;
>+    Slapi_DN *token_sdn = NULL;
>+    struct otptoken **tokens;
>+    char *user_dn = NULL;
>+    bool match;
>+
>+    /* Ignore internal operations. */
>+    if (slapi_op_internal(pb))
>+        return false;
>+
>+    /* Get the current user's SDN. */
>+    slapi_pblock_get(pb, SLAPI_CONN_DN, &user_dn);
>+    if (user_dn == NULL)
>+        return false;
>+
>+    /* Get the SDN of the only enabled token. */
>+    tokens = otptoken_find(plugin_id, user_dn, NULL, true, NULL);
>+    if (tokens != NULL && tokens[0] != NULL && tokens[1] == NULL)
>+        token_sdn = slapi_sdn_dup(otptoken_get_sdn(tokens[0]));
>+    otptoken_free_array(tokens);
>+    if (token_sdn == NULL)
>+        return false;
>+
>+    /* Get the target SDN. */
>+    slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn);
>+    if (target_sdn == NULL) {
>+        slapi_sdn_free(&token_sdn);
>+        return false;
>+    }
>+
>+    /* Does the target SDN match the only enabled token SDN? */
>+    match = slapi_sdn_compare(token_sdn, target_sdn) == 0;
>+    slapi_sdn_free(&token_sdn);
>+    return match;
>+}
>+
>+static inline int
>+send_error(Slapi_PBlock *pb, int rc, char *errstr)
>+{
>+    slapi_send_ldap_result(pb, rc, NULL, errstr, 0, NULL);
>+    slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
>+    return rc;
>+}
>+
>+static int
>+preop_del(Slapi_PBlock *pb)
>+{
>+    if (!target_is_only_enabled_token(pb))
>+        return 0;
>+
>+    return send_error(pb, LDAP_UNWILLING_TO_PERFORM,
>+                      "Can't delete last active token");
>+}
>+
>+static int
>+preop_mod(Slapi_PBlock *pb)
>+{
>+    LDAPMod **mods = NULL;
>+
>+    if (!target_is_only_enabled_token(pb))
>+        return 0;
>+
>+    /* Do not permit deactivation of the last active token. */
>+    slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
>+    for (int i = 0; mods != NULL && mods[i] != NULL; i++) {
>+        if (strcasecmp(mods[i]->mod_type, "ipatokenDisabled") == 0) {
>+            return send_error(pb, LDAP_UNWILLING_TO_PERFORM,
>+                              "Can't disable last active token");
>+        }
>+
>+        if (strcasecmp(mods[i]->mod_type, "ipatokenOwner") == 0) {
>+            return send_error(pb, LDAP_UNWILLING_TO_PERFORM,
>+                              "Can't change last active token's owner");
>+        }
>+
>+        if (strcasecmp(mods[i]->mod_type, "ipatokenNotBefore") == 0) {
>+            return send_error(pb, LDAP_UNWILLING_TO_PERFORM,
>+                              "Can't change last active token's start time");
>+        }
>+
>+        if (strcasecmp(mods[i]->mod_type, "ipatokenNotAfter") == 0) {
>+            return send_error(pb, LDAP_UNWILLING_TO_PERFORM,
>+                              "Can't change last active token's end time");
>+        }
>+    }
>+
>+    return 0;
>+}
>+
>+static int
>+preop_init(Slapi_PBlock *pb)
>+{
>+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01))
>+        goto error;
>+
>+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &preop_desc))
>+        goto error;
>+
>+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN, preop_del))
>+        goto error;
>+
>+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN, preop_mod))
>+        goto error;
>+
>+    return 0;
>+
>+error:
>+    return LOG(FATAL, "failed to register be_txn_pre_op plugin");
>+}
>+
>+int
>+ipa_otp_lasttoken_init(Slapi_PBlock *pb)
>+{
>+    slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_id);
>+
>+    if (slapi_register_plugin("betxnpreoperation", 1, __func__, preop_init,
>+                              PLUGIN_NAME, NULL, plugin_id))
>+        return LOG(FATAL, "failed to register plugin");
I think the order is wrong here and it might be the cause for those
messages I've been getting in the dirsrv error logs.

You need to fetch plugin identity, then set version and description,
set callbacks, and only then register the plugin. Finally, preop_init() will
be called and it should set the callbacks only.

-- 
/ Alexander Bokovoy




More information about the Freeipa-devel mailing list