]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/rwm.c
more about ITS#5940
[openldap] / servers / slapd / overlays / rwm.c
index f9301ccf9fc846ccacb3a303745e230098d9ca98..8f81e040b5d647692275f228056652383dc8b0c0 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2008 The OpenLDAP Foundation.
+ * Copyright 2003-2009 The OpenLDAP Foundation.
  * Portions Copyright 2003 Pierangelo Masarati.
  * All rights reserved.
  *
@@ -38,14 +38,17 @@ typedef struct rwm_op_state {
        OpRequest o_request;
 } rwm_op_state;
 
-static int
-rwm_db_destroy( BackendDB *be, ConfigReply *cr );
-
 typedef struct rwm_op_cb {
        slap_callback cb;
        rwm_op_state ros;
 } rwm_op_cb;
 
+static int
+rwm_db_destroy( BackendDB *be, ConfigReply *cr );
+
+static int
+rwm_send_entry( Operation *op, SlapReply *rs );
+
 static void
 rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
 {
@@ -93,6 +96,12 @@ rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
                        op->orr_newSup = ros->orr_newSup;
                        op->orr_nnewSup = ros->orr_nnewSup;
                }
+               if ( op->orr_newrdn.bv_val != ros->orr_newrdn.bv_val ) {
+                       ch_free( op->orr_newrdn.bv_val );
+                       ch_free( op->orr_nnewrdn.bv_val );
+                       op->orr_newrdn = ros->orr_newrdn;
+                       op->orr_nnewrdn = ros->orr_nnewrdn;
+               }
                break;
        case LDAP_REQ_SEARCH:
                ch_free( ros->mapped_attrs );
@@ -681,11 +690,11 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
                        (struct ldaprwmap *)on->on_bi.bi_private;
        
        int                     rc;
+       dncookie                dc;
 
        rwm_op_cb               *roc = rwm_callback_get( op, rs );
 
        if ( op->orr_newSup ) {
-               dncookie        dc;
                struct berval   nnewSup = BER_BVNULL;
                struct berval   newSup = BER_BVNULL;
 
@@ -715,6 +724,32 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
                }
        }
 
+       /*
+        * Rewrite the newRDN, if needed
+        */
+       {
+               struct berval   newrdn = BER_BVNULL;
+               struct berval   nnewrdn = BER_BVNULL;
+
+               dc.rwmap = rwmap;
+               dc.conn = op->o_conn;
+               dc.rs = rs;
+               dc.ctx = "newRDN";
+               newrdn = op->orr_newrdn;
+               nnewrdn = op->orr_nnewrdn;
+               rc = rwm_dn_massage_pretty_normalize( &dc, &op->orr_newrdn, &newrdn, &nnewrdn );
+               if ( rc != LDAP_SUCCESS ) {
+                       op->o_bd->bd_info = (BackendInfo *)on->on_info;
+                       send_ldap_error( op, rs, rc, "newRDN massage error" );
+                       goto err;
+               }
+
+               if ( op->orr_newrdn.bv_val != newrdn.bv_val ) {
+                       op->orr_newrdn = newrdn;
+                       op->orr_nnewrdn = nnewrdn;
+               }
+       }
+
        /*
         * Rewrite the dn, if needed
         */
@@ -722,6 +757,15 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
        if ( rc != LDAP_SUCCESS ) {
                op->o_bd->bd_info = (BackendInfo *)on->on_info;
                send_ldap_error( op, rs, rc, "renameDN massage error" );
+               goto err;
+       }
+
+       op->o_callback = &roc->cb;
+
+       rc = SLAP_CB_CONTINUE;
+
+       if ( 0 ) {
+err:;
                if ( op->orr_newSup != roc->ros.orr_newSup ) {
                        ch_free( op->orr_newSup->bv_val );
                        ch_free( op->orr_nnewSup->bv_val );
@@ -730,15 +774,16 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
                        op->orr_newSup = roc->ros.orr_newSup;
                        op->orr_nnewSup = roc->ros.orr_nnewSup;
                }
-               return -1;
-       }
 
-       /* TODO: rewrite newRDN, attribute types, 
-        * values of DN-valued attributes ... */
-
-       op->o_callback = &roc->cb;
+               if ( op->orr_newrdn.bv_val != roc->ros.orr_newrdn.bv_val ) {
+                       ch_free( op->orr_newrdn.bv_val );
+                       ch_free( op->orr_nnewrdn.bv_val );
+                       op->orr_newrdn = roc->ros.orr_newrdn;
+                       op->orr_nnewrdn = roc->ros.orr_nnewrdn;
+               }
+       }
 
-       return SLAP_CB_CONTINUE;
+       return rc;
 }
 
 
@@ -758,6 +803,97 @@ rwm_swap_attrs( Operation *op, SlapReply *rs )
        return SLAP_CB_CONTINUE;
 }
 
+/*
+ * NOTE: this implementation of get/release entry is probably far from
+ * optimal.  The rationale consists in intercepting the request directed
+ * to the underlying database, in order to rewrite/remap the request,
+ * perform it using the modified data, duplicate the resulting entry
+ * and finally free it when release is called.
+ * This implies that subsequent overlays are not called, as the request
+ * is directly shunted to the underlying database.
+ */
+static int
+rwm_entry_release_rw( Operation *op, Entry *e, int rw )
+{
+       slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
+
+       /* can't be ours */
+       if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       /* just free entry if (probably) ours */
+       if ( e->e_private == NULL ) {
+               entry_free( e );
+               return LDAP_SUCCESS;
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+rwm_entry_get_rw( Operation *op, struct berval *ndn,
+       ObjectClass *oc, AttributeDescription *at, int rw, Entry **ep )
+{
+       slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
+       struct ldaprwmap        *rwmap = 
+                       (struct ldaprwmap *)on->on_bi.bi_private;
+
+       int                     rc;
+       dncookie                dc;
+
+       BackendDB               db;
+       Operation               op2;
+       SlapReply               rs = { REP_SEARCH };
+
+       rwm_op_state            ros = { 0 };
+
+       if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       /* massage DN */
+       op2.o_tag = LDAP_REQ_SEARCH;
+       op2 = *op;
+       op2.o_req_dn = *ndn;
+       op2.o_req_ndn = *ndn;
+       rc = rwm_op_dn_massage( &op2, &rs, "searchDN", &ros );
+       if ( rc != LDAP_SUCCESS ) {
+               return LDAP_OTHER;
+       }
+
+       /* map attribute & objectClass */
+       if ( at != NULL ) {
+       }
+
+       if ( oc != NULL ) {
+       }
+
+       /* fetch entry */
+       db = *op->o_bd;
+       op2.o_bd = &db;
+       op2.o_bd->bd_info = (BackendInfo *)on->on_info->oi_orig;
+       op2.ors_attrs = slap_anlist_all_attributes;
+       rc = op2.o_bd->bd_info->bi_entry_get_rw( &op2, &ros.r_ndn, oc, at, rw, ep );
+       if ( rc == LDAP_SUCCESS && *ep != NULL ) {
+               rs.sr_entry = *ep;
+
+               /* duplicate & release */
+               op2.o_bd->bd_info = (BackendInfo *)on;
+               rc = rwm_send_entry( &op2, &rs );
+               if ( rc == SLAP_CB_CONTINUE ) {
+                       *ep = rs.sr_entry;
+                       rc = LDAP_SUCCESS;
+               }
+       }
+
+       if ( ros.r_ndn.bv_val != ndn->bv_val ) {
+               op->o_tmpfree( ros.r_ndn.bv_val, op->o_tmpmemctx );
+       }
+
+       return rc;
+}
+
 static int
 rwm_op_search( Operation *op, SlapReply *rs )
 {
@@ -1177,7 +1313,9 @@ remove_oc:;
                                        last--;
                                        bv--;
 
-                               } else if ( mapped.bv_val != bv[0].bv_val ) {
+                               } else if ( mapped.bv_val != bv[0].bv_val
+                                       && ber_bvstrcasecmp( &mapped, &bv[0] ) != 0 )
+                               {
                                        int     i;
 
                                        for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
@@ -1223,7 +1361,7 @@ remove_oc:;
                                || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
                {
                        dc.ctx = "searchAttrDN";
-                       rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
+                       rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals, (*ap)->a_nvals );
                        if ( rc != LDAP_SUCCESS ) {
                                goto cleanup_attr;
                        }
@@ -1692,7 +1830,6 @@ rwm_db_config(
 enum {
        /* rewrite */
        RWM_CF_REWRITE = 1,
-       RWM_CF_SUFFIXMASSAGE,
 
        /* map */
        RWM_CF_MAP,
@@ -1703,8 +1840,10 @@ enum {
 };
 
 static slap_verbmasks t_f_mode[] = {
+       { BER_BVC( "true" ),            RWM_F_SUPPORT_T_F },
        { BER_BVC( "yes" ),             RWM_F_SUPPORT_T_F },
        { BER_BVC( "discover" ),        RWM_F_SUPPORT_T_F_DISCOVER },
+       { BER_BVC( "false" ),           RWM_F_NONE },
        { BER_BVC( "no" ),              RWM_F_NONE },
        { BER_BVNULL,                   0 }
 };
@@ -1714,7 +1853,7 @@ static ConfigDriver rwm_cf_gen;
 static ConfigTable rwmcfg[] = {
        { "rwm-rewrite", "rewrite",
                2, 0, STRLENOF("rwm-rewrite"),
-               ARG_MAGIC|ARG_QUOTE|RWM_CF_REWRITE, rwm_cf_gen,
+               ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
                "( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
                        "DESC 'Rewrites strings' "
                        "EQUALITY caseIgnoreMatch "
@@ -1723,7 +1862,7 @@ static ConfigTable rwmcfg[] = {
                NULL, NULL },
 
        { "rwm-suffixmassage", "[virtual]> <real",
-               2, 3, 0, ARG_MAGIC|RWM_CF_SUFFIXMASSAGE, rwm_cf_gen,
+               2, 3, 0, ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
                NULL, NULL, NULL },
                
        { "rwm-t-f-support", "true|false|discover",
@@ -1808,6 +1947,53 @@ slap_rewrite_unparse( BerVarray in, BerVarray *out )
        *out = bva;
 }
 
+static int
+rwm_bva_rewrite_add(
+       struct ldaprwmap        *rwmap,
+       const char              *argv[] )
+{
+       char            *line;
+       struct berval   bv;
+
+       line = ldap_charray2str( argv, "\" \"" );
+       if ( line != NULL ) {
+               int     len = strlen( argv[ 0 ] );
+
+               ber_str2bv( line, 0, 0, &bv );
+               AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
+                       bv.bv_len - ( len + 1 ) );
+               bv.bv_val[ bv.bv_len - 1 ] = '"';
+               ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
+       }
+
+       return 0;
+}
+
+static int
+rwm_info_init( struct ldaprwmap *rwmap )
+{
+       char                    *rargv[ 3 ];
+
+       rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
+       if ( rwmap->rwm_rw == NULL ) {
+               return -1;
+       }
+
+       /* this rewriteContext by default must be null;
+        * rules can be added if required */
+       rargv[ 0 ] = "rewriteContext";
+       rargv[ 1 ] = "searchFilter";
+       rargv[ 2 ] = NULL;
+       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
+
+       rargv[ 0 ] = "rewriteContext";
+       rargv[ 1 ] = "default";
+       rargv[ 2 ] = NULL;
+       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
+
+       return 0;
+}
+
 static int
 rwm_cf_gen( ConfigArgs *c )
 {
@@ -1817,6 +2003,7 @@ rwm_cf_gen( ConfigArgs *c )
 
        BackendDB               db;
        char                    *argv0;
+       int                     idx0 = 0;
        int                     rc = 0;
 
        db = *c->be;
@@ -1874,7 +2061,6 @@ rwm_cf_gen( ConfigArgs *c )
                switch ( c->type ) {
                case RWM_CF_REWRITE:
                        if ( c->valx >= 0 ) {
-                               /* single modification is not allowed */
                                rc = 1;
 
                        } else if ( rwmap->rwm_rw != NULL ) {
@@ -1883,6 +2069,8 @@ rwm_cf_gen( ConfigArgs *c )
 
                                ber_bvarray_free( rwmap->rwm_bva_rewrite );
                                rwmap->rwm_bva_rewrite = NULL;
+
+                               rc = rwm_info_init( rwmap );
                        }
                        break;
 
@@ -1921,59 +2109,35 @@ rwm_cf_gen( ConfigArgs *c )
                return rc;
        }
 
+       if ( strncasecmp( c->argv[ 0 ], "olcRwm", STRLENOF( "olcRwm" ) ) == 0 ) {
+               idx0 = 1;
+       }
+
        switch ( c->type ) {
        case RWM_CF_REWRITE:
-               argv0 = c->argv[ 0 ];
-               c->argv[ 0 ] += STRLENOF( "rwm-" );
-               rc = rwm_rw_config( &db, c->fname, c->lineno, c->argc, c->argv );
-               c->argv[ 0 ] = argv0;
-               if ( rc ) {
+               if ( c->valx >= 0 ) {
                        return 1;
+               }
 
-               } else {
-                       char            *line;
-                       struct berval   bv;
-
-                       line = ldap_charray2str( c->argv, "\" \"" );
-                       if ( line != NULL ) {
-                               int     len = strlen( c->argv[ 0 ] );
-
-                               ber_str2bv( line, 0, 0, &bv );
-                               AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
-                                       bv.bv_len - ( len + 1 ) );
-                               bv.bv_val[ bv.bv_len - 1 ] = '"';
-                               ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
-                       }
+               argv0 = c->argv[ idx0 ];
+               if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
+                       return 1;
                }
-               break;
+               c->argv[ idx0 ] += STRLENOF( "rwm-" );
+               if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
+                       rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
+                               c->argc - idx0, &c->argv[ idx0 ] );
 
-       case RWM_CF_SUFFIXMASSAGE:
-               argv0 = c->argv[ 0 ];
-               c->argv[ 0 ] += STRLENOF( "rwm-" );
-               rc = rwm_suffixmassage_config( &db, c->fname, c->lineno, c->argc, c->argv );
-               c->argv[ 0 ] = argv0;
+               } else {
+                       rc = rwm_rw_config( &db, c->fname, c->lineno,
+                               c->argc - idx0, &c->argv[ idx0 ] );
+               }
+               c->argv[ idx0 ] = argv0;
                if ( rc ) {
                        return 1;
 
                } else {
-                       char            *line;
-                       struct berval   bv;
-
-                       /* FIXME: not optimal; in fact, this keeps track
-                        * of the fact that a set of rules was added
-                        * using the rwm-suffixmassage shortcut, but the
-                        * rules are not clarified */
-
-                       line = ldap_charray2str( c->argv, "\" \"" );
-                       if ( line != NULL ) {
-                               int     len = strlen( c->argv[ 0 ] );
-
-                               ber_str2bv( line, 0, 0, &bv );
-                               AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
-                                       bv.bv_len - ( len + 1 ) );
-                               bv.bv_val[ bv.bv_len - 1 ] = '"';
-                               ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
-                       }
+                       rwm_bva_rewrite_add( rwmap, &c->argv[ idx0 ] );
                }
                break;
 
@@ -1989,6 +2153,10 @@ rwm_cf_gen( ConfigArgs *c )
                break;
 
        case RWM_CF_MAP:
+               if ( c->valx >= 0 ) {
+                       return 1;
+               }
+
                argv0 = c->argv[ 0 ];
                c->argv[ 0 ] += STRLENOF( "rwm-" );
                rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
@@ -2031,28 +2199,11 @@ rwm_db_init(
 {
        slap_overinst           *on = (slap_overinst *) be->bd_info;
        struct ldaprwmap        *rwmap;
-       char                    *rargv[ 3 ];
        int                     rc = 0;
 
        rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
 
-       rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
-       if ( rwmap->rwm_rw == NULL ) {
-               rc = -1;
-               goto error_return;
-       }
-
-       /* this rewriteContext by default must be null;
-        * rules can be added if required */
-       rargv[ 0 ] = "rewriteContext";
-       rargv[ 1 ] = "searchFilter";
-       rargv[ 2 ] = NULL;
-       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
-
-       rargv[ 0 ] = "rewriteContext";
-       rargv[ 1 ] = "default";
-       rargv[ 2 ] = NULL;
-       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
+       rc = rwm_info_init( rwmap );
 
 error_return:;
        on->on_bi.bi_private = (void *)rwmap;
@@ -2126,6 +2277,10 @@ rwm_initialize( void )
        rwm.on_bi.bi_op_delete = rwm_op_delete;
        rwm.on_bi.bi_op_unbind = rwm_op_unbind;
        rwm.on_bi.bi_extended = rwm_extended;
+#if 1 /* TODO */
+       rwm.on_bi.bi_entry_release_rw = rwm_entry_release_rw;
+       rwm.on_bi.bi_entry_get_rw = rwm_entry_get_rw;
+#endif
 
        rwm.on_bi.bi_operational = rwm_operational;
        rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;