Back to index

openldap  2.4.31
rwm.c
Go to the documentation of this file.
00001 /* rwm.c - rewrite/remap operations */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2003-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2003 Pierangelo Masarati.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 
00018 #include "portable.h"
00019 
00020 #ifdef SLAPD_OVER_RWM
00021 
00022 #include <stdio.h>
00023 
00024 #include <ac/string.h>
00025 
00026 #include "slap.h"
00027 #include "config.h"
00028 #include "lutil.h"
00029 #include "rwm.h"
00030 
00031 typedef struct rwm_op_state {
00032        ber_tag_t r_tag;
00033        struct berval ro_dn;
00034        struct berval ro_ndn;
00035        struct berval r_dn;
00036        struct berval r_ndn;
00037        struct berval rx_dn;
00038        struct berval rx_ndn;
00039        AttributeName *mapped_attrs;
00040        OpRequest o_request;
00041 } rwm_op_state;
00042 
00043 typedef struct rwm_op_cb {
00044        slap_callback cb;
00045        rwm_op_state ros;
00046 } rwm_op_cb;
00047 
00048 static int
00049 rwm_db_destroy( BackendDB *be, ConfigReply *cr );
00050 
00051 static int
00052 rwm_send_entry( Operation *op, SlapReply *rs );
00053 
00054 static void
00055 rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
00056 {
00057        /* in case of successful extended operation cleanup
00058         * gets called *after* (ITS#6632); this hack counts
00059         * on others to cleanup our o_req_dn/o_req_ndn,
00060         * while we cleanup theirs. */
00061        if ( ros->r_tag == LDAP_REQ_EXTENDED && rs->sr_err == LDAP_SUCCESS ) {
00062               if ( !BER_BVISNULL( &ros->rx_dn ) ) {
00063                      ch_free( ros->rx_dn.bv_val );
00064               }
00065               if ( !BER_BVISNULL( &ros->rx_ndn ) ) {
00066                      ch_free( ros->rx_ndn.bv_val );
00067               }
00068 
00069        } else {
00070               if ( !BER_BVISNULL( &ros->ro_dn ) ) {
00071                      op->o_req_dn = ros->ro_dn;
00072               }
00073               if ( !BER_BVISNULL( &ros->ro_ndn ) ) {
00074                      op->o_req_ndn = ros->ro_ndn;
00075               }
00076 
00077               if ( !BER_BVISNULL( &ros->r_dn )
00078                      && ros->r_dn.bv_val != ros->ro_dn.bv_val )
00079               {
00080                      assert( ros->r_dn.bv_val != ros->r_ndn.bv_val );
00081                      ch_free( ros->r_dn.bv_val );
00082               }
00083 
00084               if ( !BER_BVISNULL( &ros->r_ndn )
00085                      && ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
00086               {
00087                      ch_free( ros->r_ndn.bv_val );
00088               }
00089        }
00090 
00091        BER_BVZERO( &ros->r_dn );
00092        BER_BVZERO( &ros->r_ndn );
00093        BER_BVZERO( &ros->ro_dn );
00094        BER_BVZERO( &ros->ro_ndn );
00095        BER_BVZERO( &ros->rx_dn );
00096        BER_BVZERO( &ros->rx_ndn );
00097 
00098        switch( ros->r_tag ) {
00099        case LDAP_REQ_COMPARE:
00100               if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
00101                      op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
00102               op->orc_ava = ros->orc_ava;
00103               break;
00104        case LDAP_REQ_MODIFY:
00105               slap_mods_free( op->orm_modlist, 1 );
00106               op->orm_modlist = ros->orm_modlist;
00107               break;
00108        case LDAP_REQ_MODRDN:
00109               if ( op->orr_newSup != ros->orr_newSup ) {
00110                      ch_free( op->orr_newSup->bv_val );
00111                      ch_free( op->orr_nnewSup->bv_val );
00112                      op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
00113                      op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
00114                      op->orr_newSup = ros->orr_newSup;
00115                      op->orr_nnewSup = ros->orr_nnewSup;
00116               }
00117               if ( op->orr_newrdn.bv_val != ros->orr_newrdn.bv_val ) {
00118                      ch_free( op->orr_newrdn.bv_val );
00119                      ch_free( op->orr_nnewrdn.bv_val );
00120                      op->orr_newrdn = ros->orr_newrdn;
00121                      op->orr_nnewrdn = ros->orr_nnewrdn;
00122               }
00123               break;
00124        case LDAP_REQ_SEARCH:
00125               op->o_tmpfree( ros->mapped_attrs, op->o_tmpmemctx );
00126               filter_free_x( op, op->ors_filter, 1 );
00127               op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
00128               op->ors_attrs = ros->ors_attrs;
00129               op->ors_filter = ros->ors_filter;
00130               op->ors_filterstr = ros->ors_filterstr;
00131               break;
00132        case LDAP_REQ_EXTENDED:
00133               if ( op->ore_reqdata != ros->ore_reqdata ) {
00134                      ber_bvfree( op->ore_reqdata );
00135                      op->ore_reqdata = ros->ore_reqdata;
00136               }
00137               break;
00138        case LDAP_REQ_BIND:
00139               if ( rs->sr_err == LDAP_SUCCESS ) {
00140 #if 0
00141                      ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00142                      /* too late, c_mutex released */
00143                      Debug( LDAP_DEBUG_ANY, "*** DN: \"%s\" => \"%s\"\n",
00144                             op->o_conn->c_ndn.bv_val,
00145                             op->o_req_ndn.bv_val );
00146                      ber_bvreplace( &op->o_conn->c_ndn,
00147                             &op->o_req_ndn );
00148                      ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00149 #endif
00150               }
00151               break;
00152        default:      break;
00153        }
00154 }
00155 
00156 static int
00157 rwm_op_cleanup( Operation *op, SlapReply *rs )
00158 {
00159        slap_callback *cb = op->o_callback;
00160        rwm_op_state *ros = cb->sc_private;
00161 
00162        if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
00163               op->o_abandon || rs->sr_err == SLAPD_ABANDON )
00164        {
00165               rwm_op_rollback( op, rs, ros );
00166 
00167               op->o_callback = op->o_callback->sc_next;
00168               op->o_tmpfree( cb, op->o_tmpmemctx );
00169        }
00170 
00171        return SLAP_CB_CONTINUE;
00172 }
00173 
00174 static rwm_op_cb *
00175 rwm_callback_get( Operation *op )
00176 {
00177        rwm_op_cb     *roc;
00178 
00179        roc = op->o_tmpalloc( sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
00180        roc->cb.sc_cleanup = rwm_op_cleanup;
00181        roc->cb.sc_response = NULL;
00182        roc->cb.sc_next = op->o_callback;
00183        roc->cb.sc_private = &roc->ros;
00184        roc->ros.r_tag = op->o_tag;
00185        roc->ros.ro_dn = op->o_req_dn;
00186        roc->ros.ro_ndn = op->o_req_ndn;
00187        BER_BVZERO( &roc->ros.r_dn );
00188        BER_BVZERO( &roc->ros.r_ndn );
00189        BER_BVZERO( &roc->ros.rx_dn );
00190        BER_BVZERO( &roc->ros.rx_ndn );
00191        roc->ros.mapped_attrs = NULL;
00192        roc->ros.o_request = op->o_request;
00193 
00194        return roc;
00195 }
00196 
00197 
00198 static int
00199 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
00200        rwm_op_state *ros )
00201 {
00202        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00203        struct ldaprwmap     *rwmap = 
00204                      (struct ldaprwmap *)on->on_bi.bi_private;
00205 
00206        struct berval        dn = BER_BVNULL,
00207                             ndn = BER_BVNULL;
00208        int                  rc = 0;
00209        dncookie             dc;
00210 
00211        /*
00212         * Rewrite the dn if needed
00213         */
00214        dc.rwmap = rwmap;
00215        dc.conn = op->o_conn;
00216        dc.rs = rs;
00217        dc.ctx = (char *)cookie;
00218 
00219        /* NOTE: in those cases where only the ndn is available,
00220         * and the caller sets op->o_req_dn = op->o_req_ndn,
00221         * only rewrite the op->o_req_ndn and use it as 
00222         * op->o_req_dn as well */
00223        ndn = op->o_req_ndn;
00224        if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
00225               dn = op->o_req_dn;
00226               rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
00227        } else {
00228               rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
00229        }
00230 
00231        if ( rc != LDAP_SUCCESS ) {
00232               return rc;
00233        }
00234 
00235        if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
00236                      || ndn.bv_val == op->o_req_ndn.bv_val )
00237        {
00238               return LDAP_SUCCESS;
00239        }
00240 
00241        if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
00242               op->o_req_dn = dn;
00243               assert( BER_BVISNULL( &ros->r_dn ) );
00244               ros->r_dn = dn;
00245        } else {
00246               op->o_req_dn = ndn;
00247        }
00248        op->o_req_ndn = ndn;
00249        assert( BER_BVISNULL( &ros->r_ndn ) );
00250        ros->r_ndn = ndn;
00251 
00252        if ( ros->r_tag == LDAP_REQ_EXTENDED ) {
00253               ros->rx_dn = ros->r_dn;
00254               ros->rx_ndn = ros->r_ndn;
00255        }
00256 
00257        return LDAP_SUCCESS;
00258 }
00259 
00260 static int
00261 rwm_op_add( Operation *op, SlapReply *rs )
00262 {
00263        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00264        struct ldaprwmap     *rwmap = 
00265                      (struct ldaprwmap *)on->on_bi.bi_private;
00266 
00267        int                  rc,
00268                             i;
00269        Attribute            **ap = NULL;
00270        char                 *olddn = op->o_req_dn.bv_val;
00271        int                  isupdate;
00272 
00273        rwm_op_cb            *roc = rwm_callback_get( op );
00274 
00275        rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
00276        if ( rc != LDAP_SUCCESS ) {
00277               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00278               send_ldap_error( op, rs, rc, "addDN massage error" );
00279               return -1;
00280        }
00281 
00282        if ( olddn != op->o_req_dn.bv_val ) {
00283               ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
00284               ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
00285        }
00286 
00287        /* Count number of attributes in entry */ 
00288        isupdate = be_shadow_update( op );
00289        for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
00290               Attribute     *a;
00291 
00292               if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
00293                             (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
00294               {
00295                      int           j, last;
00296 
00297                      last = (*ap)->a_numvals - 1;
00298                      for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
00299                             struct ldapmapping   *mapping = NULL;
00300 
00301                             ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
00302                                           &mapping, RWM_MAP );
00303                             if ( mapping == NULL ) {
00304                                    if ( rwmap->rwm_at.drop_missing ) {
00305                                           /* FIXME: we allow to remove objectClasses as well;
00306                                            * if the resulting entry is inconsistent, that's
00307                                            * the relayed database's business...
00308                                            */
00309                                           ch_free( (*ap)->a_vals[ j ].bv_val );
00310                                           if ( last > j ) {
00311                                                  (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
00312                                           }
00313                                           BER_BVZERO( &(*ap)->a_vals[ last ] );
00314                                           (*ap)->a_numvals--;
00315                                           last--;
00316                                           j--;
00317                                    }
00318 
00319                             } else {
00320                                    ch_free( (*ap)->a_vals[ j ].bv_val );
00321                                    ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
00322                             }
00323                      }
00324 
00325               } else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
00326               {
00327                      goto next_attr;
00328 
00329               } else {
00330                      struct ldapmapping   *mapping = NULL;
00331 
00332                      ( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
00333                                    &mapping, RWM_MAP );
00334                      if ( mapping == NULL ) {
00335                             if ( rwmap->rwm_at.drop_missing ) {
00336                                    goto cleanup_attr;
00337                             }
00338                      }
00339 
00340                      if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
00341                                    || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
00342                      {
00343                             /*
00344                              * FIXME: rewrite could fail; in this case
00345                              * the operation should give up, right?
00346                              */
00347                             rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
00348                                           (*ap)->a_vals,
00349                                           (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
00350                             if ( rc ) {
00351                                    goto cleanup_attr;
00352                             }
00353 
00354                      } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
00355                             rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
00356                                           (*ap)->a_vals,
00357                                           (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
00358                             if ( rc != LDAP_SUCCESS ) {
00359                                    goto cleanup_attr;
00360                             }
00361                      }
00362               
00363                      if ( mapping != NULL ) {
00364                             assert( mapping->m_dst_ad != NULL );
00365                             (*ap)->a_desc = mapping->m_dst_ad;
00366                      }
00367               }
00368 
00369 next_attr:;
00370               ap = &(*ap)->a_next;
00371               continue;
00372 
00373 cleanup_attr:;
00374               /* FIXME: leaking attribute/values? */
00375               a = *ap;
00376 
00377               *ap = (*ap)->a_next;
00378               attr_free( a );
00379        }
00380 
00381        op->o_callback = &roc->cb;
00382 
00383        return SLAP_CB_CONTINUE;
00384 }
00385 
00386 static int
00387 rwm_conn_init( BackendDB *be, Connection *conn )
00388 {
00389        slap_overinst        *on = (slap_overinst *) be->bd_info;
00390        struct ldaprwmap     *rwmap = 
00391                      (struct ldaprwmap *)on->on_bi.bi_private;
00392 
00393        ( void )rewrite_session_init( rwmap->rwm_rw, conn );
00394 
00395        return SLAP_CB_CONTINUE;
00396 }
00397 
00398 static int
00399 rwm_conn_destroy( BackendDB *be, Connection *conn )
00400 {
00401        slap_overinst        *on = (slap_overinst *) be->bd_info;
00402        struct ldaprwmap     *rwmap = 
00403                      (struct ldaprwmap *)on->on_bi.bi_private;
00404 
00405        ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
00406 
00407        return SLAP_CB_CONTINUE;
00408 }
00409 
00410 static int
00411 rwm_op_bind( Operation *op, SlapReply *rs )
00412 {
00413        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00414        int                  rc;
00415 
00416        rwm_op_cb            *roc = rwm_callback_get( op );
00417 
00418        rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
00419        if ( rc != LDAP_SUCCESS ) {
00420               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00421               send_ldap_error( op, rs, rc, "bindDN massage error" );
00422               return -1;
00423        }
00424 
00425        overlay_callback_after_backover( op, &roc->cb, 1 );
00426 
00427        return SLAP_CB_CONTINUE;
00428 }
00429 
00430 static int
00431 rwm_op_unbind( Operation *op, SlapReply *rs )
00432 {
00433        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00434        struct ldaprwmap     *rwmap = 
00435                      (struct ldaprwmap *)on->on_bi.bi_private;
00436 
00437        rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
00438 
00439        return SLAP_CB_CONTINUE;
00440 }
00441 
00442 static int
00443 rwm_op_compare( Operation *op, SlapReply *rs )
00444 {
00445        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00446        struct ldaprwmap     *rwmap = 
00447                      (struct ldaprwmap *)on->on_bi.bi_private;
00448 
00449        int                  rc;
00450        struct berval        mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
00451 
00452        rwm_op_cb            *roc = rwm_callback_get( op );
00453 
00454        rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
00455        if ( rc != LDAP_SUCCESS ) {
00456               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00457               send_ldap_error( op, rs, rc, "compareDN massage error" );
00458               return -1;
00459        }
00460 
00461        /* if the attribute is an objectClass, try to remap its value */
00462        if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
00463                      || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
00464        {
00465               rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
00466                             &mapped_vals[0], RWM_MAP );
00467               if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
00468               {
00469                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
00470                      send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
00471                      return -1;
00472 
00473               } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
00474                      ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
00475                             op->o_tmpmemctx );
00476               }
00477 
00478        } else {
00479               struct ldapmapping   *mapping = NULL;
00480               AttributeDescription *ad = op->orc_ava->aa_desc;
00481 
00482               ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
00483                             &mapping, RWM_MAP );
00484               if ( mapping == NULL ) {
00485                      if ( rwmap->rwm_at.drop_missing ) {
00486                             op->o_bd->bd_info = (BackendInfo *)on->on_info;
00487                             send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
00488                             return -1;
00489                      }
00490 
00491               } else {
00492                      assert( mapping->m_dst_ad != NULL );
00493                      ad = mapping->m_dst_ad;
00494               }
00495 
00496               if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
00497                             || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
00498               {
00499                      struct berval *mapped_valsp[2];
00500                      
00501                      mapped_valsp[0] = &mapped_vals[0];
00502                      mapped_valsp[1] = &mapped_vals[1];
00503 
00504                      mapped_vals[0] = op->orc_ava->aa_value;
00505 
00506                      rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
00507 
00508                      if ( rc != LDAP_SUCCESS ) {
00509                             op->o_bd->bd_info = (BackendInfo *)on->on_info;
00510                             send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
00511                             return -1;
00512                      }
00513 
00514                      if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
00515                             /* NOTE: if we get here, rwm_dnattr_rewrite()
00516                              * already freed the old value, so now 
00517                              * it's invalid */
00518                             ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
00519                                    op->o_tmpmemctx );
00520                             ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
00521                      }
00522               }
00523               op->orc_ava->aa_desc = ad;
00524        }
00525 
00526        op->o_callback = &roc->cb;
00527 
00528        return SLAP_CB_CONTINUE;
00529 }
00530 
00531 static int
00532 rwm_op_delete( Operation *op, SlapReply *rs )
00533 {
00534        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00535        int                  rc;
00536 
00537        rwm_op_cb            *roc = rwm_callback_get( op );
00538 
00539        rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
00540        if ( rc != LDAP_SUCCESS ) {
00541               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00542               send_ldap_error( op, rs, rc, "deleteDN massage error" );
00543               return -1;
00544        }
00545 
00546        op->o_callback = &roc->cb;
00547 
00548        return SLAP_CB_CONTINUE;
00549 }
00550 
00551 static int
00552 rwm_op_modify( Operation *op, SlapReply *rs )
00553 {
00554        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00555        struct ldaprwmap     *rwmap = 
00556                      (struct ldaprwmap *)on->on_bi.bi_private;
00557 
00558        int                  isupdate;
00559        Modifications        **mlp;
00560        int                  rc;
00561 
00562        rwm_op_cb            *roc = rwm_callback_get( op );
00563 
00564        rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
00565        if ( rc != LDAP_SUCCESS ) {
00566               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00567               send_ldap_error( op, rs, rc, "modifyDN massage error" );
00568               return -1;
00569        }
00570 
00571        isupdate = be_shadow_update( op );
00572        for ( mlp = &op->orm_modlist; *mlp; ) {
00573               int                  is_oc = 0;
00574               Modifications        *ml = *mlp;
00575               struct ldapmapping   *mapping = NULL;
00576 
00577               /* ml points to a temporary mod until needs duplication */
00578               if ( ml->sml_desc == slap_schema.si_ad_objectClass 
00579                             || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
00580               {
00581                      is_oc = 1;
00582 
00583               } else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
00584               {
00585                      ml = ch_malloc( sizeof( Modifications ) );
00586                      *ml = **mlp;
00587                      if ( (*mlp)->sml_values ) {
00588                             ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
00589                             if ( (*mlp)->sml_nvalues ) {
00590                                    ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
00591                             }
00592                      }
00593                      *mlp = ml;
00594                      goto next_mod;
00595 
00596               } else {
00597                      int                  drop_missing;
00598 
00599                      drop_missing = rwm_mapping( &rwmap->rwm_at,
00600                                    &ml->sml_desc->ad_cname,
00601                                    &mapping, RWM_MAP );
00602                      if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
00603                      {
00604                             goto skip_mod;
00605                      }
00606               }
00607 
00608               /* duplicate the modlist */
00609               ml = ch_malloc( sizeof( Modifications ));
00610               *ml = **mlp;
00611               *mlp = ml;
00612 
00613               if ( ml->sml_values != NULL ) {
00614                      int i, num;
00615                      struct berval *bva;
00616 
00617                      for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
00618                             /* count values */ ;
00619 
00620                      bva = ch_malloc( (num+1) * sizeof( struct berval ));
00621                      for (i=0; i<num; i++)
00622                             ber_dupbv( &bva[i], &ml->sml_values[i] );
00623                      BER_BVZERO( &bva[i] );
00624                      ml->sml_values = bva;
00625 
00626                      if ( ml->sml_nvalues ) {
00627                             bva = ch_malloc( (num+1) * sizeof( struct berval ));
00628                             for (i=0; i<num; i++)
00629                                    ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
00630                             BER_BVZERO( &bva[i] );
00631                             ml->sml_nvalues = bva;
00632                      }
00633 
00634                      if ( is_oc ) {
00635                             int    last, j;
00636 
00637                             last = num-1;
00638 
00639                             for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
00640                                    struct ldapmapping   *oc_mapping = NULL;
00641               
00642                                    ( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
00643                                                  &oc_mapping, RWM_MAP );
00644                                    if ( oc_mapping == NULL ) {
00645                                           if ( rwmap->rwm_at.drop_missing ) {
00646                                                  /* FIXME: we allow to remove objectClasses as well;
00647                                                   * if the resulting entry is inconsistent, that's
00648                                                   * the relayed database's business...
00649                                                   */
00650                                                  if ( last > j ) {
00651                                                         ch_free( ml->sml_values[ j ].bv_val );
00652                                                         ml->sml_values[ j ] = ml->sml_values[ last ];
00653                                                  }
00654                                                  BER_BVZERO( &ml->sml_values[ last ] );
00655                                                  last--;
00656                                                  j--;
00657                                           }
00658        
00659                                    } else {
00660                                           ch_free( ml->sml_values[ j ].bv_val );
00661                                           ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
00662                                    }
00663                             }
00664 
00665                      } else {
00666                             if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
00667                                           || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
00668                             {
00669                                    rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
00670                                                  ml->sml_values,
00671                                                  ml->sml_nvalues ? &ml->sml_nvalues : NULL );
00672 
00673                             } else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
00674                                    rc = rwm_referral_rewrite( op, rs,
00675                                                  "referralAttrDN",
00676                                                  ml->sml_values,
00677                                                  ml->sml_nvalues ? &ml->sml_nvalues : NULL );
00678                                    if ( rc != LDAP_SUCCESS ) {
00679                                           goto cleanup_mod;
00680                                    }
00681                             }
00682 
00683                             if ( rc != LDAP_SUCCESS ) {
00684                                    goto cleanup_mod;
00685                             }
00686                      }
00687               }
00688 
00689 next_mod:;
00690               if ( mapping != NULL ) {
00691                      /* use new attribute description */
00692                      assert( mapping->m_dst_ad != NULL );
00693                      ml->sml_desc = mapping->m_dst_ad;
00694               }
00695 
00696               mlp = &ml->sml_next;
00697               continue;
00698 
00699 skip_mod:;
00700               *mlp = (*mlp)->sml_next;
00701               continue;
00702 
00703 cleanup_mod:;
00704               ml = *mlp;
00705               *mlp = (*mlp)->sml_next;
00706               slap_mod_free( &ml->sml_mod, 0 );
00707               free( ml );
00708        }
00709 
00710        op->o_callback = &roc->cb;
00711 
00712        return SLAP_CB_CONTINUE;
00713 }
00714 
00715 static int
00716 rwm_op_modrdn( Operation *op, SlapReply *rs )
00717 {
00718        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00719        struct ldaprwmap     *rwmap = 
00720                      (struct ldaprwmap *)on->on_bi.bi_private;
00721        
00722        int                  rc;
00723        dncookie             dc;
00724 
00725        rwm_op_cb            *roc = rwm_callback_get( op );
00726 
00727        if ( op->orr_newSup ) {
00728               struct berval nnewSup = BER_BVNULL;
00729               struct berval newSup = BER_BVNULL;
00730 
00731               /*
00732                * Rewrite the new superior, if defined and required
00733                */
00734               dc.rwmap = rwmap;
00735               dc.conn = op->o_conn;
00736               dc.rs = rs;
00737               dc.ctx = "newSuperiorDN";
00738               newSup = *op->orr_newSup;
00739               nnewSup = *op->orr_nnewSup;
00740               rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
00741               if ( rc != LDAP_SUCCESS ) {
00742                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
00743                      send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
00744                      return -1;
00745               }
00746 
00747               if ( op->orr_newSup->bv_val != newSup.bv_val ) {
00748                      op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
00749                             op->o_tmpmemctx );
00750                      op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
00751                             op->o_tmpmemctx );
00752                      *op->orr_newSup = newSup;
00753                      *op->orr_nnewSup = nnewSup;
00754               }
00755        }
00756 
00757        /*
00758         * Rewrite the newRDN, if needed
00759         */
00760        {
00761               struct berval newrdn = BER_BVNULL;
00762               struct berval nnewrdn = BER_BVNULL;
00763 
00764               dc.rwmap = rwmap;
00765               dc.conn = op->o_conn;
00766               dc.rs = rs;
00767               dc.ctx = "newRDN";
00768               newrdn = op->orr_newrdn;
00769               nnewrdn = op->orr_nnewrdn;
00770               rc = rwm_dn_massage_pretty_normalize( &dc, &op->orr_newrdn, &newrdn, &nnewrdn );
00771               if ( rc != LDAP_SUCCESS ) {
00772                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
00773                      send_ldap_error( op, rs, rc, "newRDN massage error" );
00774                      goto err;
00775               }
00776 
00777               if ( op->orr_newrdn.bv_val != newrdn.bv_val ) {
00778                      op->orr_newrdn = newrdn;
00779                      op->orr_nnewrdn = nnewrdn;
00780               }
00781        }
00782 
00783        /*
00784         * Rewrite the dn, if needed
00785         */
00786        rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
00787        if ( rc != LDAP_SUCCESS ) {
00788               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00789               send_ldap_error( op, rs, rc, "renameDN massage error" );
00790               goto err;
00791        }
00792 
00793        op->o_callback = &roc->cb;
00794 
00795        rc = SLAP_CB_CONTINUE;
00796 
00797        if ( 0 ) {
00798 err:;
00799               if ( op->orr_newSup != roc->ros.orr_newSup ) {
00800                      ch_free( op->orr_newSup->bv_val );
00801                      ch_free( op->orr_nnewSup->bv_val );
00802                      op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
00803                      op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
00804                      op->orr_newSup = roc->ros.orr_newSup;
00805                      op->orr_nnewSup = roc->ros.orr_nnewSup;
00806               }
00807 
00808               if ( op->orr_newrdn.bv_val != roc->ros.orr_newrdn.bv_val ) {
00809                      ch_free( op->orr_newrdn.bv_val );
00810                      ch_free( op->orr_nnewrdn.bv_val );
00811                      op->orr_newrdn = roc->ros.orr_newrdn;
00812                      op->orr_nnewrdn = roc->ros.orr_nnewrdn;
00813               }
00814        }
00815 
00816        return rc;
00817 }
00818 
00819 
00820 static int
00821 rwm_swap_attrs( Operation *op, SlapReply *rs )
00822 {
00823        slap_callback *cb = op->o_callback;
00824        rwm_op_state *ros = cb->sc_private;
00825 
00826        rs->sr_attrs = ros->ors_attrs;
00827 
00828        /* other overlays might have touched op->ors_attrs, 
00829         * so we restore the original version here, otherwise
00830         * attribute-mapping might fail */
00831        op->ors_attrs = ros->mapped_attrs; 
00832        
00833        return SLAP_CB_CONTINUE;
00834 }
00835 
00836 /*
00837  * NOTE: this implementation of get/release entry is probably far from
00838  * optimal.  The rationale consists in intercepting the request directed
00839  * to the underlying database, in order to rewrite/remap the request,
00840  * perform it using the modified data, duplicate the resulting entry
00841  * and finally free it when release is called.
00842  * This implies that subsequent overlays are not called, as the request
00843  * is directly shunted to the underlying database.
00844  */
00845 static int
00846 rwm_entry_release_rw( Operation *op, Entry *e, int rw )
00847 {
00848        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00849 
00850        /* can't be ours */
00851        if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
00852               return SLAP_CB_CONTINUE;
00853        }
00854 
00855        /* just free entry if (probably) ours */
00856        if ( e->e_private == NULL && BER_BVISNULL( &e->e_bv ) ) {
00857               entry_free( e );
00858               return LDAP_SUCCESS;
00859        }
00860 
00861        return SLAP_CB_CONTINUE;
00862 }
00863 
00864 static int
00865 rwm_entry_get_rw( Operation *op, struct berval *ndn,
00866        ObjectClass *oc, AttributeDescription *at, int rw, Entry **ep )
00867 {
00868        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00869        int                  rc;
00870        BackendDB            db;
00871        Operation            op2;
00872        SlapReply            rs = { REP_SEARCH };
00873 
00874        rwm_op_state         ros = { 0 };
00875        struct berval        mndn = BER_BVNULL;
00876 
00877        if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
00878               return SLAP_CB_CONTINUE;
00879        }
00880 
00881        /* massage DN */
00882        op2.o_tag = LDAP_REQ_SEARCH;
00883        op2 = *op;
00884        op2.o_req_dn = *ndn;
00885        op2.o_req_ndn = *ndn;
00886        rc = rwm_op_dn_massage( &op2, &rs, "searchDN", &ros );
00887        if ( rc != LDAP_SUCCESS ) {
00888               return LDAP_OTHER;
00889        }
00890 
00891        mndn = BER_BVISNULL( &ros.r_ndn ) ? *ndn : ros.r_ndn;
00892 
00893        /* map attribute & objectClass */
00894        if ( at != NULL ) {
00895        }
00896 
00897        if ( oc != NULL ) {
00898        }
00899 
00900        /* fetch entry */
00901        db = *op->o_bd;
00902        op2.o_bd = &db;
00903        op2.o_bd->bd_info = (BackendInfo *)on->on_info->oi_orig;
00904        op2.ors_attrs = slap_anlist_all_attributes;
00905        rc = op2.o_bd->bd_info->bi_entry_get_rw( &op2, &mndn, oc, at, rw, ep );
00906        if ( rc == LDAP_SUCCESS && *ep != NULL ) {
00907               /* we assume be_entry_release() needs to be called */
00908               rs.sr_flags = REP_ENTRY_MUSTRELEASE;
00909               rs.sr_entry = *ep;
00910 
00911               /* duplicate & release */
00912               op2.o_bd->bd_info = (BackendInfo *)on;
00913               rc = rwm_send_entry( &op2, &rs );
00914               RS_ASSERT( rs.sr_flags & REP_ENTRY_MUSTFLUSH );
00915               if ( rc == SLAP_CB_CONTINUE ) {
00916                      *ep = rs.sr_entry;
00917                      rc = LDAP_SUCCESS;
00918               } else {
00919                      assert( rc != LDAP_SUCCESS && rs.sr_entry == *ep );
00920                      *ep = NULL;
00921                      op2.o_bd->bd_info = (BackendInfo *)on->on_info;
00922                      be_entry_release_r( &op2, rs.sr_entry );
00923                      op2.o_bd->bd_info = (BackendInfo *)on;
00924               }
00925        }
00926 
00927        if ( !BER_BVISNULL( &ros.r_ndn) && ros.r_ndn.bv_val != ndn->bv_val ) {
00928               op->o_tmpfree( ros.r_ndn.bv_val, op->o_tmpmemctx );
00929        }
00930 
00931        return rc;
00932 }
00933 
00934 static int
00935 rwm_op_search( Operation *op, SlapReply *rs )
00936 {
00937        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
00938        struct ldaprwmap     *rwmap = 
00939                      (struct ldaprwmap *)on->on_bi.bi_private;
00940 
00941        int                  rc;
00942        dncookie             dc;
00943 
00944        struct berval        fstr = BER_BVNULL;
00945        Filter               *f = NULL;
00946 
00947        AttributeName        *an = NULL;
00948 
00949        char                 *text = NULL;
00950 
00951        rwm_op_cb            *roc = rwm_callback_get( op );
00952 
00953        rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
00954               "searchFilter", op->ors_filterstr.bv_val );
00955        if ( rc == LDAP_SUCCESS )
00956               rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
00957        if ( rc != LDAP_SUCCESS ) {
00958               text = "searchDN massage error";
00959               goto error_return;
00960        }
00961 
00962        /*
00963         * Rewrite the dn if needed
00964         */
00965        dc.rwmap = rwmap;
00966        dc.conn = op->o_conn;
00967        dc.rs = rs;
00968        dc.ctx = "searchFilterAttrDN";
00969 
00970        rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
00971        if ( rc != LDAP_SUCCESS ) {
00972               text = "searchFilter/searchFilterAttrDN massage error";
00973               goto error_return;
00974        }
00975 
00976        f = str2filter_x( op, fstr.bv_val );
00977 
00978        if ( f == NULL ) {
00979               text = "massaged filter parse error";
00980               goto error_return;
00981        }
00982 
00983        op->ors_filter = f;
00984        op->ors_filterstr = fstr;
00985 
00986        rc = rwm_map_attrnames( op, &rwmap->rwm_at, &rwmap->rwm_oc,
00987                      op->ors_attrs, &an, RWM_MAP );
00988        if ( rc != LDAP_SUCCESS ) {
00989               text = "attribute list mapping error";
00990               goto error_return;
00991        }
00992 
00993        op->ors_attrs = an;
00994        /* store the mapped Attributes for later usage, in
00995         * the case that other overlays change op->ors_attrs */
00996        roc->ros.mapped_attrs = an;
00997        roc->cb.sc_response = rwm_swap_attrs;
00998 
00999        op->o_callback = &roc->cb;
01000 
01001        return SLAP_CB_CONTINUE;
01002 
01003 error_return:;
01004        if ( an != NULL ) {
01005               ch_free( an );
01006        }
01007 
01008        if ( f != NULL ) {
01009               filter_free_x( op, f, 1 );
01010        }
01011 
01012        if ( !BER_BVISNULL( &fstr ) ) {
01013               op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
01014        }
01015 
01016        rwm_op_rollback( op, rs, &roc->ros );
01017        op->oq_search = roc->ros.oq_search;
01018        op->o_tmpfree( roc, op->o_tmpmemctx );
01019 
01020        op->o_bd->bd_info = (BackendInfo *)on->on_info;
01021        send_ldap_error( op, rs, rc, text );
01022 
01023        return -1;
01024 
01025 }
01026 
01027 static int
01028 rwm_exop_passwd( Operation *op, SlapReply *rs )
01029 {
01030        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
01031        int                  rc;
01032        rwm_op_cb *roc;
01033 
01034        struct berval id = BER_BVNULL,
01035                      pwold = BER_BVNULL,
01036                      pwnew = BER_BVNULL;
01037        BerElement *ber = NULL;
01038 
01039        if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
01040               return LDAP_SUCCESS;
01041        }
01042 
01043        if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
01044               rs->sr_err = LDAP_OTHER;
01045               return rs->sr_err;
01046        }
01047 
01048        rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
01049               &pwold, &pwnew, &rs->sr_text );
01050        if ( rs->sr_err != LDAP_SUCCESS ) {
01051               return rs->sr_err;
01052        }
01053 
01054        if ( !BER_BVISNULL( &id ) ) {
01055               char idNul = id.bv_val[id.bv_len];
01056               id.bv_val[id.bv_len] = '\0';
01057               rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
01058                             &op->o_req_ndn, op->o_tmpmemctx );
01059               id.bv_val[id.bv_len] = idNul;
01060               if ( rs->sr_err != LDAP_SUCCESS ) {
01061                      rs->sr_text = "Invalid DN";
01062                      return rs->sr_err;
01063               }
01064 
01065        } else {
01066               ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
01067               ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
01068        }
01069 
01070        roc = rwm_callback_get( op );
01071 
01072        rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
01073        if ( rc != LDAP_SUCCESS ) {
01074               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01075               send_ldap_error( op, rs, rc, "extendedDN massage error" );
01076               return -1;
01077        }
01078 
01079        ber = ber_alloc_t( LBER_USE_DER );
01080        if ( !ber ) {
01081               rs->sr_err = LDAP_OTHER;
01082               rs->sr_text = "No memory";
01083               return rs->sr_err;
01084        }
01085        ber_printf( ber, "{" );
01086        if ( !BER_BVISNULL( &id )) {
01087               ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, 
01088                      &op->o_req_dn );
01089        }
01090        if ( !BER_BVISNULL( &pwold )) {
01091               ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
01092        }
01093        if ( !BER_BVISNULL( &pwnew )) {
01094               ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
01095        }
01096        ber_printf( ber, "N}" );
01097        ber_flatten( ber, &op->ore_reqdata );
01098        ber_free( ber, 1 );
01099 
01100        op->o_callback = &roc->cb;
01101 
01102        return SLAP_CB_CONTINUE;
01103 }
01104 
01105 static struct exop {
01106        struct berval oid;
01107        BI_op_extended       *extended;
01108 } exop_table[] = {
01109        { BER_BVC(LDAP_EXOP_MODIFY_PASSWD),       rwm_exop_passwd },
01110        { BER_BVNULL, NULL }
01111 };
01112 
01113 static int
01114 rwm_extended( Operation *op, SlapReply *rs )
01115 {
01116        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
01117        int                  rc;
01118        rwm_op_cb *roc;
01119 
01120        int    i;
01121 
01122        for ( i = 0; exop_table[i].extended != NULL; i++ ) {
01123               if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
01124               {
01125                      rc = exop_table[i].extended( op, rs );
01126                      switch ( rc ) {
01127                      case LDAP_SUCCESS:
01128                             break;
01129 
01130                      case SLAP_CB_CONTINUE:
01131                      case SLAPD_ABANDON:
01132                             return rc;
01133 
01134                      default:
01135                             send_ldap_result( op, rs );
01136                             return rc;
01137                      }
01138                      break;
01139               }
01140        }
01141 
01142        roc = rwm_callback_get( op );
01143 
01144        rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
01145        if ( rc != LDAP_SUCCESS ) {
01146               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01147               send_ldap_error( op, rs, rc, "extendedDN massage error" );
01148               return -1;
01149        }
01150 
01151        /* TODO: rewrite/map extended data ? ... */
01152        op->o_callback = &roc->cb;
01153 
01154        return SLAP_CB_CONTINUE;
01155 }
01156 
01157 static void
01158 rwm_matched( Operation *op, SlapReply *rs )
01159 {
01160        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
01161        struct ldaprwmap     *rwmap = 
01162                      (struct ldaprwmap *)on->on_bi.bi_private;
01163 
01164        struct berval        dn, mdn;
01165        dncookie             dc;
01166        int                  rc;
01167 
01168        if ( rs->sr_matched == NULL ) {
01169               return;
01170        }
01171 
01172        dc.rwmap = rwmap;
01173        dc.conn = op->o_conn;
01174        dc.rs = rs;
01175        dc.ctx = "matchedDN";
01176        ber_str2bv( rs->sr_matched, 0, 0, &dn );
01177        mdn = dn;
01178        rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
01179        if ( rc != LDAP_SUCCESS ) {
01180               rs->sr_err = rc;
01181               rs->sr_text = "Rewrite error";
01182 
01183        } else if ( mdn.bv_val != dn.bv_val ) {
01184               if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
01185                      ch_free( (void *)rs->sr_matched );
01186 
01187               } else {
01188                      rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
01189               }
01190               rs->sr_matched = mdn.bv_val;
01191        }
01192 }
01193 
01194 static int
01195 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
01196 {
01197        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
01198        struct ldaprwmap     *rwmap = 
01199                      (struct ldaprwmap *)on->on_bi.bi_private;
01200 
01201        dncookie             dc;
01202        int                  rc;
01203        Attribute            **ap;
01204        int                  isupdate;
01205        int                  check_duplicate_attrs = 0;
01206 
01207        /*
01208         * Rewrite the dn attrs, if needed
01209         */
01210        dc.rwmap = rwmap;
01211        dc.conn = op->o_conn;
01212        dc.rs = NULL; 
01213 
01214        /* FIXME: the entries are in the remote mapping form;
01215         * so we need to select those attributes we are willing
01216         * to return, and remap them accordingly */
01217 
01218        /* FIXME: in principle, one could map an attribute
01219         * on top of another, which already exists.
01220         * As such, in the end there might exist more than
01221         * one instance of an attribute.
01222         * We should at least check if this occurs, and issue
01223         * an error (because multiple instances of attrs in 
01224         * response are not valid), or merge the values (what
01225         * about duplicate values?) */
01226        isupdate = be_shadow_update( op );
01227        for ( ap = a_first; *ap; ) {
01228               struct ldapmapping   *mapping = NULL;
01229               int                  drop_missing;
01230               int                  last = -1;
01231               Attribute            *a;
01232 
01233               if ( ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS ) &&
01234                             op->ors_attrs != NULL && 
01235                             !SLAP_USERATTRS( rs->sr_attr_flags ) &&
01236                             !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
01237               {
01238                      goto cleanup_attr;
01239               }
01240 
01241               drop_missing = rwm_mapping( &rwmap->rwm_at,
01242                             &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
01243               if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
01244               {
01245                      goto cleanup_attr;
01246               }
01247               if ( mapping != NULL ) {
01248                      assert( mapping->m_dst_ad != NULL );
01249 
01250                      /* try to normalize mapped Attributes if the original 
01251                       * AttributeType was not normalized */
01252                      if ( (!(*ap)->a_desc->ad_type->sat_equality || 
01253                             !(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
01254                             mapping->m_dst_ad->ad_type->sat_equality &&
01255                             mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
01256                      {
01257                             if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS))
01258                             {
01259                                    int i = 0;
01260 
01261                                    last = (*ap)->a_numvals;
01262                                    if ( last )
01263                                    {
01264                                           (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
01265 
01266                                           for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
01267                                                  int           rc;
01268                                                  /*
01269                                                   * check that each value is valid per syntax
01270                                                   * and pretty if appropriate
01271                                                   */
01272                                                  rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
01273                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
01274                                                         mapping->m_dst_ad->ad_type->sat_syntax,
01275                                                         mapping->m_dst_ad->ad_type->sat_equality,
01276                                                         &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
01277                                                         NULL );
01278 
01279                                                  if ( rc != LDAP_SUCCESS ) {
01280                                                         /* FIXME: this is wrong, putting a non-normalized value
01281                                                          * into nvals. But when a proxy sends us bogus data,
01282                                                          * we still need to give it to the client, even if it
01283                                                          * violates the syntax. I.e., we don't want to silently
01284                                                          * drop things and trigger an apparent data loss.
01285                                                          */
01286                                                         ber_dupbv( &(*ap)->a_nvals[i], &(*ap)->a_vals[i] );
01287                                                  }
01288                                           }
01289                                           BER_BVZERO( &(*ap)->a_nvals[i] );
01290                                    }
01291 
01292                             } else {
01293                                    assert( (*ap)->a_nvals == (*ap)->a_vals );
01294                                    (*ap)->a_nvals = NULL;
01295                                    ber_bvarray_dup_x( &(*ap)->a_nvals, (*ap)->a_vals, NULL );
01296                             }
01297                      }
01298 
01299                      /* rewrite the attribute description */
01300                      (*ap)->a_desc = mapping->m_dst_ad;
01301 
01302                      /* will need to check for duplicate attrs */
01303                      check_duplicate_attrs++;
01304               }
01305 
01306               if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
01307                      if ( stripEntryDN ) {
01308                             /* will be generated by frontend */
01309                             goto cleanup_attr;
01310                      }
01311                      
01312               } else if ( !isupdate
01313                      && !get_relax( op )
01314                      && (*ap)->a_desc->ad_type->sat_no_user_mod 
01315                      && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
01316               {
01317                      goto next_attr;
01318               }
01319 
01320               if ( last == -1 ) { /* not yet counted */ 
01321                      last = (*ap)->a_numvals;
01322               }
01323 
01324               if ( last == 0 ) {
01325                      /* empty? leave it in place because of attrsonly and vlv */
01326                      goto next_attr;
01327               }
01328               last--;
01329 
01330               if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
01331                             || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
01332               {
01333                      struct berval *bv;
01334                      
01335                      for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
01336                             struct berval mapped;
01337 
01338                             rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
01339                             if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
01340 remove_oc:;
01341                                    ch_free( bv[0].bv_val );
01342                                    BER_BVZERO( &bv[0] );
01343                                    if ( &(*ap)->a_vals[last] > &bv[0] ) {
01344                                           bv[0] = (*ap)->a_vals[last];
01345                                           BER_BVZERO( &(*ap)->a_vals[last] );
01346                                    }
01347                                    last--;
01348                                    bv--;
01349 
01350                             } else if ( mapped.bv_val != bv[0].bv_val
01351                                    && ber_bvstrcasecmp( &mapped, &bv[0] ) != 0 )
01352                             {
01353                                    int    i;
01354 
01355                                    for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
01356                                           if ( &(*ap)->a_vals[ i ] == bv ) {
01357                                                  continue;
01358                                           }
01359 
01360                                           if ( ber_bvstrcasecmp( &mapped, &(*ap)->a_vals[ i ] ) == 0 ) {
01361                                                  break;
01362                                           }
01363                                    }
01364 
01365                                    if ( !BER_BVISNULL( &(*ap)->a_vals[ i ] ) ) {
01366                                           goto remove_oc;
01367                                    }
01368 
01369                                    /*
01370                                     * FIXME: after LBER_FREEing
01371                                     * the value is replaced by
01372                                     * ch_alloc'ed memory
01373                                     */
01374                                    ber_bvreplace( &bv[0], &mapped );
01375 
01376                                    /* FIXME: will need to check
01377                                     * if the structuralObjectClass
01378                                     * changed */
01379                             }
01380                      }
01381 
01382               /*
01383                * It is necessary to try to rewrite attributes with
01384                * dn syntax because they might be used in ACLs as
01385                * members of groups; since ACLs are applied to the
01386                * rewritten stuff, no dn-based subject clause could
01387                * be used at the ldap backend side (see
01388                * http://www.OpenLDAP.org/faq/data/cache/452.html)
01389                * The problem can be overcome by moving the dn-based
01390                * ACLs to the target directory server, and letting
01391                * everything pass thru the ldap backend. */
01392               /* FIXME: handle distinguishedName-like syntaxes, like
01393                * nameAndOptionalUID */
01394               } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
01395                             || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
01396               {
01397                      dc.ctx = "searchAttrDN";
01398                      rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals, (*ap)->a_nvals );
01399                      if ( rc != LDAP_SUCCESS ) {
01400                             goto cleanup_attr;
01401                      }
01402 
01403               } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
01404                      dc.ctx = "searchAttrDN";
01405                      rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
01406                      if ( rc != LDAP_SUCCESS ) {
01407                             goto cleanup_attr;
01408                      }
01409               }
01410 
01411 
01412 next_attr:;
01413               ap = &(*ap)->a_next;
01414               continue;
01415 
01416 cleanup_attr:;
01417               a = *ap;
01418               *ap = (*ap)->a_next;
01419 
01420               attr_free( a );
01421        }
01422 
01423        /* only check if some mapping occurred */
01424        if ( check_duplicate_attrs ) {
01425               for ( ap = a_first; *ap != NULL; ap = &(*ap)->a_next ) {
01426                      Attribute     **tap;
01427 
01428                      for ( tap = &(*ap)->a_next; *tap != NULL; ) {
01429                             if ( (*tap)->a_desc == (*ap)->a_desc ) {
01430                                    Entry         e = { 0 };
01431                                    Modification  mod = { 0 };
01432                                    const char    *text = NULL;
01433                                    char          textbuf[ SLAP_TEXT_BUFLEN ];
01434                                    Attribute     *next = (*tap)->a_next;
01435 
01436                                    BER_BVSTR( &e.e_name, "" );
01437                                    BER_BVSTR( &e.e_nname, "" );
01438                                    e.e_attrs = *ap;
01439                                    mod.sm_op = LDAP_MOD_ADD;
01440                                    mod.sm_desc = (*ap)->a_desc;
01441                                    mod.sm_type = mod.sm_desc->ad_cname;
01442                                    mod.sm_numvals = (*tap)->a_numvals;
01443                                    mod.sm_values = (*tap)->a_vals;
01444                                    if ( (*tap)->a_nvals != (*tap)->a_vals ) {
01445                                           mod.sm_nvalues = (*tap)->a_nvals;
01446                                    }
01447 
01448                                    (void)modify_add_values( &e, &mod,
01449                                           /* permissive */ 1,
01450                                           &text, textbuf, sizeof( textbuf ) );
01451 
01452                                    /* should not insert new attrs! */
01453                                    assert( e.e_attrs == *ap );
01454 
01455                                    attr_free( *tap );
01456                                    *tap = next;
01457 
01458                             } else {
01459                                    tap = &(*tap)->a_next;
01460                             }
01461                      }
01462               }
01463        }
01464 
01465        return 0;
01466 }
01467 
01468 /* Should return SLAP_CB_CONTINUE or failure, never LDAP_SUCCESS. */
01469 static int
01470 rwm_send_entry( Operation *op, SlapReply *rs )
01471 {
01472        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
01473        struct ldaprwmap     *rwmap = 
01474                      (struct ldaprwmap *)on->on_bi.bi_private;
01475 
01476        Entry                *e = NULL;
01477        struct berval        dn = BER_BVNULL,
01478                             ndn = BER_BVNULL;
01479        dncookie             dc;
01480        int                  rc;
01481 
01482        assert( rs->sr_entry != NULL );
01483 
01484        /*
01485         * Rewrite the dn of the result, if needed
01486         */
01487        dc.rwmap = rwmap;
01488        dc.conn = op->o_conn;
01489        dc.rs = NULL; 
01490        dc.ctx = "searchEntryDN";
01491 
01492        e = rs->sr_entry;
01493        if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
01494               /* FIXME: all we need to duplicate are:
01495                * - dn
01496                * - ndn
01497                * - attributes that are requested
01498                * - no values if attrsonly is set
01499                */
01500               e = entry_dup( e );
01501               if ( e == NULL ) {
01502                      rc = LDAP_NO_MEMORY;
01503                      goto fail;
01504               }
01505        } else if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
01506               /* ITS#6423: REP_ENTRY_MUSTRELEASE incompatible
01507                * with REP_ENTRY_MODIFIABLE */
01508               RS_ASSERT( 0 );
01509               rc = 1;
01510               goto fail;
01511        }
01512 
01513        /*
01514         * Note: this may fail if the target host(s) schema differs
01515         * from the one known to the meta, and a DN with unknown
01516         * attributes is returned.
01517         */
01518        dn = e->e_name;
01519        ndn = e->e_nname;
01520        rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
01521        if ( rc != LDAP_SUCCESS ) {
01522               rc = 1;
01523               goto fail;
01524        }
01525 
01526        if ( e->e_name.bv_val != dn.bv_val ) {
01527               ch_free( e->e_name.bv_val );
01528               ch_free( e->e_nname.bv_val );
01529 
01530               e->e_name = dn;
01531               e->e_nname = ndn;
01532        }
01533 
01534        /* TODO: map entry attribute types, objectclasses 
01535         * and dn-valued attribute values */
01536 
01537        /* FIXME: the entries are in the remote mapping form;
01538         * so we need to select those attributes we are willing
01539         * to return, and remap them accordingly */
01540        (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
01541 
01542        if ( e != rs->sr_entry ) {
01543               /* Reimplementing rs_replace_entry(), I suppose to
01544                * bypass our own dubious rwm_entry_release_rw() */
01545               if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
01546                      rs->sr_flags ^= REP_ENTRY_MUSTRELEASE;
01547                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
01548                      be_entry_release_r( op, rs->sr_entry );
01549                      op->o_bd->bd_info = (BackendInfo *)on;
01550               } else if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
01551                      entry_free( rs->sr_entry );
01552               }
01553               rs->sr_entry = e;
01554               rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
01555        }
01556 
01557        return SLAP_CB_CONTINUE;
01558 
01559 fail:;
01560        if ( e != NULL && e != rs->sr_entry ) {
01561               if ( e->e_name.bv_val == dn.bv_val ) {
01562                      BER_BVZERO( &e->e_name );
01563               }
01564 
01565               if ( e->e_nname.bv_val == ndn.bv_val ) {
01566                      BER_BVZERO( &e->e_nname );
01567               }
01568 
01569               entry_free( e );
01570        }
01571 
01572        if ( !BER_BVISNULL( &dn ) ) {
01573               ch_free( dn.bv_val );
01574        }
01575 
01576        if ( !BER_BVISNULL( &ndn ) ) {
01577               ch_free( ndn.bv_val );
01578        }
01579 
01580        return rc;
01581 }
01582 
01583 static int
01584 rwm_operational( Operation *op, SlapReply *rs )
01585 {
01586        /* FIXME: the entries are in the remote mapping form;
01587         * so we need to select those attributes we are willing
01588         * to return, and remap them accordingly */
01589        if ( rs->sr_operational_attrs ) {
01590               rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
01591        }
01592 
01593        return SLAP_CB_CONTINUE;
01594 }
01595 
01596 #if 0
01597 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
01598  * rewritten for subsequent operations; fine for plain suffixmassage,
01599  * but destroys everything else */
01600 static int
01601 rwm_chk_referrals( Operation *op, SlapReply *rs )
01602 {
01603        slap_overinst        *on = (slap_overinst *) op->o_bd->bd_info;
01604        int                  rc;
01605 
01606        rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
01607        if ( rc != LDAP_SUCCESS ) {
01608               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01609               send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
01610               return -1;
01611        }
01612 
01613        return SLAP_CB_CONTINUE;
01614 }
01615 #endif
01616 
01617 static int
01618 rwm_rw_config(
01619        BackendDB     *be,
01620        const char    *fname,
01621        int           lineno,
01622        int           argc,
01623        char          **argv )
01624 {
01625        slap_overinst        *on = (slap_overinst *) be->bd_info;
01626        struct ldaprwmap     *rwmap = 
01627                      (struct ldaprwmap *)on->on_bi.bi_private;
01628 
01629        return rewrite_parse( rwmap->rwm_rw,
01630                             fname, lineno, argc, argv );
01631 
01632        return 0;
01633 }
01634 
01635 static int
01636 rwm_suffixmassage_config(
01637        BackendDB     *be,
01638        const char    *fname,
01639        int           lineno,
01640        int           argc,
01641        char          **argv )
01642 {
01643        slap_overinst        *on = (slap_overinst *) be->bd_info;
01644        struct ldaprwmap     *rwmap = 
01645                      (struct ldaprwmap *)on->on_bi.bi_private;
01646 
01647        struct berval        bvnc, nvnc, pvnc, brnc, nrnc, prnc;
01648        int                  massaged;
01649        int                  rc;
01650               
01651        /*
01652         * syntax:
01653         * 
01654         *     suffixmassage [<suffix>] <massaged suffix>
01655         *
01656         * the [<suffix>] field must be defined as a valid suffix
01657         * for the current database;
01658         * the <massaged suffix> shouldn't have already been
01659         * defined as a valid suffix for the current server
01660         */
01661        if ( argc == 2 ) {
01662               if ( be->be_suffix == NULL ) {
01663                      Debug( LDAP_DEBUG_ANY, "%s: line %d: "
01664                                    " \"suffixMassage [<suffix>]"
01665                                    " <massaged suffix>\" without "
01666                                    "<suffix> part requires database "
01667                                    "suffix be defined first.\n",
01668                             fname, lineno, 0 );
01669                      return 1;
01670               }
01671               bvnc = be->be_suffix[ 0 ];
01672               massaged = 1;
01673 
01674        } else if ( argc == 3 ) {
01675               ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
01676               massaged = 2;
01677 
01678        } else  {
01679               Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is"
01680                             " \"suffixMassage [<suffix>]"
01681                             " <massaged suffix>\"\n",
01682                      fname, lineno, 0 );
01683               return 1;
01684        }
01685 
01686        if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
01687               Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
01688                      fname, lineno, bvnc.bv_val );
01689               return 1;
01690        }
01691 
01692        ber_str2bv( argv[ massaged ], 0, 0, &brnc );
01693        if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
01694               Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
01695                             fname, lineno, brnc.bv_val );
01696               free( nvnc.bv_val );
01697               free( pvnc.bv_val );
01698               return 1;
01699        }
01700 
01701        /*
01702         * The suffix massaging is emulated 
01703         * by means of the rewrite capabilities
01704         */
01705        rc = rwm_suffix_massage_config( rwmap->rwm_rw,
01706                      &pvnc, &nvnc, &prnc, &nrnc );
01707        free( nvnc.bv_val );
01708        free( pvnc.bv_val );
01709        free( nrnc.bv_val );
01710        free( prnc.bv_val );
01711 
01712        return rc;
01713 }
01714 
01715 static int
01716 rwm_m_config(
01717        BackendDB     *be,
01718        const char    *fname,
01719        int           lineno,
01720        int           argc,
01721        char          **argv )
01722 {
01723        slap_overinst        *on = (slap_overinst *) be->bd_info;
01724        struct ldaprwmap     *rwmap = 
01725                      (struct ldaprwmap *)on->on_bi.bi_private;
01726 
01727        /* objectclass/attribute mapping */
01728        return rwm_map_config( &rwmap->rwm_oc,
01729                      &rwmap->rwm_at,
01730                      fname, lineno, argc, argv );
01731 }
01732 
01733 static int
01734 rwm_response( Operation *op, SlapReply *rs )
01735 {
01736        slap_overinst        *on = (slap_overinst *)op->o_bd->bd_info;
01737        struct ldaprwmap     *rwmap = 
01738                      (struct ldaprwmap *)on->on_bi.bi_private;
01739 
01740        int           rc;
01741 
01742        if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
01743               return rwm_send_entry( op, rs );
01744        }
01745 
01746        switch( op->o_tag ) {
01747        case LDAP_REQ_SEARCH:
01748        case LDAP_REQ_BIND:
01749        case LDAP_REQ_ADD:
01750        case LDAP_REQ_DELETE:
01751        case LDAP_REQ_MODRDN:
01752        case LDAP_REQ_MODIFY:
01753        case LDAP_REQ_COMPARE:
01754        case LDAP_REQ_EXTENDED:
01755               if ( rs->sr_ref ) {
01756                      dncookie             dc;
01757 
01758                      /*
01759                       * Rewrite the dn of the referrals, if needed
01760                       */
01761                      dc.rwmap = rwmap;
01762                      dc.conn = op->o_conn;
01763                      dc.rs = NULL; 
01764                      dc.ctx = "referralDN";
01765                      rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
01766                      /* FIXME: impossible, so far */
01767                      if ( rc != LDAP_SUCCESS ) {
01768                             rs->sr_err = rc;
01769                             break;
01770                      }
01771               }
01772 
01773               rwm_matched( op, rs );
01774               break;
01775        }
01776 
01777        return SLAP_CB_CONTINUE;
01778 }
01779 
01780 static int
01781 rwm_db_config(
01782        BackendDB     *be,
01783        const char    *fname,
01784        int           lineno,
01785        int           argc,
01786        char          **argv )
01787 {
01788        slap_overinst        *on = (slap_overinst *) be->bd_info;
01789        struct ldaprwmap     *rwmap = 
01790                      (struct ldaprwmap *)on->on_bi.bi_private;
01791 
01792        int           rc = 0;
01793        char          *argv0 = NULL;
01794 
01795        if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
01796               argv0 = argv[ 0 ];
01797               argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
01798        }
01799 
01800        if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
01801               rc = rwm_rw_config( be, fname, lineno, argc, argv );
01802 
01803        } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
01804               rc = rwm_m_config( be, fname, lineno, argc, argv );
01805 
01806        } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
01807               rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
01808 
01809        } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
01810               if ( argc != 2 ) {
01811                      Debug( LDAP_DEBUG_ANY,
01812               "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
01813                                    fname, lineno, 0 );
01814                      return( 1 );
01815               }
01816 
01817               if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
01818                      rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F_MASK2);
01819 
01820               } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
01821                      rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
01822 
01823               /* TODO: not implemented yet */
01824               } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
01825                      Debug( LDAP_DEBUG_ANY,
01826               "%s: line %d: \"discover\" not supported yet "
01827               "in \"t-f-support {no|yes|discover}\".\n",
01828                                    fname, lineno, 0 );
01829                      return( 1 );
01830 #if 0
01831                      rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
01832 #endif
01833 
01834               } else {
01835                      Debug( LDAP_DEBUG_ANY,
01836        "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
01837                             fname, lineno, argv[ 1 ] );
01838                      return 1;
01839               }
01840 
01841        } else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) ==  0 ) {
01842               if ( argc !=2 ) { 
01843                      Debug( LDAP_DEBUG_ANY,
01844               "%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
01845                                    fname, lineno, 0 );
01846                      return( 1 );
01847               }
01848 
01849               if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
01850                      rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
01851 
01852               } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
01853                      rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
01854               }
01855 
01856        } else {
01857               rc = SLAP_CONF_UNKNOWN;
01858        }
01859 
01860        if ( argv0 ) {
01861               argv[ 0 ] = argv0;
01862        }
01863 
01864        return rc;
01865 }
01866 
01867 /*
01868  * dynamic configuration...
01869  */
01870 
01871 enum {
01872        /* rewrite */
01873        RWM_CF_REWRITE = 1,
01874 
01875        /* map */
01876        RWM_CF_MAP,
01877        RWM_CF_T_F_SUPPORT,
01878        RWM_CF_NORMALIZE_MAPPED,
01879        RWM_CF_DROP_UNREQUESTED,
01880 
01881        RWM_CF_LAST
01882 };
01883 
01884 static slap_verbmasks t_f_mode[] = {
01885        { BER_BVC( "true" ),        RWM_F_SUPPORT_T_F },
01886        { BER_BVC( "yes" ),         RWM_F_SUPPORT_T_F },
01887        { BER_BVC( "discover" ),    RWM_F_SUPPORT_T_F_DISCOVER },
01888        { BER_BVC( "false" ),              RWM_F_NONE },
01889        { BER_BVC( "no" ),          RWM_F_NONE },
01890        { BER_BVNULL,               0 }
01891 };
01892 
01893 static ConfigDriver rwm_cf_gen;
01894 
01895 static ConfigTable rwmcfg[] = {
01896        { "rwm-rewrite", "rewrite",
01897               2, 0, STRLENOF("rwm-rewrite"),
01898               ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
01899               "( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
01900                      "DESC 'Rewrites strings' "
01901                      "EQUALITY caseIgnoreMatch "
01902                      "SYNTAX OMsDirectoryString "
01903                      "X-ORDERED 'VALUES' )",
01904               NULL, NULL },
01905 
01906        { "rwm-suffixmassage", "[virtual]> <real",
01907               2, 3, 0, ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
01908               NULL, NULL, NULL },
01909               
01910        { "rwm-t-f-support", "true|false|discover",
01911               2, 2, 0, ARG_MAGIC|RWM_CF_T_F_SUPPORT, rwm_cf_gen,
01912               "( OLcfgOvAt:16.2 NAME 'olcRwmTFSupport' "
01913                      "DESC 'Absolute filters support' "
01914                      "SYNTAX OMsDirectoryString "
01915                      "SINGLE-VALUE )",
01916               NULL, NULL },
01917 
01918        { "rwm-map", "{objectClass|attribute}",
01919               2, 4, 0, ARG_MAGIC|RWM_CF_MAP, rwm_cf_gen,
01920               "( OLcfgOvAt:16.3 NAME 'olcRwmMap' "
01921                      "DESC 'maps attributes/objectClasses' "
01922                      "EQUALITY caseIgnoreMatch "
01923                      "SYNTAX OMsDirectoryString "
01924                      "X-ORDERED 'VALUES' )",
01925               NULL, NULL },
01926 
01927        { "rwm-normalize-mapped-attrs", "true|false",
01928               2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_NORMALIZE_MAPPED, rwm_cf_gen,
01929               "( OLcfgOvAt:16.4 NAME 'olcRwmNormalizeMapped' "
01930                      "DESC 'Normalize mapped attributes/objectClasses' "
01931                      "SYNTAX OMsBoolean "
01932                      "SINGLE-VALUE )",
01933               NULL, NULL },
01934 
01935        { "rwm-drop-unrequested-attrs", "true|false",
01936               2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_DROP_UNREQUESTED, rwm_cf_gen,
01937               "( OLcfgOvAt:16.5 NAME 'olcRwmDropUnrequested' "
01938                      "DESC 'Drop unrequested attributes' "
01939                      "SYNTAX OMsBoolean "
01940                      "SINGLE-VALUE )",
01941               NULL, NULL },
01942 
01943        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
01944 };
01945 
01946 static ConfigOCs rwmocs[] = {
01947        { "( OLcfgOvOc:16.1 "
01948               "NAME 'olcRwmConfig' "
01949               "DESC 'Rewrite/remap configuration' "
01950               "SUP olcOverlayConfig "
01951               "MAY ( "
01952                      "olcRwmRewrite $ "
01953                      "olcRwmTFSupport $ "
01954                      "olcRwmMap $ "
01955                      "olcRwmNormalizeMapped "
01956                      ") )",
01957               Cft_Overlay, rwmcfg, NULL, NULL },
01958        { NULL, 0, NULL }
01959 };
01960 
01961 static void
01962 slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
01963 {
01964        int           i;
01965        BerVarray     bva = NULL;
01966        char          ibuf[32], *ptr;
01967        struct berval idx;
01968 
01969        assert( in != NULL );
01970 
01971        for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
01972               /* count'em */ ;
01973 
01974        if ( i == 0 ) {
01975               return;
01976        }
01977 
01978        idx.bv_val = ibuf;
01979 
01980        bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
01981        BER_BVZERO( &bva[ 0 ] );
01982 
01983        for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
01984               idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
01985               if ( idx.bv_len >= sizeof( ibuf ) ) {
01986                      ber_bvarray_free( bva );
01987                      return;
01988               }
01989 
01990               bva[i].bv_len = idx.bv_len + in[i].bv_len;
01991               bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
01992               ptr = lutil_strcopy( bva[i].bv_val, ibuf );
01993               ptr = lutil_strcopy( ptr, in[i].bv_val );
01994               *ptr = '\0';
01995               BER_BVZERO( &bva[ i + 1 ] );
01996        }
01997 
01998        *out = bva;
01999 }
02000 
02001 static int
02002 rwm_bva_add(
02003        BerVarray            *bva,
02004        int                  idx,
02005        char                 **argv )
02006 {
02007        char          *line;
02008        struct berval bv;
02009 
02010        line = ldap_charray2str( argv, "\" \"" );
02011        if ( line != NULL ) {
02012               int    len = strlen( argv[ 0 ] );
02013 
02014               ber_str2bv( line, 0, 0, &bv );
02015               AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
02016                      bv.bv_len - ( len + 1 ) );
02017               bv.bv_val[ bv.bv_len - 1 ] = '"';
02018 
02019               if ( idx == -1 ) {
02020                      ber_bvarray_add( bva, &bv );
02021 
02022               } else {
02023                      (*bva)[ idx ] = bv;
02024               }
02025 
02026               return 0;
02027        }
02028 
02029        return -1;
02030 }
02031 
02032 static int
02033 rwm_bva_rewrite_add(
02034        struct ldaprwmap     *rwmap,
02035        int                  idx,
02036        char                 **argv )
02037 {
02038        return rwm_bva_add( &rwmap->rwm_bva_rewrite, idx, argv );
02039 }
02040 
02041 #ifdef unused
02042 static int
02043 rwm_bva_map_add(
02044        struct ldaprwmap     *rwmap,
02045        int                  idx,
02046        char                 **argv )
02047 {
02048        return rwm_bva_add( &rwmap->rwm_bva_map, idx, argv );
02049 }
02050 #endif /* unused */
02051 
02052 static int
02053 rwm_info_init( struct rewrite_info ** rwm_rw )
02054 {
02055        char                 *rargv[ 3 ];
02056 
02057        *rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
02058        if ( *rwm_rw == NULL ) {
02059               return -1;
02060        }
02061 
02062        /* this rewriteContext by default must be null;
02063         * rules can be added if required */
02064        rargv[ 0 ] = "rewriteContext";
02065        rargv[ 1 ] = "searchFilter";
02066        rargv[ 2 ] = NULL;
02067        rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
02068 
02069        rargv[ 0 ] = "rewriteContext";
02070        rargv[ 1 ] = "default";
02071        rargv[ 2 ] = NULL;
02072        rewrite_parse( *rwm_rw, "<suffix massage>", 2, 2, rargv );
02073 
02074        return 0;
02075 }
02076 
02077 static int
02078 rwm_cf_gen( ConfigArgs *c )
02079 {
02080        slap_overinst        *on = (slap_overinst *)c->bi;
02081        struct ldaprwmap     *rwmap = 
02082                      (struct ldaprwmap *)on->on_bi.bi_private;
02083 
02084        BackendDB            db;
02085        char                 *argv0;
02086        int                  idx0 = 0;
02087        int                  rc = 0;
02088 
02089        db = *c->be;
02090        db.bd_info = c->bi;
02091 
02092        if ( c->op == SLAP_CONFIG_EMIT ) {
02093               struct berval bv = BER_BVNULL;
02094 
02095               switch ( c->type ) {
02096               case RWM_CF_REWRITE:
02097                      if ( rwmap->rwm_bva_rewrite == NULL ) {
02098                             rc = 1;
02099 
02100                      } else {
02101                             slap_bv_x_ordered_unparse( rwmap->rwm_bva_rewrite, &c->rvalue_vals );
02102                             if ( !c->rvalue_vals ) {
02103                                    rc = 1;
02104                             }
02105                      }
02106                      break;
02107 
02108               case RWM_CF_T_F_SUPPORT:
02109                      enum_to_verb( t_f_mode, (rwmap->rwm_flags & RWM_F_SUPPORT_T_F_MASK2), &bv );
02110                      if ( BER_BVISNULL( &bv ) ) {
02111                             /* there's something wrong... */
02112                             assert( 0 );
02113                             rc = 1;
02114 
02115                      } else {
02116                             value_add_one( &c->rvalue_vals, &bv );
02117                      }
02118                      break;
02119 
02120               case RWM_CF_MAP:
02121                      if ( rwmap->rwm_bva_map == NULL ) {
02122                             rc = 1;
02123 
02124                      } else {
02125                             slap_bv_x_ordered_unparse( rwmap->rwm_bva_map, &c->rvalue_vals );
02126                             if ( !c->rvalue_vals ) {
02127                                    rc = 1;
02128                             }
02129                      }
02130                      break;
02131 
02132               case RWM_CF_NORMALIZE_MAPPED:
02133                      c->value_int = ( rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS );
02134                      break;
02135 
02136               case RWM_CF_DROP_UNREQUESTED:
02137                      c->value_int = ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS );
02138                      break;
02139 
02140               default:
02141                      assert( 0 );
02142                      rc = 1;
02143               }
02144 
02145               return rc;
02146 
02147        } else if ( c->op == LDAP_MOD_DELETE ) {
02148               switch ( c->type ) {
02149               case RWM_CF_REWRITE:
02150                      if ( c->valx >= 0 ) {
02151                             int i;
02152 
02153                             for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
02154                                    /* count'em */ ;
02155 
02156                             if ( c->valx >= i ) {
02157                                    rc = 1;
02158                                    break;
02159                             }
02160 
02161                             ber_memfree( rwmap->rwm_bva_rewrite[ c->valx ].bv_val );
02162                             for ( i = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i + 1 ] ); i++ )
02163                             {
02164                                    rwmap->rwm_bva_rewrite[ i ] = rwmap->rwm_bva_rewrite[ i + 1 ];
02165                             }
02166                             BER_BVZERO( &rwmap->rwm_bva_rewrite[ i ] );
02167 
02168                             rewrite_info_delete( &rwmap->rwm_rw );
02169                             assert( rwmap->rwm_rw == NULL );
02170 
02171                             rc = rwm_info_init( &rwmap->rwm_rw );
02172 
02173                             for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
02174                             {
02175                                    ConfigArgs ca = { 0 };
02176 
02177                                    ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
02178                                    ca.argc = 0;
02179                                    config_fp_parse_line( &ca );
02180                                    
02181                                    if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
02182                                           rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
02183                                                  ca.argc, ca.argv );
02184 
02185                                    } else {
02186                                           rc = rwm_rw_config( &db, c->fname, c->lineno,
02187                                                  ca.argc, ca.argv );
02188                                    }
02189 
02190                                    ch_free( ca.tline );
02191                                    ch_free( ca.argv );
02192 
02193                                    assert( rc == 0 );
02194                             }
02195 
02196                      } else if ( rwmap->rwm_rw != NULL ) {
02197                             rewrite_info_delete( &rwmap->rwm_rw );
02198                             assert( rwmap->rwm_rw == NULL );
02199 
02200                             ber_bvarray_free( rwmap->rwm_bva_rewrite );
02201                             rwmap->rwm_bva_rewrite = NULL;
02202 
02203                             rc = rwm_info_init( &rwmap->rwm_rw );
02204                      }
02205                      break;
02206 
02207               case RWM_CF_T_F_SUPPORT:
02208                      rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
02209                      break;
02210 
02211               case RWM_CF_MAP:
02212                      if ( c->valx >= 0 ) {
02213                             struct ldapmap rwm_oc = rwmap->rwm_oc;
02214                             struct ldapmap rwm_at = rwmap->rwm_at;
02215                             char *argv[5];
02216                             int cnt = 0;
02217 
02218                             if ( rwmap->rwm_bva_map ) {
02219                                    for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
02220                                           /* count */ ;
02221                             }
02222 
02223                             if ( c->valx >= cnt ) {
02224                                    rc = 1;
02225                                    break;
02226                             }
02227 
02228                             memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
02229                             memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
02230 
02231                             /* re-parse all mappings except the one
02232                              * that needs to be eliminated */
02233                             argv[0] = "map";
02234                             for ( cnt = 0; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
02235                                    ConfigArgs ca = { 0 };
02236 
02237                                    if ( cnt == c->valx ) {
02238                                           continue;
02239                                    }
02240 
02241                                    ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
02242                                    ca.argc = 0;
02243                                    config_fp_parse_line( &ca );
02244                                    
02245                                    argv[1] = ca.argv[0];
02246                                    argv[2] = ca.argv[1];
02247                                    argv[3] = ca.argv[2];
02248                                    argv[4] = ca.argv[3];
02249                      
02250                                    rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
02251 
02252                                    ch_free( ca.tline );
02253                                    ch_free( ca.argv );
02254 
02255                                    /* in case of failure, restore
02256                                     * the existing mapping */
02257                                    if ( rc ) {
02258                                           avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
02259                                           avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
02260                                           avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
02261                                           avl_free( rwmap->rwm_at.map, rwm_mapping_free );
02262                                           rwmap->rwm_oc = rwm_oc;
02263                                           rwmap->rwm_at = rwm_at;
02264                                           break;
02265                                    }
02266                             }
02267 
02268                             /* in case of success, destroy the old mapping
02269                              * and eliminate the deleted one */
02270                             if ( rc == 0 ) {
02271                                    avl_free( rwm_oc.remap, rwm_mapping_dst_free );
02272                                    avl_free( rwm_oc.map, rwm_mapping_free );
02273                                    avl_free( rwm_at.remap, rwm_mapping_dst_free );
02274                                    avl_free( rwm_at.map, rwm_mapping_free );
02275 
02276                                    ber_memfree( rwmap->rwm_bva_map[ c->valx ].bv_val );
02277                                    for ( cnt = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
02278                                           rwmap->rwm_bva_map[ cnt ] = rwmap->rwm_bva_map[ cnt + 1 ];
02279                                    }
02280                             }
02281 
02282                      } else {
02283                             avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
02284                             avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
02285                             avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
02286                             avl_free( rwmap->rwm_at.map, rwm_mapping_free );
02287 
02288                             rwmap->rwm_oc.remap = NULL;
02289                             rwmap->rwm_oc.map = NULL;
02290                             rwmap->rwm_at.remap = NULL;
02291                             rwmap->rwm_at.map = NULL;
02292 
02293                             ber_bvarray_free( rwmap->rwm_bva_map );
02294                             rwmap->rwm_bva_map = NULL;
02295                      }
02296                      break;
02297 
02298               case RWM_CF_NORMALIZE_MAPPED:
02299                      rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
02300                      break;
02301 
02302               case RWM_CF_DROP_UNREQUESTED:
02303                      rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
02304                      break;
02305 
02306               default:
02307                      return 1;
02308               }
02309               return rc;
02310        }
02311 
02312        if ( strncasecmp( c->argv[ 0 ], "olcRwm", STRLENOF( "olcRwm" ) ) == 0 ) {
02313               idx0 = 1;
02314        }
02315 
02316        switch ( c->type ) {
02317        case RWM_CF_REWRITE:
02318               if ( c->valx >= 0 ) {
02319                      struct rewrite_info *rwm_rw = rwmap->rwm_rw;
02320                      int i, last;
02321 
02322                      for ( last = 0; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ last ] ); last++ )
02323                             /* count'em */ ;
02324 
02325                      if ( c->valx > last ) {
02326                             c->valx = last;
02327                      }
02328 
02329                      rwmap->rwm_rw = NULL;
02330                      rc = rwm_info_init( &rwmap->rwm_rw );
02331 
02332                      for ( i = 0; i < c->valx; i++ ) {
02333                             ConfigArgs ca = { 0 };
02334 
02335                             ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
02336                             ca.argc = 0;
02337                             config_fp_parse_line( &ca );
02338 
02339                             argv0 = ca.argv[ 0 ];
02340                             ca.argv[ 0 ] += STRLENOF( "rwm-" );
02341                             
02342                             if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
02343                                    rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
02344                                           ca.argc, ca.argv );
02345 
02346                             } else {
02347                                    rc = rwm_rw_config( &db, c->fname, c->lineno,
02348                                           ca.argc, ca.argv );
02349                             }
02350 
02351                             ca.argv[ 0 ] = argv0;
02352 
02353                             ch_free( ca.tline );
02354                             ch_free( ca.argv );
02355 
02356                             assert( rc == 0 );
02357                      }
02358 
02359                      argv0 = c->argv[ idx0 ];
02360                      if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
02361                             return 1;
02362                      }
02363                      c->argv[ idx0 ] += STRLENOF( "rwm-" );
02364                      if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
02365                             rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
02366                                    c->argc - idx0, &c->argv[ idx0 ] );
02367 
02368                      } else {
02369                             rc = rwm_rw_config( &db, c->fname, c->lineno,
02370                                    c->argc - idx0, &c->argv[ idx0 ] );
02371                      }
02372                      c->argv[ idx0 ] = argv0;
02373                      if ( rc != 0 ) {
02374                             rewrite_info_delete( &rwmap->rwm_rw );
02375                             assert( rwmap->rwm_rw == NULL );
02376 
02377                             rwmap->rwm_rw = rwm_rw;
02378                             return 1;
02379                      }
02380 
02381                      for ( i = c->valx; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
02382                      {
02383                             ConfigArgs ca = { 0 };
02384 
02385                             ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
02386                             ca.argc = 0;
02387                             config_fp_parse_line( &ca );
02388                             
02389                             argv0 = ca.argv[ 0 ];
02390                             ca.argv[ 0 ] += STRLENOF( "rwm-" );
02391                             
02392                             if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
02393                                    rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
02394                                           ca.argc, ca.argv );
02395 
02396                             } else {
02397                                    rc = rwm_rw_config( &db, c->fname, c->lineno,
02398                                           ca.argc, ca.argv );
02399                             }
02400 
02401                             ca.argv[ 0 ] = argv0;
02402 
02403                             ch_free( ca.tline );
02404                             ch_free( ca.argv );
02405 
02406                             assert( rc == 0 );
02407                      }
02408 
02409                      rwmap->rwm_bva_rewrite = ch_realloc( rwmap->rwm_bva_rewrite,
02410                             ( last + 2 )*sizeof( struct berval ) );
02411                      BER_BVZERO( &rwmap->rwm_bva_rewrite[last+1] );
02412 
02413                      for ( i = last - 1; i >= c->valx; i-- )
02414                      {
02415                             rwmap->rwm_bva_rewrite[ i + 1 ] = rwmap->rwm_bva_rewrite[ i ];
02416                      }
02417 
02418                      rwm_bva_rewrite_add( rwmap, c->valx, &c->argv[ idx0 ] );
02419 
02420                      rewrite_info_delete( &rwm_rw );
02421                      assert( rwm_rw == NULL );
02422 
02423                      break;
02424               }
02425 
02426               argv0 = c->argv[ idx0 ];
02427               if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
02428                      return 1;
02429               }
02430               c->argv[ idx0 ] += STRLENOF( "rwm-" );
02431               if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
02432                      rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
02433                             c->argc - idx0, &c->argv[ idx0 ] );
02434 
02435               } else {
02436                      rc = rwm_rw_config( &db, c->fname, c->lineno,
02437                             c->argc - idx0, &c->argv[ idx0 ] );
02438               }
02439               c->argv[ idx0 ] = argv0;
02440               if ( rc ) {
02441                      return 1;
02442 
02443               } else {
02444                      rwm_bva_rewrite_add( rwmap, -1, &c->argv[ idx0 ] );
02445               }
02446               break;
02447 
02448        case RWM_CF_T_F_SUPPORT:
02449               rc = verb_to_mask( c->argv[ 1 ], t_f_mode );
02450               if ( BER_BVISNULL( &t_f_mode[ rc ].word ) ) {
02451                      return 1;
02452               }
02453 
02454               rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
02455               rwmap->rwm_flags |= t_f_mode[ rc ].mask;
02456               rc = 0;
02457               break;
02458 
02459        case RWM_CF_MAP:
02460               if ( c->valx >= 0 ) {
02461                      struct ldapmap rwm_oc = rwmap->rwm_oc;
02462                      struct ldapmap rwm_at = rwmap->rwm_at;
02463                      char *argv[5];
02464                      int cnt = 0;
02465 
02466                      if ( rwmap->rwm_bva_map ) {
02467                             for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
02468                                    /* count */ ;
02469                      }
02470 
02471                      if ( c->valx >= cnt ) {
02472                             c->valx = cnt;
02473                      }
02474 
02475                      memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
02476                      memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
02477 
02478                      /* re-parse all mappings, including the one
02479                       * that needs to be added */
02480                      argv[0] = "map";
02481                      for ( cnt = 0; cnt < c->valx; cnt++ ) {
02482                             ConfigArgs ca = { 0 };
02483 
02484                             ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
02485                             ca.argc = 0;
02486                             config_fp_parse_line( &ca );
02487 
02488                             argv[1] = ca.argv[0];
02489                             argv[2] = ca.argv[1];
02490                             argv[3] = ca.argv[2];
02491                             argv[4] = ca.argv[3];
02492                      
02493                             rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
02494 
02495                             ch_free( ca.tline );
02496                             ch_free( ca.argv );
02497 
02498                             /* in case of failure, restore
02499                              * the existing mapping */
02500                             if ( rc ) {
02501                                    goto rwmmap_fail;
02502                             }
02503                      }
02504 
02505                      argv0 = c->argv[0];
02506                      c->argv[0] = "map";
02507                      rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
02508                      c->argv[0] = argv0;
02509                      if ( rc ) {
02510                             goto rwmmap_fail;
02511                      }
02512 
02513                      if ( rwmap->rwm_bva_map ) {
02514                             for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
02515                                    ConfigArgs ca = { 0 };
02516 
02517                                    ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
02518                                    ca.argc = 0;
02519                                    config_fp_parse_line( &ca );
02520                      
02521                                    argv[1] = ca.argv[0];
02522                                    argv[2] = ca.argv[1];
02523                                    argv[3] = ca.argv[2];
02524                                    argv[4] = ca.argv[3];
02525                      
02526                                    rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
02527 
02528                                    ch_free( ca.tline );
02529                                    ch_free( ca.argv );
02530 
02531                                    /* in case of failure, restore
02532                                     * the existing mapping */
02533                                    if ( rc ) {
02534                                           goto rwmmap_fail;
02535                                    }
02536                             }
02537                      }
02538 
02539                      /* in case of success, destroy the old mapping
02540                       * and add the new one */
02541                      if ( rc == 0 ) {
02542                             BerVarray tmp;
02543                             struct berval bv, *bvp = &bv;
02544 
02545                             if ( rwm_bva_add( &bvp, 0, &c->argv[ idx0 ] ) ) {
02546                                    rc = 1;
02547                                    goto rwmmap_fail;
02548                             }
02549                                    
02550                             tmp = ber_memrealloc( rwmap->rwm_bva_map,
02551                                    sizeof( struct berval )*( cnt + 2 ) );
02552                             if ( tmp == NULL ) {
02553                                    ber_memfree( bv.bv_val );
02554                                    rc = 1;
02555                                    goto rwmmap_fail;
02556                             }
02557                             rwmap->rwm_bva_map = tmp;
02558                             BER_BVZERO( &rwmap->rwm_bva_map[ cnt + 1 ] );
02559 
02560                             avl_free( rwm_oc.remap, rwm_mapping_dst_free );
02561                             avl_free( rwm_oc.map, rwm_mapping_free );
02562                             avl_free( rwm_at.remap, rwm_mapping_dst_free );
02563                             avl_free( rwm_at.map, rwm_mapping_free );
02564 
02565                             for ( ; cnt-- > c->valx; ) {
02566                                    rwmap->rwm_bva_map[ cnt + 1 ] = rwmap->rwm_bva_map[ cnt ];
02567                             }
02568                             rwmap->rwm_bva_map[ c->valx ] = bv;
02569 
02570                      } else {
02571 rwmmap_fail:;
02572                             avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
02573                             avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
02574                             avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
02575                             avl_free( rwmap->rwm_at.map, rwm_mapping_free );
02576                             rwmap->rwm_oc = rwm_oc;
02577                             rwmap->rwm_at = rwm_at;
02578                      }
02579 
02580                      break;
02581               }
02582 
02583               argv0 = c->argv[ 0 ];
02584               c->argv[ 0 ] += STRLENOF( "rwm-" );
02585               rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
02586               c->argv[ 0 ] = argv0;
02587               if ( rc ) {
02588                      return 1;
02589 
02590               } else {
02591                      char          *line;
02592                      struct berval bv;
02593 
02594                      line = ldap_charray2str( &c->argv[ 1 ], " " );
02595                      if ( line != NULL ) {
02596                             ber_str2bv( line, 0, 0, &bv );
02597                             ber_bvarray_add( &rwmap->rwm_bva_map, &bv );
02598                      }
02599               }
02600               break;
02601 
02602        case RWM_CF_NORMALIZE_MAPPED:
02603               if ( c->value_int ) {
02604                      rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
02605               } else {
02606                      rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
02607               }
02608               break;
02609 
02610        case RWM_CF_DROP_UNREQUESTED:
02611               if ( c->value_int ) {
02612                      rwmap->rwm_flags |= RWM_F_DROP_UNREQUESTED_ATTRS;
02613               } else {
02614                      rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
02615               }
02616               break;
02617 
02618        default:
02619               assert( 0 );
02620               return 1;
02621        }
02622 
02623        return rc;
02624 }
02625 
02626 static int
02627 rwm_db_init(
02628        BackendDB     *be,
02629        ConfigReply   *cr )
02630 {
02631        slap_overinst        *on = (slap_overinst *) be->bd_info;
02632        struct ldaprwmap     *rwmap;
02633        int                  rc = 0;
02634 
02635        rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
02636 
02637        /* default */
02638        rwmap->rwm_flags = RWM_F_DROP_UNREQUESTED_ATTRS;
02639 
02640        rc = rwm_info_init( &rwmap->rwm_rw );
02641 
02642        on->on_bi.bi_private = (void *)rwmap;
02643 
02644        if ( rc ) {
02645               (void)rwm_db_destroy( be, NULL );
02646        }
02647 
02648        return rc;
02649 }
02650 
02651 static int
02652 rwm_db_destroy(
02653        BackendDB     *be,
02654        ConfigReply   *cr )
02655 {
02656        slap_overinst *on = (slap_overinst *) be->bd_info;
02657        int           rc = 0;
02658 
02659        if ( on->on_bi.bi_private ) {
02660               struct ldaprwmap     *rwmap = 
02661                      (struct ldaprwmap *)on->on_bi.bi_private;
02662 
02663               if ( rwmap->rwm_rw ) {
02664                      rewrite_info_delete( &rwmap->rwm_rw );
02665                      if ( rwmap->rwm_bva_rewrite )
02666                             ber_bvarray_free( rwmap->rwm_bva_rewrite );
02667               }
02668 
02669               avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
02670               avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
02671               avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
02672               avl_free( rwmap->rwm_at.map, rwm_mapping_free );
02673               ber_bvarray_free( rwmap->rwm_bva_map );
02674 
02675               ch_free( rwmap );
02676        }
02677 
02678        return rc;
02679 }
02680 
02681 static slap_overinst rwm = { { NULL } };
02682 
02683 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
02684 static
02685 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
02686 int
02687 rwm_initialize( void )
02688 {
02689        int           rc;
02690 
02691        /* Make sure we don't exceed the bits reserved for userland */
02692        config_check_userland( RWM_CF_LAST );
02693 
02694        memset( &rwm, 0, sizeof( slap_overinst ) );
02695 
02696        rwm.on_bi.bi_type = "rwm";
02697        rwm.on_bi.bi_flags =
02698               SLAPO_BFLAG_SINGLE |
02699               0;
02700 
02701        rwm.on_bi.bi_db_init = rwm_db_init;
02702        rwm.on_bi.bi_db_config = rwm_db_config;
02703        rwm.on_bi.bi_db_destroy = rwm_db_destroy;
02704 
02705        rwm.on_bi.bi_op_bind = rwm_op_bind;
02706        rwm.on_bi.bi_op_search = rwm_op_search;
02707        rwm.on_bi.bi_op_compare = rwm_op_compare;
02708        rwm.on_bi.bi_op_modify = rwm_op_modify;
02709        rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
02710        rwm.on_bi.bi_op_add = rwm_op_add;
02711        rwm.on_bi.bi_op_delete = rwm_op_delete;
02712        rwm.on_bi.bi_op_unbind = rwm_op_unbind;
02713        rwm.on_bi.bi_extended = rwm_extended;
02714 #if 1 /* TODO */
02715        rwm.on_bi.bi_entry_release_rw = rwm_entry_release_rw;
02716        rwm.on_bi.bi_entry_get_rw = rwm_entry_get_rw;
02717 #endif
02718 
02719        rwm.on_bi.bi_operational = rwm_operational;
02720        rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
02721 
02722        rwm.on_bi.bi_connection_init = rwm_conn_init;
02723        rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
02724 
02725        rwm.on_response = rwm_response;
02726 
02727        rwm.on_bi.bi_cf_ocs = rwmocs;
02728 
02729        rc = config_register_schema( rwmcfg, rwmocs );
02730        if ( rc ) {
02731               return rc;
02732        }
02733 
02734        return overlay_register( &rwm );
02735 }
02736 
02737 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
02738 int
02739 init_module( int argc, char *argv[] )
02740 {
02741        return rwm_initialize();
02742 }
02743 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
02744 
02745 #endif /* SLAPD_OVER_RWM */