Users that can rename the token (such as admins) can also create
non-UUID token names.

https://fedorahosted.org/freeipa/ticket/4456

NOTE: this patch is an alternate approach to my patch 0065. This version
has two main advantages compared to 0065:
1. Permissions are more flexible (not tied to the admin group).
2. Enforcement occurs at the DS-level

It should also be noted that this patch does not enforce UUID
randomness, only syntax. Users can still specify a token ID so long as
it is in UUID format.

Nathaniel
From aed2d3705a050d24119d2b5124088dfcb76b81d7 Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccal...@redhat.com>
Date: Sun, 21 Sep 2014 14:58:32 -0400
Subject: [PATCH] Adds 389DS plugin to enforce UUID token IDs

Users that can rename the token (such as admins) can also create
non-UUID token names.

https://fedorahosted.org/freeipa/ticket/4456
---
 daemons/configure.ac                               |   1 +
 daemons/ipa-slapi-plugins/Makefile.am              |   1 +
 .../ipa-slapi-plugins/ipa-otp-tokenid/Makefile.am  |  25 +++
 .../ipa-otp-tokenid/ipa-otp-tokenid.sym            |   1 +
 .../ipa-otp-tokenid/ipa_otp_tokenid.c              | 206 +++++++++++++++++++++
 .../ipa-otp-tokenid/otp-tokenid-conf.ldif          |  15 ++
 freeipa.spec.in                                    |   2 +
 ipaserver/install/dsinstance.py                    |   4 +
 8 files changed, 255 insertions(+)
 create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-tokenid/Makefile.am
 create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa-otp-tokenid.sym
 create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa_otp_tokenid.c
 create mode 100644 daemons/ipa-slapi-plugins/ipa-otp-tokenid/otp-tokenid-conf.ldif

diff --git a/daemons/configure.ac b/daemons/configure.ac
index b4507a6d972f854331925e72869898576bdfd76f..55636c9dd62985e54b6bb4599211d96001582d1e 100644
--- a/daemons/configure.ac
+++ b/daemons/configure.ac
@@ -315,6 +315,7 @@ AC_CONFIG_FILES([
     ipa-slapi-plugins/ipa-enrollment/Makefile
     ipa-slapi-plugins/ipa-lockout/Makefile
     ipa-slapi-plugins/ipa-otp-lasttoken/Makefile
+    ipa-slapi-plugins/ipa-otp-tokenid/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 06e6ee8b86f138cce05f2184ac98c39ffaf9757f..08ce230686ca4dd16c15f08c40826aefd7023bd8 100644
--- a/daemons/ipa-slapi-plugins/Makefile.am
+++ b/daemons/ipa-slapi-plugins/Makefile.am
@@ -8,6 +8,7 @@ SUBDIRS =			\
 	ipa-lockout		\
 	ipa-modrdn		\
 	ipa-otp-lasttoken	\
+	ipa-otp-tokenid	\
 	ipa-pwd-extop		\
 	ipa-extdom-extop	\
 	ipa-uuid		\
diff --git a/daemons/ipa-slapi-plugins/ipa-otp-tokenid/Makefile.am b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..4889af554c001433b41f7b9e08aa2628e38b6bc7
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/Makefile.am
@@ -0,0 +1,25 @@
+MAINTAINERCLEANFILES = *~ Makefile.in
+PLUGIN_COMMON_DIR = ../common
+AM_CPPFLAGS =							\
+	-I.							\
+	-I$(srcdir)						\
+	-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_tokenid.la
+libipa_otp_tokenid_la_SOURCES = ipa_otp_tokenid.c
+libipa_otp_tokenid_la_LDFLAGS = -avoid-version -export-symbols ipa-otp-tokenid.sym
+libipa_otp_tokenid_la_LIBADD = $(LDAP_LIBS)
+
+appdir = $(IPA_DATA_DIR)
+app_DATA = otp-tokenid-conf.ldif
+EXTRA_DIST = $(app_DATA)
diff --git a/daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa-otp-tokenid.sym b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa-otp-tokenid.sym
new file mode 100644
index 0000000000000000000000000000000000000000..ed6aaa999928c833cfe13f95a3bd0d273b5fcd86
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa-otp-tokenid.sym
@@ -0,0 +1 @@
+ipa_otp_tokenid_init
diff --git a/daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa_otp_tokenid.c b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa_otp_tokenid.c
new file mode 100644
index 0000000000000000000000000000000000000000..8778ed3aadda98e5beef51b3d06b047b01821f6c
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/ipa_otp_tokenid.c
@@ -0,0 +1,206 @@
+/** 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 <npmccal...@redhat.com>
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <slapi-plugin.h>
+#include <stdbool.h>
+#include <plstr.h>
+
+static int
+send_error(Slapi_PBlock *pb, int rc, char *msg)
+{
+    slapi_send_ldap_result(pb, rc, NULL, msg, 0, NULL);
+    slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
+    return rc;
+}
+
+static bool
+is_token(Slapi_Entry *entry)
+{
+    char **clsses = slapi_entry_attr_get_charray(entry, "objectClass");
+    for (size_t i = 0; clsses != NULL && clsses[i] != NULL; i++) {
+        if (PL_strcasecmp("ipaToken", clsses[i]) == 0)
+            return true;
+    }
+
+    slapi_ch_array_free(clsses);
+    return false;
+}
+
+static bool
+is_hex(char c)
+{
+    switch (c) {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case 'a':
+    case 'b':
+    case 'c':
+    case 'd':
+    case 'e':
+    case 'f':
+        return true;
+    default:
+        return false;
+    }
+}
+
+static bool
+is_hex_group(const char **str, size_t n, char c)
+{
+    for (size_t i = 0; i < n; i++) {
+        if (!is_hex(*(*str)++))
+            return false;
+    }
+
+    return *(*str)++ == c;
+}
+
+static bool
+is_uuid(const char *str, ...)
+{
+    if (!is_hex_group(&str, 8, '-'))
+        return false;
+
+    if (!is_hex_group(&str, 4, '-'))
+        return false;
+
+    if (!is_hex_group(&str, 4, '-'))
+        return false;
+
+    if (!is_hex_group(&str, 4, '-'))
+        return false;
+
+    return is_hex_group(&str, 12, '\0');
+}
+
+static int
+preop_add(Slapi_PBlock *pb)
+{
+    Slapi_Entry *entry = NULL;
+    int is_repl_op = 0;
+    char *id;
+
+    /* Bypass replication operations. */
+    slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_repl_op);
+    if (is_repl_op)
+        return 0;
+
+    /* Get the entry to be added. */
+    slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &entry);
+    if (entry == NULL)
+        return 0;
+
+    /* Ensure this is a token. */
+    if (!is_token(entry))
+        return 0;
+
+    /* Get the ID. */
+    id = slapi_entry_attr_get_charptr(entry, "ipatokenUniqueID");
+    if (id == NULL)
+        return 0;
+
+    /* Don't block operations that are in UUID format. */
+    if (is_uuid(id)) {
+        slapi_ch_free_string(&id);
+        return 0;
+    }
+
+    /* Non-UUIDs are allowed if the write ACI passes. */
+    slapi_ch_free_string(&id);
+    if (slapi_access_allowed(pb, entry, "ipatokenUniqueID",
+                             NULL, SLAPI_ACL_WRITE) == LDAP_SUCCESS)
+        return 0;
+
+    return send_error(pb, LDAP_INSUFFICIENT_ACCESS,
+                      "ipatokenUniqueID must be a UUID");
+}
+
+static int
+preop_init(Slapi_PBlock *pb)
+{
+    return slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN, preop_add);
+}
+
+static int
+start_fn(Slapi_PBlock *pb)
+{
+    return 0;
+}
+
+static int
+close_fn(Slapi_PBlock *pb)
+{
+    return 0;
+}
+
+int
+ipa_otp_tokenid_init(Slapi_PBlock *pb)
+{
+    static const Slapi_PluginDesc preop_desc = {
+        "ipa-otp-tokenid",
+        "FreeIPA",
+        "FreeIPA/1.0",
+        "Only permit UUID token IDs for normal users"
+    };
+
+    void *plugin_id;
+    int ret = 0;
+
+    ret |= slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_id);
+    ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+    ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &preop_desc);
+    ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, start_fn);
+    ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, close_fn);
+    ret |= slapi_register_plugin("betxnpreoperation", 1, __func__, preop_init,
+                                 preop_desc.spd_id, NULL, plugin_id);
+
+    return ret;
+}
diff --git a/daemons/ipa-slapi-plugins/ipa-otp-tokenid/otp-tokenid-conf.ldif b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/otp-tokenid-conf.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..9843a497f3d836840eed09643b92369c2f204ecc
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-otp-tokenid/otp-tokenid-conf.ldif
@@ -0,0 +1,15 @@
+dn: cn=IPA OTP Token ID,cn=plugins,cn=config
+changetype: add
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: IPA OTP Token ID
+nsslapd-pluginpath: libipa_otp_tokenid
+nsslapd-plugininitfunc: ipa_otp_tokenid_init
+nsslapd-plugintype: preoperation
+nsslapd-pluginenabled: on
+nsslapd-pluginid: ipa-otp-tokenid
+nsslapd-pluginversion: 1.0
+nsslapd-pluginvendor: Red Hat, Inc.
+nsslapd-plugindescription: IPA OTP Token ID plugin
+nsslapd-plugin-depends-on-type: database
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 685b345fedb9d157c8deedc66f8712da32c5963b..d656cf71da713371b423cc4b1cdb20b41886baa3 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -349,6 +349,7 @@ rm %{buildroot}/%{plugin_dir}/libipa_sidgen_task.la
 rm %{buildroot}/%{plugin_dir}/libipa_extdom_extop.la
 rm %{buildroot}/%{plugin_dir}/libipa_range_check.la
 rm %{buildroot}/%{plugin_dir}/libipa_otp_lasttoken.la
+rm %{buildroot}/%{plugin_dir}/libipa_otp_tokenid.la
 rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la
 rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la
 
@@ -698,6 +699,7 @@ fi
 %attr(755,root,root) %{plugin_dir}/libipa_dns.so
 %attr(755,root,root) %{plugin_dir}/libipa_range_check.so
 %attr(755,root,root) %{plugin_dir}/libipa_otp_lasttoken.so
+%attr(755,root,root) %{plugin_dir}/libipa_otp_tokenid.so
 %dir %{_localstatedir}/lib/ipa
 %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/backup
 %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 0518dd0e0f20255f4e42911af6f1f95fc25f554e..4463a95b06214701fb66d0a8754898a436c2ac66 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -277,6 +277,7 @@ class DsInstance(service.Service):
         self.step("enabling entryUSN plugin", self.__enable_entryusn)
         self.step("configuring lockout plugin", self.__config_lockout_module)
         self.step("configuring OTP last token plugin", self.__config_otp_lasttoken_module)
+        self.step("configuring OTP token ID plugin", self.__config_otp_tokenid_module)
         self.step("creating indices", self.__create_indices)
         self.step("enabling referential integrity plugin", self.__add_referint_module)
         if enable_ssl:
@@ -591,6 +592,9 @@ class DsInstance(service.Service):
     def __config_otp_lasttoken_module(self):
         self._ldap_mod("otp-lasttoken-conf.ldif")
 
+    def __config_otp_tokenid_module(self):
+        self._ldap_mod("otp-tokenid-conf.ldif")
+
     def __repoint_managed_entries(self):
         self._ldap_mod("repoint-managed-entries.ldif", self.sub_dict)
 
-- 
2.1.0

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to