On Wed, 15 Jun 2016, thierry bordaz wrote:
From 6cd06b9004f8ab72e13c26742d11ee31d30bbc79 Mon Sep 17 00:00:00 2001
From: Thierry Bordaz <tbor...@redhat.com>
Date: Mon, 13 Jun 2016 18:13:04 +0200
Subject: [PATCH] slapi-nis should allow password update on a virtual entry

During password modification ext. op (1.3.6.1.4.1.4203.1.11.1),
if the target entry is in the compat tree, slapi-nis should
remap the entry to the real entry.

This needs to be done in a pre-op extop that calls the callback
function handling a given OID.
The password mod. callback does a reverse mapping of
extop USERID and set it in SLAPI_TARGET_SDN.
---
configure.ac   |   1 +
src/back-sch.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/back-sch.h |  16 +++++
src/plug-sch.c |  24 +++++++
4 files changed, 258 insertions(+)

diff --git a/configure.ac b/configure.ac
index 5b10376..9ce6bcf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -113,6 +113,7 @@ dirsrv)
                        SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN,
                        SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN,
                        SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN,
+                       SLAPI_PLUGIN_PRE_EXTOP_FN,
                        NULL]
                       ,,,
                       [AC_INCLUDES_DEFAULT
diff --git a/src/back-sch.c b/src/back-sch.c
index 32b1d9e..f9ab812 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -54,6 +54,8 @@
#include "map.h"
#include "back-sch.h"

+backend_extop_handlers_t extop_handlers[] = {{EXTOP_PASSWD_OID, (IFP) backend_passwdmod_extop}, + {NULL, NULL}};
static void
backend_entries_to_return_push(struct backend_search_cbdata *cbdata, 
Slapi_Entry *e);

@@ -2223,6 +2225,203 @@ done_with_lock:
        return ret;
}

+/* This callback handles EXTOP_PASSWD_OID "1.3.6.1.4.1.4203.1.11.1"
+ * If the extop defines a USERID, it sets SLAPI_TARGET_SDN to
+ * the reverse mapping of the USERID.
+ *
+ * If it is not possible to retrieve USERID in the ber
+ * then value of SLAPI_TARGET_SDN is unchanged.
+ *
+ * Else the value of SLAPI_TARGET_SDN is freed and replaced
+ * either by the USERID or the reverse mapping of USERID (if it exists)
+ */
+static int
+backend_passwdmod_extop(Slapi_PBlock *pb)
+{
+       struct backend_entry_data *data;
+       struct plugin_state *state;
+       Slapi_DN *sdn = NULL;
+       char *extopdn;
+       char *ndn;
+       char *username = NULL;
+       char *group = NULL;
+       const char *entry_group = NULL;
+       char *set = NULL;
+       const char *entry_set = NULL;
+       struct berval   *extop_value = NULL;
+       BerElement      *ber = NULL;
+       ber_tag_t       tag = 0;
+        ber_len_t      len = (ber_len_t) -1;
+       
+       if (wrap_get_call_level() > 0) {
+               return 0;
+       }
+
+       slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+       if (state->ready_to_serve == 0) {
+               /* No data to serve yet */
+               goto free_and_return;
+       }
+       /* Retrieve the original DN from the ber request */
+       /* Get the ber value of the extended operation */
+       slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+       if (!BV_HAS_DATA(extop_value)) {
+               goto free_and_return;
+       }
+
+        if ((ber = ber_init(extop_value)) == NULL) {
+               goto free_and_return;
+       }
+ + /* Format of request to parse
+        *
+        * PasswdModifyRequestValue ::= SEQUENCE {
+        * userIdentity    [0]  OCTET STRING OPTIONAL
+        * oldPasswd       [1]  OCTET STRING OPTIONAL
+        * newPasswd       [2]  OCTET STRING OPTIONAL }
+        *
+        * The request value field is optional. If it is
+        * provided, at least one field must be filled in.
+        */
+
+       /* ber parse code */
+       if ( ber_scanf( ber, "{") == LBER_ERROR ) {
+               /* The request field wasn't provided.  We'll
+                * now try to determine the userid and verify
+                * knowledge of the old password via other
+                * means.
+                */
+               goto free_and_return;
+       } else {
+               tag = ber_peek_tag( ber, &len);
+       }
+
+       /* identify userID field by tags */
+       if (tag == LDAP_EXTOP_PASSMOD_TAG_USERID ) {
+
+               if ( ber_scanf( ber, "a", &extopdn) == LBER_ERROR ) {
+                       slapi_ch_free_string(&extopdn);
+                       goto free_and_return;
+               }
+
+                slapi_log_error(SLAPI_LOG_PLUGIN, "backend_passwdmod_extop",
+                       "extopdn = %s\n", extopdn ? extopdn : "<unknown>" );
+               
+               /* Free the current target_DN */
+               slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
+               if (sdn) {
+                       const char *olddn;
+                       olddn = slapi_sdn_get_ndn(sdn);
+                       slapi_log_error(SLAPI_LOG_PLUGIN, 
"backend_passwdmod_extop",
+                                                         "olddn = %s (unknown expected)\n", 
olddn ? olddn : "<unknown>" );
+                       slapi_sdn_free(&sdn);
+               }
+
+               /* replace it with the one in the extop req*/
+               sdn = slapi_sdn_new_dn_byref(extopdn);
+               slapi_pblock_set(pb, SLAPI_TARGET_SDN, sdn);
+       } else {
+               /* we can not retrieve the USERID */
+               goto free_and_return;
+       }
+       
+       wrap_inc_call_level();
+       if (map_rdlock() != 0) {
+               slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
+                               "backend_passwdmod_extop unable to acquire read 
lock\n");
+               wrap_dec_call_level();
+               goto free_and_return;
+       }
+       backend_locate(pb, &data, &entry_group, &entry_set);
+       if (data != NULL) {
+               /* If there is a mapping to a real entry
+                * ndn will contains its DN
+                */
+               if (slapi_sdn_get_ndn(data->original_entry_dn)) {
+                       ndn = 
slapi_ch_strdup(slapi_sdn_get_ndn(data->original_entry_dn));
+               } else {
+                       ndn = NULL;
+               }
+               slapi_log_error(SLAPI_LOG_PLUGIN, "backend_passwdmod_extop",
+                               "reverse mapped dn = %s\n", ndn ? ndn : 
"<unknown>" );
+
+               username = slapi_entry_attr_get_charptr(data->e, "uid");
+               group = slapi_ch_strdup(entry_group);
+               set = slapi_ch_strdup(entry_set);
You don't use username/group/set anywhere, just remove them.

+               
+               /* the rest does not require to hold the map lock */
+               map_unlock();
+               wrap_dec_call_level();
+
+               if (ndn) {
+                       /* replace the TARGET_SDN by the one found in the map
+                        * This is the responsibility of the extop to free it
+                        */
+                       slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
+                       if (sdn != NULL) {
+                               slapi_sdn_free(&sdn);
+                       }
+                       sdn = slapi_sdn_new_dn_byref(ndn);
+                       slapi_pblock_set(pb, SLAPI_TARGET_SDN, (void*) sdn);
+               }
+
+               /* We are not really interested in those info, just free them */
+               slapi_ch_free_string(&set);
+               slapi_ch_free_string(&group);
+               slapi_ch_free_string(&username);
and here.

+       } else {
+               /* no mapping entry to real entry, this is fine */
+               map_unlock();
+               wrap_dec_call_level();
+       }
+       
+free_and_return:
+       
+       if ( ber != NULL ){
+               ber_free(ber, 1);
+               ber = NULL;
+       }
+       return 0;
+}
+static int
+backend_extop_cb(Slapi_PBlock *pb)
+{
+       struct plugin_state *state;
+       int ret;
+       int i;
+       char *oid = NULL;
+       IFP fct = NULL;
+
+       slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+       if (state->ready_to_serve == 0) {
+               /* No data to serve yet */
+               return 0;
+       }
+       
+       /* First check this is a supported OID (for slapi-nis) */
+       if ( slapi_pblock_get( pb, SLAPI_EXT_OP_REQ_OID, &oid ) != 0 )
+       {
+               slapi_log_error( SLAPI_LOG_FATAL, state->plugin_desc->spd_id, "Could 
not get OID from request\n" );
+               return 0;
+       }
+       
+       for (i = 0; extop_handlers[i].oid != NULL; i++) {
+               if (strcmp( oid, extop_handlers[i].oid) == 0 ) {
+                       fct = extop_handlers[i].extop_fct;
+                       break;
+               }
+       }
+       
+       if (fct) {
+               ret = fct(pb);
+               if (ret) {
+ slapi_log_error( SLAPI_LOG_FATAL, "backend_extop_cb", + "pre-extop for %s failed %d\n", oid, ret );
+               }
+       }
+       return (ret);
+}
+
static int
backend_compare_cb(Slapi_PBlock *pb)
{
@@ -2286,6 +2485,24 @@ backend_shutdown(struct plugin_state *state)
    backend_shr_shutdown(state);
}

+#ifndef SLAPI_PLUGIN_PRE_EXTOP_FN
+#define SLAPI_PLUGIN_PRE_EXTOP_FN  413
+#endif
+int
+backend_init_extop(Slapi_PBlock *pb, struct plugin_state *state)
+{
+       slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+                       "hooking up extop callbacks\n");
+       /* Intercept extended operation requests */
+       if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_EXTOP_FN,
+                            backend_extop_cb) != 0) {
+               slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+                               "error hooking up pre extop callback\n");
+               return -1;
+       }
+       return 0;
+}
+
int
backend_init_preop(Slapi_PBlock *pb, struct plugin_state *state)
{
diff --git a/src/back-sch.h b/src/back-sch.h
index e8ec400..72ba641 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -127,6 +127,22 @@ struct backend_search_filter_config {
        void *callback_data;
};

+/* OIDs of the supported extended operation */
+#define EXTOP_PASSWD_OID       "1.3.6.1.4.1.4203.1.11.1"
+
+/* ber tags for the PasswdModifyRequestValue sequence */
+#define LDAP_EXTOP_PASSMOD_TAG_USERID  0x80U
+#define LDAP_EXTOP_PASSMOD_TAG_OLDPWD  0x81U
+#define LDAP_EXTOP_PASSMOD_TAG_NEWPWD  0x82U
+
+typedef int (*IFP)();
+static int backend_passwdmod_extop(Slapi_PBlock *pb);
+typedef struct backend_extop_handlers {
+    char *oid;
+    IFP extop_fct;
+} backend_extop_handlers_t;
+
+
/* Analyzes the filter to decide what kind of NSS search is it
 * Returns 0 on success, 1 on failure
 * struct backend_search_filter_config is populated with information about the 
filter
diff --git a/src/plug-sch.c b/src/plug-sch.c
index 7af8480..00e7041 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -65,6 +65,7 @@
#define PLUGIN_BETXN_POSTOP_ID PLUGIN_ID "-betxn_postop"
#define PLUGIN_POSTOP_ID PLUGIN_ID "-postop"
#define PLUGIN_INTERNAL_POSTOP_ID PLUGIN_ID "-internal-postop"
+#define PLUGIN_PRE_EXTOP_ID PLUGIN_ID "-extop-preop"

/* the module initialization function */
static Slapi_PluginDesc
@@ -185,6 +186,20 @@ plugin_shutdown(Slapi_PBlock *pb)
                        "plugin shutdown completed\n");
        return 0;
}
+static int
+schema_compat_plugin_init_extop(Slapi_PBlock *pb)
+{
+       slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
+       slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description);
+       slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, global_plugin_state);
+       if (backend_init_extop(pb, global_plugin_state) == -1) {
+               slapi_log_error(SLAPI_LOG_PLUGIN,
+                               global_plugin_state->plugin_desc->spd_id,
+                               "error registering extop hooks\n");
+               return -1;
+       }
+       return 0;
+}

static int
schema_compat_plugin_init_preop(Slapi_PBlock *pb)
@@ -343,6 +358,15 @@ schema_compat_plugin_init(Slapi_PBlock *pb)
                return -1;
        }
#endif
+       if (slapi_register_plugin("preextendedop", TRUE,
+                                 "schema_compat_plugin_init_extop",
+                                 schema_compat_plugin_init_extop,
+                                 PLUGIN_PRE_EXTOP_ID, NULL,
+                                 state->plugin_identity) != 0) {
+               slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+                               "error registering extop plugin\n");
+               return -1;
+       }
        slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
                        "registered plugin hooks\n");
        global_plugin_state = NULL;
--
2.5.0



--
/ Alexander Bokovoy

--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to