Back to index

openldap  2.4.31
memberof.c
Go to the documentation of this file.
00001 /* memberof.c - back-reference for group membership */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2005-2007 Pierangelo Masarati <ando@sys-net.it>
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGMENTS:
00017  * This work was initially developed by Pierangelo Masarati for inclusion
00018  * in OpenLDAP Software, sponsored by SysNet s.r.l.
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #ifdef SLAPD_OVER_MEMBEROF
00024 
00025 #include <stdio.h>
00026 
00027 #include "ac/string.h"
00028 #include "ac/socket.h"
00029 
00030 #include "slap.h"
00031 #include "config.h"
00032 #include "lutil.h"
00033 
00034 /*
00035  *     Glossary:
00036  *
00037  *            GROUP         a group object (an entry with GROUP_OC
00038  *                          objectClass)
00039  *            MEMBER        a member object (an entry whose DN is
00040  *                          listed as MEMBER_AT value of a GROUP)
00041  *            GROUP_OC      the objectClass of the group object
00042  *                          (default: groupOfNames)
00043  *            MEMBER_AT     the membership attribute, DN-valued;
00044  *                          note: nameAndOptionalUID is tolerated
00045  *                          as soon as the optionalUID is absent
00046  *                          (default: member)
00047  *            MEMBER_OF     reverse membership attribute
00048  *                          (default: memberOf)
00049  *
00050  *     - add:
00051  *            - if the entry that is being added is a GROUP,
00052  *              the MEMBER_AT defined as values of the add operation
00053  *              get the MEMBER_OF value directly from the request.
00054  *
00055  *              if configured to do so, the MEMBER objects do not exist,
00056  *              and no relax control is issued, either:
00057  *                   - fail
00058  *                   - drop non-existing members
00059  *              (by default: don't muck with values)
00060  *
00061  *            - if (configured to do so,) the referenced GROUP exists,
00062  *              the relax control is set and the user has
00063  *              "manage" privileges, allow to add MEMBER_OF values to
00064  *              generic entries.
00065  *
00066  *     - modify:
00067  *            - if the entry being modified is a GROUP_OC and the 
00068  *              MEMBER_AT attribute is modified, the MEMBER_OF value
00069  *              of the (existing) MEMBER_AT entries that are affected
00070  *              is modified according to the request:
00071  *                   - if a MEMBER is removed from the group,
00072  *                     delete the corresponding MEMBER_OF
00073  *                   - if a MEMBER is added to a group,
00074  *                     add the corresponding MEMBER_OF
00075  *
00076  *              We need to determine, from the database, if it is
00077  *              a GROUP_OC, and we need to check, from the
00078  *              modification list, if the MEMBER_AT attribute is being
00079  *              affected, and what MEMBER_AT values are affected.
00080  *
00081  *              if configured to do so, the entries corresponding to
00082  *              the MEMBER_AT values do not exist, and no relax control
00083  *              is issued, either:
00084  *                   - fail
00085  *                   - drop non-existing members
00086  *              (by default: don't muck with values)
00087  *
00088  *            - if configured to do so, the referenced GROUP exists,
00089  *              (the relax control is set) and the user has
00090  *              "manage" privileges, allow to add MEMBER_OF values to
00091  *              generic entries; the change is NOT automatically reflected
00092  *              in the MEMBER attribute of the GROUP referenced
00093  *              by the value of MEMBER_OF; a separate modification,
00094  *              with or without relax control, needs to be performed.
00095  *
00096  *     - modrdn:
00097  *            - if the entry being renamed is a GROUP, the MEMBER_OF
00098  *              value of the (existing) MEMBER objects is modified
00099  *              accordingly based on the newDN of the GROUP.
00100  *
00101  *              We need to determine, from the database, if it is
00102  *              a GROUP; the list of MEMBER objects is obtained from
00103  *              the database.
00104  *
00105  *              Non-existing MEMBER objects are ignored, since the
00106  *              MEMBER_AT is not being addressed by the operation.
00107  *
00108  *            - if the entry being renamed has the MEMBER_OF attribute,
00109  *              the corresponding MEMBER value must be modified in the
00110  *              respective group entries.
00111  *            
00112  *
00113  *     - delete:
00114  *            - if the entry being deleted is a GROUP, the (existing)
00115  *              MEMBER objects are modified accordingly; a copy of the 
00116  *              values of the MEMBER_AT is saved and, if the delete 
00117  *              succeeds, the MEMBER_OF value of the (existing) MEMBER
00118  *              objects is deleted.
00119  *
00120  *              We need to determine, from the database, if it is
00121  *              a GROUP.
00122  *
00123  *              Non-existing MEMBER objects are ignored, since the entry
00124  *              is being deleted.
00125  *
00126  *            - if the entry being deleted has the MEMBER_OF attribute,
00127  *              the corresponding value of the MEMBER_AT must be deleted
00128  *              from the respective GROUP entries.
00129  */
00130 
00131 #define       SLAPD_MEMBEROF_ATTR  "memberOf"
00132 
00133 static slap_overinst        memberof;
00134 
00135 typedef struct memberof_t {
00136        struct berval        mo_dn;
00137        struct berval        mo_ndn;
00138 
00139        ObjectClass          *mo_oc_group;
00140        AttributeDescription *mo_ad_member;
00141        AttributeDescription *mo_ad_memberof;
00142        
00143        struct berval        mo_groupFilterstr;
00144        AttributeAssertion   mo_groupAVA;
00145        Filter               mo_groupFilter;
00146 
00147        struct berval        mo_memberFilterstr;
00148        Filter               mo_memberFilter;
00149 
00150        unsigned             mo_flags;
00151 #define       MEMBEROF_NONE        0x00U
00152 #define       MEMBEROF_FDANGLING_DROP     0x01U
00153 #define       MEMBEROF_FDANGLING_ERROR    0x02U
00154 #define       MEMBEROF_FDANGLING_MASK     (MEMBEROF_FDANGLING_DROP|MEMBEROF_FDANGLING_ERROR)
00155 #define       MEMBEROF_FREFINT     0x04U
00156 #define       MEMBEROF_FREVERSE    0x08U
00157 
00158        ber_int_t            mo_dangling_err;
00159 
00160 #define MEMBEROF_CHK(mo,f) \
00161        (((mo)->mo_flags & (f)) == (f))
00162 #define MEMBEROF_DANGLING_CHECK(mo) \
00163        ((mo)->mo_flags & MEMBEROF_FDANGLING_MASK)
00164 #define MEMBEROF_DANGLING_DROP(mo) \
00165        MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_DROP)
00166 #define MEMBEROF_DANGLING_ERROR(mo) \
00167        MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_ERROR)
00168 #define MEMBEROF_REFINT(mo) \
00169        MEMBEROF_CHK((mo),MEMBEROF_FREFINT)
00170 #define MEMBEROF_REVERSE(mo) \
00171        MEMBEROF_CHK((mo),MEMBEROF_FREVERSE)
00172 } memberof_t;
00173 
00174 typedef enum memberof_is_t {
00175        MEMBEROF_IS_NONE = 0x00,
00176        MEMBEROF_IS_GROUP = 0x01,
00177        MEMBEROF_IS_MEMBER = 0x02,
00178        MEMBEROF_IS_BOTH = (MEMBEROF_IS_GROUP|MEMBEROF_IS_MEMBER)
00179 } memberof_is_t;
00180 
00181 typedef struct memberof_cookie_t {
00182        AttributeDescription *ad;
00183        BerVarray            vals;
00184        int                  foundit;
00185 } memberof_cookie_t;
00186 
00187 typedef struct memberof_cbinfo_t {
00188        slap_overinst *on;
00189        BerVarray member;
00190        BerVarray memberof;
00191        memberof_is_t what;
00192 } memberof_cbinfo_t;
00193        
00194 static int
00195 memberof_isGroupOrMember_cb( Operation *op, SlapReply *rs )
00196 {
00197        if ( rs->sr_type == REP_SEARCH ) {
00198               memberof_cookie_t    *mc;
00199 
00200               mc = (memberof_cookie_t *)op->o_callback->sc_private;
00201               mc->foundit = 1;
00202        }
00203 
00204        return 0;
00205 }
00206 
00207 /*
00208  * callback for internal search that saves the member attribute values
00209  * of groups being deleted.
00210  */
00211 static int
00212 memberof_saveMember_cb( Operation *op, SlapReply *rs )
00213 {
00214        if ( rs->sr_type == REP_SEARCH ) {
00215               memberof_cookie_t    *mc;
00216               Attribute            *a;
00217 
00218               mc = (memberof_cookie_t *)op->o_callback->sc_private;
00219               mc->foundit = 1;
00220 
00221               assert( rs->sr_entry != NULL );
00222               assert( rs->sr_entry->e_attrs != NULL );
00223 
00224               a = attr_find( rs->sr_entry->e_attrs, mc->ad );
00225               if ( a != NULL ) {
00226                      ber_bvarray_dup_x( &mc->vals, a->a_nvals, op->o_tmpmemctx );
00227 
00228                      assert( attr_find( a->a_next, mc->ad ) == NULL );
00229               }
00230        }
00231 
00232        return 0;
00233 }
00234 
00235 /*
00236  * the delete hook performs an internal search that saves the member
00237  * attribute values of groups being deleted.
00238  */
00239 static int
00240 memberof_isGroupOrMember( Operation *op, memberof_cbinfo_t *mci )
00241 {
00242        slap_overinst        *on = mci->on;
00243        memberof_t           *mo = (memberof_t *)on->on_bi.bi_private;
00244 
00245        Operation            op2 = *op;
00246        slap_callback        cb = { 0 };
00247        BackendInfo   *bi = op->o_bd->bd_info;
00248        AttributeName        an[ 2 ];
00249 
00250        memberof_is_t        iswhat = MEMBEROF_IS_NONE;
00251        memberof_cookie_t    mc;
00252 
00253        assert( mci->what != MEMBEROF_IS_NONE );
00254 
00255        cb.sc_private = &mc;
00256        if ( op->o_tag == LDAP_REQ_DELETE ) {
00257               cb.sc_response = memberof_saveMember_cb;
00258 
00259        } else {
00260               cb.sc_response = memberof_isGroupOrMember_cb;
00261        }
00262 
00263        op2.o_tag = LDAP_REQ_SEARCH;
00264        op2.o_callback = &cb;
00265        op2.o_dn = op->o_bd->be_rootdn;
00266        op2.o_ndn = op->o_bd->be_rootndn;
00267 
00268        op2.ors_scope = LDAP_SCOPE_BASE;
00269        op2.ors_deref = LDAP_DEREF_NEVER;
00270        BER_BVZERO( &an[ 1 ].an_name );
00271        op2.ors_attrs = an;
00272        op2.ors_attrsonly = 0;
00273        op2.ors_limit = NULL;
00274        op2.ors_slimit = 1;
00275        op2.ors_tlimit = SLAP_NO_LIMIT;
00276 
00277        if ( mci->what & MEMBEROF_IS_GROUP ) {
00278               SlapReply     rs2 = { REP_RESULT };
00279 
00280               mc.ad = mo->mo_ad_member;
00281               mc.foundit = 0;
00282               mc.vals = NULL;
00283               an[ 0 ].an_desc = mo->mo_ad_member;
00284               an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname;
00285               op2.ors_filterstr = mo->mo_groupFilterstr;
00286               op2.ors_filter = &mo->mo_groupFilter;
00287 
00288               op2.o_bd->bd_info = (BackendInfo *)on->on_info;
00289               (void)op->o_bd->be_search( &op2, &rs2 );
00290               op2.o_bd->bd_info = bi;
00291 
00292               if ( mc.foundit ) {
00293                      iswhat |= MEMBEROF_IS_GROUP;
00294                      if ( mc.vals ) mci->member = mc.vals;
00295 
00296               }
00297        }
00298 
00299        if ( mci->what & MEMBEROF_IS_MEMBER ) {
00300               SlapReply     rs2 = { REP_RESULT };
00301 
00302               mc.ad = mo->mo_ad_memberof;
00303               mc.foundit = 0;
00304               mc.vals = NULL;
00305               an[ 0 ].an_desc = mo->mo_ad_memberof;
00306               an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname;
00307               op2.ors_filterstr = mo->mo_memberFilterstr;
00308               op2.ors_filter = &mo->mo_memberFilter;
00309 
00310               op2.o_bd->bd_info = (BackendInfo *)on->on_info;
00311               (void)op->o_bd->be_search( &op2, &rs2 );
00312               op2.o_bd->bd_info = bi;
00313 
00314               if ( mc.foundit ) {
00315                      iswhat |= MEMBEROF_IS_MEMBER;
00316                      if ( mc.vals ) mci->memberof = mc.vals;
00317 
00318               }
00319        }
00320 
00321        mci->what = iswhat;
00322 
00323        return LDAP_SUCCESS;
00324 }
00325 
00326 /*
00327  * response callback that adds memberof values when a group is modified.
00328  */
00329 static void
00330 memberof_value_modify(
00331        Operation            *op,
00332        struct berval        *ndn,
00333        AttributeDescription *ad,
00334        struct berval        *old_dn,
00335        struct berval        *old_ndn,
00336        struct berval        *new_dn,
00337        struct berval        *new_ndn )
00338 {
00339        memberof_cbinfo_t *mci = op->o_callback->sc_private;
00340        slap_overinst *on = mci->on;
00341        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
00342 
00343        Operation     op2 = *op;
00344        SlapReply     rs2 = { REP_RESULT };
00345        slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
00346        Modifications mod[ 2 ] = { { { 0 } } }, *ml;
00347        struct berval values[ 4 ], nvalues[ 4 ];
00348        int           mcnt = 0;
00349 
00350        op2.o_tag = LDAP_REQ_MODIFY;
00351 
00352        op2.o_req_dn = *ndn;
00353        op2.o_req_ndn = *ndn;
00354 
00355        op2.o_callback = &cb;
00356        op2.o_dn = op->o_bd->be_rootdn;
00357        op2.o_ndn = op->o_bd->be_rootndn;
00358        op2.orm_modlist = NULL;
00359 
00360        /* Internal ops, never replicate these */
00361        op2.orm_no_opattrs = 1;
00362        op2.o_dont_replicate = 1;
00363 
00364        if ( !BER_BVISNULL( &mo->mo_ndn ) ) {
00365               ml = &mod[ mcnt ];
00366               ml->sml_numvals = 1;
00367               ml->sml_values = &values[ 0 ];
00368               ml->sml_values[ 0 ] = mo->mo_dn;
00369               BER_BVZERO( &ml->sml_values[ 1 ] );
00370               ml->sml_nvalues = &nvalues[ 0 ];
00371               ml->sml_nvalues[ 0 ] = mo->mo_ndn;
00372               BER_BVZERO( &ml->sml_nvalues[ 1 ] );
00373               ml->sml_desc = slap_schema.si_ad_modifiersName;
00374               ml->sml_type = ml->sml_desc->ad_cname;
00375               ml->sml_op = LDAP_MOD_REPLACE;
00376               ml->sml_flags = SLAP_MOD_INTERNAL;
00377               ml->sml_next = op2.orm_modlist;
00378               op2.orm_modlist = ml;
00379 
00380               mcnt++;
00381        }
00382 
00383        ml = &mod[ mcnt ];
00384        ml->sml_numvals = 1;
00385        ml->sml_values = &values[ 2 ];
00386        BER_BVZERO( &ml->sml_values[ 1 ] );
00387        ml->sml_nvalues = &nvalues[ 2 ];
00388        BER_BVZERO( &ml->sml_nvalues[ 1 ] );
00389        ml->sml_desc = ad;
00390        ml->sml_type = ml->sml_desc->ad_cname;
00391        ml->sml_flags = SLAP_MOD_INTERNAL;
00392        ml->sml_next = op2.orm_modlist;
00393        op2.orm_modlist = ml;
00394 
00395        if ( new_ndn != NULL ) {
00396               BackendInfo *bi = op2.o_bd->bd_info;
00397               OpExtra       oex;
00398 
00399               assert( !BER_BVISNULL( new_dn ) );
00400               assert( !BER_BVISNULL( new_ndn ) );
00401 
00402               ml = &mod[ mcnt ];
00403               ml->sml_op = LDAP_MOD_ADD;
00404 
00405               ml->sml_values[ 0 ] = *new_dn;
00406               ml->sml_nvalues[ 0 ] = *new_ndn;
00407 
00408               oex.oe_key = (void *)&memberof;
00409               LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next);
00410               op2.o_bd->bd_info = (BackendInfo *)on->on_info;
00411               (void)op->o_bd->be_modify( &op2, &rs2 );
00412               op2.o_bd->bd_info = bi;
00413               LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next);
00414               if ( rs2.sr_err != LDAP_SUCCESS ) {
00415                      char buf[ SLAP_TEXT_BUFLEN ];
00416                      snprintf( buf, sizeof( buf ),
00417                             "memberof_value_modify DN=\"%s\" add %s=\"%s\" failed err=%d",
00418                             op2.o_req_dn.bv_val, ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err );
00419                      Debug( LDAP_DEBUG_ANY, "%s: %s\n",
00420                             op->o_log_prefix, buf, 0 );
00421               }
00422 
00423               assert( op2.orm_modlist == &mod[ mcnt ] );
00424               assert( mcnt == 0 || op2.orm_modlist->sml_next == &mod[ 0 ] );
00425               ml = op2.orm_modlist->sml_next;
00426               if ( mcnt == 1 ) {
00427                      assert( ml == &mod[ 0 ] );
00428                      ml = ml->sml_next;
00429               }
00430               if ( ml != NULL ) {
00431                      slap_mods_free( ml, 1 );
00432               }
00433 
00434               mod[ 0 ].sml_next = NULL;
00435        }
00436 
00437        if ( old_ndn != NULL ) {
00438               BackendInfo *bi = op2.o_bd->bd_info;
00439               OpExtra       oex;
00440 
00441               assert( !BER_BVISNULL( old_dn ) );
00442               assert( !BER_BVISNULL( old_ndn ) );
00443 
00444               ml = &mod[ mcnt ];
00445               ml->sml_op = LDAP_MOD_DELETE;
00446 
00447               ml->sml_values[ 0 ] = *old_dn;
00448               ml->sml_nvalues[ 0 ] = *old_ndn;
00449 
00450               oex.oe_key = (void *)&memberof;
00451               LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next);
00452               op2.o_bd->bd_info = (BackendInfo *)on->on_info;
00453               (void)op->o_bd->be_modify( &op2, &rs2 );
00454               op2.o_bd->bd_info = bi;
00455               LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next);
00456               if ( rs2.sr_err != LDAP_SUCCESS ) {
00457                      char buf[ SLAP_TEXT_BUFLEN ];
00458                      snprintf( buf, sizeof( buf ),
00459                             "memberof_value_modify DN=\"%s\" delete %s=\"%s\" failed err=%d",
00460                             op2.o_req_dn.bv_val, ad->ad_cname.bv_val, old_dn->bv_val, rs2.sr_err );
00461                      Debug( LDAP_DEBUG_ANY, "%s: %s\n",
00462                             op->o_log_prefix, buf, 0 );
00463               }
00464 
00465               assert( op2.orm_modlist == &mod[ mcnt ] );
00466               ml = op2.orm_modlist->sml_next;
00467               if ( mcnt == 1 ) {
00468                      assert( ml == &mod[ 0 ] );
00469                      ml = ml->sml_next;
00470               }
00471               if ( ml != NULL ) {
00472                      slap_mods_free( ml, 1 );
00473               }
00474        }
00475 
00476        /* FIXME: if old_group_ndn doesn't exist, both delete __and__
00477         * add will fail; better split in two operations, although
00478         * not optimal in terms of performance.  At least it would
00479         * move towards self-repairing capabilities. */
00480 }
00481 
00482 static int
00483 memberof_cleanup( Operation *op, SlapReply *rs )
00484 {
00485        slap_callback *sc = op->o_callback;
00486        memberof_cbinfo_t *mci = sc->sc_private;
00487 
00488        op->o_callback = sc->sc_next;
00489        if ( mci->memberof )
00490               ber_bvarray_free_x( mci->memberof, op->o_tmpmemctx );
00491        if ( mci->member )
00492               ber_bvarray_free_x( mci->member, op->o_tmpmemctx );
00493        op->o_tmpfree( sc, op->o_tmpmemctx );
00494        return 0;
00495 }
00496 
00497 static int memberof_res_add( Operation *op, SlapReply *rs );
00498 static int memberof_res_delete( Operation *op, SlapReply *rs );
00499 static int memberof_res_modify( Operation *op, SlapReply *rs );
00500 static int memberof_res_modrdn( Operation *op, SlapReply *rs );
00501 
00502 static int
00503 memberof_op_add( Operation *op, SlapReply *rs )
00504 {
00505        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00506        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
00507 
00508        Attribute     **ap, **map = NULL;
00509        int           rc = SLAP_CB_CONTINUE;
00510        int           i;
00511        struct berval save_dn, save_ndn;
00512        slap_callback *sc;
00513        memberof_cbinfo_t *mci;
00514        OpExtra              *oex;
00515 
00516        LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
00517               if ( oex->oe_key == (void *)&memberof )
00518                      return SLAP_CB_CONTINUE;
00519        }
00520 
00521        if ( op->ora_e->e_attrs == NULL ) {
00522               /* FIXME: global overlay; need to deal with */
00523               Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): "
00524                      "consistency checks not implemented when overlay "
00525                      "is instantiated as global.\n",
00526                      op->o_log_prefix, op->o_req_dn.bv_val, 0 );
00527               return SLAP_CB_CONTINUE;
00528        }
00529 
00530        if ( MEMBEROF_REVERSE( mo ) ) {
00531               for ( ap = &op->ora_e->e_attrs; *ap; ap = &(*ap)->a_next ) {
00532                      Attribute     *a = *ap;
00533 
00534                      if ( a->a_desc == mo->mo_ad_memberof ) {
00535                             map = ap;
00536                             break;
00537                      }
00538               }
00539        }
00540 
00541        save_dn = op->o_dn;
00542        save_ndn = op->o_ndn;
00543 
00544        if ( MEMBEROF_DANGLING_CHECK( mo )
00545                      && !get_relax( op )
00546                      && is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) )
00547        {
00548               op->o_dn = op->o_bd->be_rootdn;
00549               op->o_ndn = op->o_bd->be_rootndn;
00550               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00551 
00552               for ( ap = &op->ora_e->e_attrs; *ap; ) {
00553                      Attribute     *a = *ap;
00554 
00555                      if ( !is_ad_subtype( a->a_desc, mo->mo_ad_member ) ) {
00556                             ap = &a->a_next;
00557                             continue;
00558                      }
00559 
00560                      assert( a->a_nvals != NULL );
00561 
00562                      for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
00563                             Entry         *e = NULL;
00564 
00565                             /* ITS#6670 Ignore member pointing to this entry */
00566                             if ( dn_match( &a->a_nvals[i], &save_ndn ))
00567                                    continue;
00568 
00569                             rc = be_entry_get_rw( op, &a->a_nvals[ i ],
00570                                           NULL, NULL, 0, &e );
00571                             if ( rc == LDAP_SUCCESS ) {
00572                                    be_entry_release_r( op, e );
00573                                    continue;
00574                             }
00575 
00576                             if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
00577                                    rc = rs->sr_err = mo->mo_dangling_err;
00578                                    rs->sr_text = "adding non-existing object "
00579                                           "as group member";
00580                                    send_ldap_result( op, rs );
00581                                    goto done;
00582                             }
00583 
00584                             if ( MEMBEROF_DANGLING_DROP( mo ) ) {
00585                                    int    j;
00586        
00587                                    Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): "
00588                                           "member=\"%s\" does not exist (stripping...)\n",
00589                                           op->o_log_prefix, op->ora_e->e_name.bv_val,
00590                                           a->a_vals[ i ].bv_val );
00591        
00592                                    for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ );
00593                                    ber_memfree( a->a_vals[ i ].bv_val );
00594                                    BER_BVZERO( &a->a_vals[ i ] );
00595                                    if ( a->a_nvals != a->a_vals ) {
00596                                           ber_memfree( a->a_nvals[ i ].bv_val );
00597                                           BER_BVZERO( &a->a_nvals[ i ] );
00598                                    }
00599                                    if ( j - i == 1 ) {
00600                                           break;
00601                                    }
00602               
00603                                    AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ],
00604                                           sizeof( struct berval ) * ( j - i ) );
00605                                    if ( a->a_nvals != a->a_vals ) {
00606                                           AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ],
00607                                                  sizeof( struct berval ) * ( j - i ) );
00608                                    }
00609                                    i--;
00610                                    a->a_numvals--;
00611                             }
00612                      }
00613 
00614                      /* If all values have been removed,
00615                       * remove the attribute itself. */
00616                      if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) {
00617                             *ap = a->a_next;
00618                             attr_free( a );
00619        
00620                      } else {
00621                             ap = &a->a_next;
00622                      }
00623               }
00624               op->o_dn = save_dn;
00625               op->o_ndn = save_ndn;
00626               op->o_bd->bd_info = (BackendInfo *)on;
00627        }
00628 
00629        if ( map != NULL ) {
00630               Attribute            *a = *map;
00631               AccessControlState   acl_state = ACL_STATE_INIT;
00632 
00633               for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
00634                      Entry         *e;
00635 
00636                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
00637                      /* access is checked with the original identity */
00638                      rc = access_allowed( op, op->ora_e, mo->mo_ad_memberof,
00639                                    &a->a_nvals[ i ], ACL_WADD,
00640                                    &acl_state );
00641                      if ( rc == 0 ) {
00642                             rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00643                             rs->sr_text = NULL;
00644                             send_ldap_result( op, rs );
00645                             goto done;
00646                      }
00647                      /* ITS#6670 Ignore member pointing to this entry */
00648                      if ( dn_match( &a->a_nvals[i], &save_ndn ))
00649                             continue;
00650 
00651                      rc = be_entry_get_rw( op, &a->a_nvals[ i ],
00652                                    NULL, NULL, 0, &e );
00653                      op->o_bd->bd_info = (BackendInfo *)on;
00654                      if ( rc != LDAP_SUCCESS ) {
00655                             if ( get_relax( op ) ) {
00656                                    continue;
00657                             }
00658 
00659                             if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
00660                                    rc = rs->sr_err = mo->mo_dangling_err;
00661                                    rs->sr_text = "adding non-existing object "
00662                                           "as memberof";
00663                                    send_ldap_result( op, rs );
00664                                    goto done;
00665                             }
00666 
00667                             if ( MEMBEROF_DANGLING_DROP( mo ) ) {
00668                                    int    j;
00669        
00670                                    Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): "
00671                                           "memberof=\"%s\" does not exist (stripping...)\n",
00672                                           op->o_log_prefix, op->ora_e->e_name.bv_val,
00673                                           a->a_nvals[ i ].bv_val );
00674        
00675                                    for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ );
00676                                    ber_memfree( a->a_vals[ i ].bv_val );
00677                                    BER_BVZERO( &a->a_vals[ i ] );
00678                                    if ( a->a_nvals != a->a_vals ) {
00679                                           ber_memfree( a->a_nvals[ i ].bv_val );
00680                                           BER_BVZERO( &a->a_nvals[ i ] );
00681                                    }
00682                                    if ( j - i == 1 ) {
00683                                           break;
00684                                    }
00685               
00686                                    AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ],
00687                                           sizeof( struct berval ) * ( j - i ) );
00688                                    if ( a->a_nvals != a->a_vals ) {
00689                                           AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ],
00690                                                  sizeof( struct berval ) * ( j - i ) );
00691                                    }
00692                                    i--;
00693                             }
00694                             
00695                             continue;
00696                      }
00697 
00698                      /* access is checked with the original identity */
00699                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
00700                      rc = access_allowed( op, e, mo->mo_ad_member,
00701                                    &op->o_req_ndn, ACL_WADD, NULL );
00702                      be_entry_release_r( op, e );
00703                      op->o_bd->bd_info = (BackendInfo *)on;
00704 
00705                      if ( !rc ) {
00706                             rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00707                             rs->sr_text = "insufficient access to object referenced by memberof";
00708                             send_ldap_result( op, rs );
00709                             goto done;
00710                      }
00711               }
00712 
00713               if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) {
00714                      *map = a->a_next;
00715                      attr_free( a );
00716               }
00717        }
00718 
00719        rc = SLAP_CB_CONTINUE;
00720 
00721        sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
00722        sc->sc_private = sc+1;
00723        sc->sc_response = memberof_res_add;
00724        sc->sc_cleanup = memberof_cleanup;
00725        mci = sc->sc_private;
00726        mci->on = on;
00727        mci->member = NULL;
00728        mci->memberof = NULL;
00729        sc->sc_next = op->o_callback;
00730        op->o_callback = sc;
00731 
00732 done:;
00733        op->o_dn = save_dn;
00734        op->o_ndn = save_ndn;
00735        op->o_bd->bd_info = (BackendInfo *)on;
00736 
00737        return rc;
00738 }
00739 
00740 static int
00741 memberof_op_delete( Operation *op, SlapReply *rs )
00742 {
00743        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00744        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
00745 
00746        slap_callback *sc;
00747        memberof_cbinfo_t *mci;
00748        OpExtra              *oex;
00749 
00750        LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
00751               if ( oex->oe_key == (void *)&memberof )
00752                      return SLAP_CB_CONTINUE;
00753        }
00754 
00755        sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
00756        sc->sc_private = sc+1;
00757        sc->sc_response = memberof_res_delete;
00758        sc->sc_cleanup = memberof_cleanup;
00759        mci = sc->sc_private;
00760        mci->on = on;
00761        mci->member = NULL;
00762        mci->memberof = NULL;
00763        mci->what = MEMBEROF_IS_GROUP;
00764        if ( MEMBEROF_REFINT( mo ) ) {
00765               mci->what = MEMBEROF_IS_BOTH;
00766        }
00767 
00768        memberof_isGroupOrMember( op, mci );
00769 
00770        sc->sc_next = op->o_callback;
00771        op->o_callback = sc;
00772 
00773        return SLAP_CB_CONTINUE;
00774 }
00775 
00776 static int
00777 memberof_op_modify( Operation *op, SlapReply *rs )
00778 {
00779        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00780        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
00781 
00782        Modifications **mlp, **mmlp = NULL;
00783        int           rc = SLAP_CB_CONTINUE, save_member = 0;
00784        struct berval save_dn, save_ndn;
00785        slap_callback *sc;
00786        memberof_cbinfo_t *mci, mcis;
00787        OpExtra              *oex;
00788 
00789        LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
00790               if ( oex->oe_key == (void *)&memberof )
00791                      return SLAP_CB_CONTINUE;
00792        }
00793 
00794        if ( MEMBEROF_REVERSE( mo ) ) {
00795               for ( mlp = &op->orm_modlist; *mlp; mlp = &(*mlp)->sml_next ) {
00796                      Modifications *ml = *mlp;
00797 
00798                      if ( ml->sml_desc == mo->mo_ad_memberof ) {
00799                             mmlp = mlp;
00800                             break;
00801                      }
00802               }
00803        }
00804 
00805        save_dn = op->o_dn;
00806        save_ndn = op->o_ndn;
00807        mcis.on = on;
00808        mcis.what = MEMBEROF_IS_GROUP;
00809 
00810        if ( memberof_isGroupOrMember( op, &mcis ) == LDAP_SUCCESS
00811               && ( mcis.what & MEMBEROF_IS_GROUP ) )
00812        {
00813               Modifications *ml;
00814 
00815               for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
00816                      if ( ml->sml_desc == mo->mo_ad_member ) {
00817                             switch ( ml->sml_op ) {
00818                             case LDAP_MOD_DELETE:
00819                             case LDAP_MOD_REPLACE:
00820                                    save_member = 1;
00821                                    break;
00822                             }
00823                      }
00824               }
00825 
00826 
00827               if ( MEMBEROF_DANGLING_CHECK( mo )
00828                             && !get_relax( op ) )
00829               {
00830                      op->o_dn = op->o_bd->be_rootdn;
00831                      op->o_ndn = op->o_bd->be_rootndn;
00832                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
00833               
00834                      assert( op->orm_modlist != NULL );
00835               
00836                      for ( mlp = &op->orm_modlist; *mlp; ) {
00837                             Modifications *ml = *mlp;
00838                             int           i;
00839               
00840                             if ( !is_ad_subtype( ml->sml_desc, mo->mo_ad_member ) ) {
00841                                    mlp = &ml->sml_next;
00842                                    continue;
00843                             }
00844               
00845                             switch ( ml->sml_op ) {
00846                             case LDAP_MOD_DELETE:
00847                                    /* we don't care about cancellations: if the value
00848                                     * exists, fine; if it doesn't, we let the underlying
00849                                     * database fail as appropriate; */
00850                                    mlp = &ml->sml_next;
00851                                    break;
00852               
00853                             case LDAP_MOD_REPLACE:
00854                                    /* Handle this just like a delete (see above) */
00855                                    if ( !ml->sml_values ) {
00856                                           mlp = &ml->sml_next;
00857                                           break;
00858                                    }
00859  
00860                             case LDAP_MOD_ADD:
00861                                    /* NOTE: right now, the attributeType we use
00862                                     * for member must have a normalized value */
00863                                    assert( ml->sml_nvalues != NULL );
00864               
00865                                    for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) {
00866                                           int           rc;
00867                                           Entry         *e;
00868               
00869                                           /* ITS#6670 Ignore member pointing to this entry */
00870                                           if ( dn_match( &ml->sml_nvalues[i], &save_ndn ))
00871                                                  continue;
00872 
00873                                           if ( be_entry_get_rw( op, &ml->sml_nvalues[ i ],
00874                                                         NULL, NULL, 0, &e ) == LDAP_SUCCESS )
00875                                           {
00876                                                  be_entry_release_r( op, e );
00877                                                  continue;
00878                                           }
00879               
00880                                           if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
00881                                                  rc = rs->sr_err = mo->mo_dangling_err;
00882                                                  rs->sr_text = "adding non-existing object "
00883                                                         "as group member";
00884                                                  send_ldap_result( op, rs );
00885                                                  goto done;
00886                                           }
00887               
00888                                           if ( MEMBEROF_DANGLING_DROP( mo ) ) {
00889                                                  int    j;
00890               
00891                                                  Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): "
00892                                                         "member=\"%s\" does not exist (stripping...)\n",
00893                                                         op->o_log_prefix, op->o_req_dn.bv_val,
00894                                                         ml->sml_nvalues[ i ].bv_val );
00895               
00896                                                  for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ );
00897                                                  ber_memfree( ml->sml_values[ i ].bv_val );
00898                                                  BER_BVZERO( &ml->sml_values[ i ] );
00899                                                  ber_memfree( ml->sml_nvalues[ i ].bv_val );
00900                                                  BER_BVZERO( &ml->sml_nvalues[ i ] );
00901                                                  ml->sml_numvals--;
00902                                                  if ( j - i == 1 ) {
00903                                                         break;
00904                                                  }
00905               
00906                                                  AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ],
00907                                                         sizeof( struct berval ) * ( j - i ) );
00908                                                  AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ],
00909                                                         sizeof( struct berval ) * ( j - i ) );
00910                                                  i--;
00911                                           }
00912                                    }
00913               
00914                                    if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
00915                                           *mlp = ml->sml_next;
00916                                           slap_mod_free( &ml->sml_mod, 0 );
00917                                           free( ml );
00918               
00919                                    } else {
00920                                           mlp = &ml->sml_next;
00921                                    }
00922               
00923                                    break;
00924               
00925                             default:
00926                                    assert( 0 );
00927                             }
00928                      }
00929               }
00930        }
00931        
00932        if ( mmlp != NULL ) {
00933               Modifications *ml = *mmlp;
00934               int           i;
00935               Entry         *target;
00936 
00937               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00938               rc = be_entry_get_rw( op, &op->o_req_ndn,
00939                             NULL, NULL, 0, &target );
00940               op->o_bd->bd_info = (BackendInfo *)on;
00941               if ( rc != LDAP_SUCCESS ) {
00942                      rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
00943                      send_ldap_result( op, rs );
00944                      goto done;
00945               }
00946 
00947               switch ( ml->sml_op ) {
00948               case LDAP_MOD_DELETE:
00949                      if ( ml->sml_nvalues != NULL ) {
00950                             AccessControlState   acl_state = ACL_STATE_INIT;
00951 
00952                             for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) {
00953                                    Entry         *e;
00954 
00955                                    op->o_bd->bd_info = (BackendInfo *)on->on_info;
00956                                    /* access is checked with the original identity */
00957                                    rc = access_allowed( op, target,
00958                                                  mo->mo_ad_memberof,
00959                                                  &ml->sml_nvalues[ i ],
00960                                                  ACL_WDEL,
00961                                                  &acl_state );
00962                                    if ( rc == 0 ) {
00963                                           rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00964                                           rs->sr_text = NULL;
00965                                           send_ldap_result( op, rs );
00966                                           goto done2;
00967                                    }
00968 
00969                                    rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ],
00970                                                  NULL, NULL, 0, &e );
00971                                    op->o_bd->bd_info = (BackendInfo *)on;
00972                                    if ( rc != LDAP_SUCCESS ) {
00973                                           if ( get_relax( op ) ) {
00974                                                  continue;
00975                                           }
00976 
00977                                           if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
00978                                                  rc = rs->sr_err = mo->mo_dangling_err;
00979                                                  rs->sr_text = "deleting non-existing object "
00980                                                         "as memberof";
00981                                                  send_ldap_result( op, rs );
00982                                                  goto done2;
00983                                           }
00984 
00985                                           if ( MEMBEROF_DANGLING_DROP( mo ) ) {
00986                                                  int    j;
00987        
00988                                                  Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): "
00989                                                         "memberof=\"%s\" does not exist (stripping...)\n",
00990                                                         op->o_log_prefix, op->o_req_ndn.bv_val,
00991                                                         ml->sml_nvalues[ i ].bv_val );
00992        
00993                                                  for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ );
00994                                                  ber_memfree( ml->sml_values[ i ].bv_val );
00995                                                  BER_BVZERO( &ml->sml_values[ i ] );
00996                                                  if ( ml->sml_nvalues != ml->sml_values ) {
00997                                                         ber_memfree( ml->sml_nvalues[ i ].bv_val );
00998                                                         BER_BVZERO( &ml->sml_nvalues[ i ] );
00999                                                  }
01000                                                  ml->sml_numvals--;
01001                                                  if ( j - i == 1 ) {
01002                                                         break;
01003                                                  }
01004               
01005                                                  AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ],
01006                                                         sizeof( struct berval ) * ( j - i ) );
01007                                                  if ( ml->sml_nvalues != ml->sml_values ) {
01008                                                         AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ],
01009                                                                sizeof( struct berval ) * ( j - i ) );
01010                                                  }
01011                                                  i--;
01012                                           }
01013 
01014                                           continue;
01015                                    }
01016 
01017                                    /* access is checked with the original identity */
01018                                    op->o_bd->bd_info = (BackendInfo *)on->on_info;
01019                                    rc = access_allowed( op, e, mo->mo_ad_member,
01020                                                  &op->o_req_ndn,
01021                                                  ACL_WDEL, NULL );
01022                                    be_entry_release_r( op, e );
01023                                    op->o_bd->bd_info = (BackendInfo *)on;
01024 
01025                                    if ( !rc ) {
01026                                           rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
01027                                           rs->sr_text = "insufficient access to object referenced by memberof";
01028                                           send_ldap_result( op, rs );
01029                                           goto done;
01030                                    }
01031                             }
01032 
01033                             if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
01034                                    *mmlp = ml->sml_next;
01035                                    slap_mod_free( &ml->sml_mod, 0 );
01036                                    free( ml );
01037                             }
01038 
01039                             break;
01040                      }
01041                      /* fall thru */
01042 
01043               case LDAP_MOD_REPLACE:
01044 
01045                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
01046                      /* access is checked with the original identity */
01047                      rc = access_allowed( op, target,
01048                                    mo->mo_ad_memberof,
01049                                    NULL,
01050                                    ACL_WDEL, NULL );
01051                      op->o_bd->bd_info = (BackendInfo *)on;
01052                      if ( rc == 0 ) {
01053                             rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
01054                             rs->sr_text = NULL;
01055                             send_ldap_result( op, rs );
01056                             goto done2;
01057                      }
01058 
01059                      if ( ml->sml_op == LDAP_MOD_DELETE || !ml->sml_values ) {
01060                             break;
01061                      }
01062                      /* fall thru */
01063 
01064               case LDAP_MOD_ADD: {
01065                      AccessControlState   acl_state = ACL_STATE_INIT;
01066 
01067                      for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) {
01068                             Entry         *e;
01069 
01070                             op->o_bd->bd_info = (BackendInfo *)on->on_info;
01071                             /* access is checked with the original identity */
01072                             rc = access_allowed( op, target,
01073                                           mo->mo_ad_memberof,
01074                                           &ml->sml_nvalues[ i ],
01075                                           ACL_WADD,
01076                                           &acl_state );
01077                             if ( rc == 0 ) {
01078                                    rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
01079                                    rs->sr_text = NULL;
01080                                    send_ldap_result( op, rs );
01081                                    goto done2;
01082                             }
01083 
01084                             /* ITS#6670 Ignore member pointing to this entry */
01085                             if ( dn_match( &ml->sml_nvalues[i], &save_ndn ))
01086                                    continue;
01087 
01088                             rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ],
01089                                           NULL, NULL, 0, &e );
01090                             op->o_bd->bd_info = (BackendInfo *)on;
01091                             if ( rc != LDAP_SUCCESS ) {
01092                                    if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
01093                                           rc = rs->sr_err = mo->mo_dangling_err;
01094                                           rs->sr_text = "adding non-existing object "
01095                                                  "as memberof";
01096                                           send_ldap_result( op, rs );
01097                                           goto done2;
01098                                    }
01099 
01100                                    if ( MEMBEROF_DANGLING_DROP( mo ) ) {
01101                                           int    j;
01102 
01103                                           Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): "
01104                                                  "memberof=\"%s\" does not exist (stripping...)\n",
01105                                                  op->o_log_prefix, op->o_req_ndn.bv_val,
01106                                                  ml->sml_nvalues[ i ].bv_val );
01107 
01108                                           for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ );
01109                                           ber_memfree( ml->sml_values[ i ].bv_val );
01110                                           BER_BVZERO( &ml->sml_values[ i ] );
01111                                           if ( ml->sml_nvalues != ml->sml_values ) {
01112                                                  ber_memfree( ml->sml_nvalues[ i ].bv_val );
01113                                                  BER_BVZERO( &ml->sml_nvalues[ i ] );
01114                                           }
01115                                           ml->sml_numvals--;
01116                                           if ( j - i == 1 ) {
01117                                                  break;
01118                                           }
01119        
01120                                           AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ],
01121                                                  sizeof( struct berval ) * ( j - i ) );
01122                                           if ( ml->sml_nvalues != ml->sml_values ) {
01123                                                  AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ],
01124                                                         sizeof( struct berval ) * ( j - i ) );
01125                                           }
01126                                           i--;
01127                                    }
01128 
01129                                    continue;
01130                             }
01131 
01132                             /* access is checked with the original identity */
01133                             op->o_bd->bd_info = (BackendInfo *)on->on_info;
01134                             rc = access_allowed( op, e, mo->mo_ad_member,
01135                                           &op->o_req_ndn,
01136                                           ACL_WDEL, NULL );
01137                             be_entry_release_r( op, e );
01138                             op->o_bd->bd_info = (BackendInfo *)on;
01139 
01140                             if ( !rc ) {
01141                                    rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
01142                                    rs->sr_text = "insufficient access to object referenced by memberof";
01143                                    send_ldap_result( op, rs );
01144                                    goto done;
01145                             }
01146                      }
01147 
01148                      if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
01149                             *mmlp = ml->sml_next;
01150                             slap_mod_free( &ml->sml_mod, 0 );
01151                             free( ml );
01152                      }
01153 
01154                      } break;
01155 
01156               default:
01157                      assert( 0 );
01158               }
01159 
01160 done2:;
01161               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01162               be_entry_release_r( op, target );
01163               op->o_bd->bd_info = (BackendInfo *)on;
01164        }
01165 
01166        sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
01167        sc->sc_private = sc+1;
01168        sc->sc_response = memberof_res_modify;
01169        sc->sc_cleanup = memberof_cleanup;
01170        mci = sc->sc_private;
01171        mci->on = on;
01172        mci->member = NULL;
01173        mci->memberof = NULL;
01174        mci->what = mcis.what;
01175 
01176        if ( save_member ) {
01177               op->o_dn = op->o_bd->be_rootdn;
01178               op->o_ndn = op->o_bd->be_rootndn;
01179               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01180               rc = backend_attribute( op, NULL, &op->o_req_ndn,
01181                             mo->mo_ad_member, &mci->member, ACL_READ );
01182               op->o_bd->bd_info = (BackendInfo *)on;
01183        }
01184 
01185        sc->sc_next = op->o_callback;
01186        op->o_callback = sc;
01187 
01188        rc = SLAP_CB_CONTINUE;
01189 
01190 done:;
01191        op->o_dn = save_dn;
01192        op->o_ndn = save_ndn;
01193        op->o_bd->bd_info = (BackendInfo *)on;
01194 
01195        return rc;
01196 }
01197 
01198 static int
01199 memberof_op_modrdn( Operation *op, SlapReply *rs )
01200 {
01201        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
01202        slap_callback *sc;
01203        memberof_cbinfo_t *mci;
01204        OpExtra              *oex;
01205 
01206        LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
01207               if ( oex->oe_key == (void *)&memberof )
01208                      return SLAP_CB_CONTINUE;
01209        }
01210 
01211        sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
01212        sc->sc_private = sc+1;
01213        sc->sc_response = memberof_res_modrdn;
01214        sc->sc_cleanup = memberof_cleanup;
01215        mci = sc->sc_private;
01216        mci->on = on;
01217        mci->member = NULL;
01218        mci->memberof = NULL;
01219 
01220        sc->sc_next = op->o_callback;
01221        op->o_callback = sc;
01222 
01223        return SLAP_CB_CONTINUE;
01224 }
01225 
01226 /*
01227  * response callback that adds memberof values when a group is added.
01228  */
01229 static int
01230 memberof_res_add( Operation *op, SlapReply *rs )
01231 {
01232        memberof_cbinfo_t *mci = op->o_callback->sc_private;
01233        slap_overinst *on = mci->on;
01234        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
01235 
01236        int           i;
01237 
01238        if ( rs->sr_err != LDAP_SUCCESS ) {
01239               return SLAP_CB_CONTINUE;
01240        }
01241 
01242        if ( MEMBEROF_REVERSE( mo ) ) {
01243               Attribute     *ma;
01244 
01245               ma = attr_find( op->ora_e->e_attrs, mo->mo_ad_memberof );
01246               if ( ma != NULL ) {
01247                      /* relax is required to allow to add
01248                       * a non-existing member */
01249                      op->o_relax = SLAP_CONTROL_CRITICAL;
01250 
01251                      for ( i = 0; !BER_BVISNULL( &ma->a_nvals[ i ] ); i++ ) {
01252               
01253                             /* ITS#6670 Ignore member pointing to this entry */
01254                             if ( dn_match( &ma->a_nvals[i], &op->o_req_ndn ))
01255                                    continue;
01256 
01257                             /* the modification is attempted
01258                              * with the original identity */
01259                             memberof_value_modify( op,
01260                                    &ma->a_nvals[ i ], mo->mo_ad_member,
01261                                    NULL, NULL, &op->o_req_dn, &op->o_req_ndn );
01262                      }
01263               }
01264        }
01265 
01266        if ( is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) ) {
01267               Attribute     *a;
01268 
01269               for ( a = attrs_find( op->ora_e->e_attrs, mo->mo_ad_member );
01270                             a != NULL;
01271                             a = attrs_find( a->a_next, mo->mo_ad_member ) )
01272               {
01273                      for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
01274                             /* ITS#6670 Ignore member pointing to this entry */
01275                             if ( dn_match( &a->a_nvals[i], &op->o_req_ndn ))
01276                                    continue;
01277 
01278                             memberof_value_modify( op,
01279                                           &a->a_nvals[ i ],
01280                                           mo->mo_ad_memberof,
01281                                           NULL, NULL,
01282                                           &op->o_req_dn,
01283                                           &op->o_req_ndn );
01284                      }
01285               }
01286        }
01287 
01288        return SLAP_CB_CONTINUE;
01289 }
01290 
01291 /*
01292  * response callback that deletes memberof values when a group is deleted.
01293  */
01294 static int
01295 memberof_res_delete( Operation *op, SlapReply *rs )
01296 {
01297        memberof_cbinfo_t *mci = op->o_callback->sc_private;
01298        slap_overinst *on = mci->on;
01299        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
01300 
01301        BerVarray     vals;
01302        int           i;
01303 
01304        if ( rs->sr_err != LDAP_SUCCESS ) {
01305               return SLAP_CB_CONTINUE;
01306        }
01307 
01308        vals = mci->member;
01309        if ( vals != NULL ) {
01310               for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01311                      memberof_value_modify( op,
01312                                    &vals[ i ], mo->mo_ad_memberof,
01313                                    &op->o_req_dn, &op->o_req_ndn,
01314                                    NULL, NULL );
01315               }
01316        }
01317 
01318        if ( MEMBEROF_REFINT( mo ) ) {
01319               vals = mci->memberof;
01320               if ( vals != NULL ) {
01321                      for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01322                             memberof_value_modify( op,
01323                                           &vals[ i ], mo->mo_ad_member,
01324                                           &op->o_req_dn, &op->o_req_ndn,
01325                                           NULL, NULL );
01326                      }
01327               }
01328        }
01329 
01330        return SLAP_CB_CONTINUE;
01331 }
01332 
01333 /*
01334  * response callback that adds/deletes memberof values when a group
01335  * is modified.
01336  */
01337 static int
01338 memberof_res_modify( Operation *op, SlapReply *rs )
01339 {
01340        memberof_cbinfo_t *mci = op->o_callback->sc_private;
01341        slap_overinst *on = mci->on;
01342        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
01343 
01344        int           i, rc;
01345        Modifications *ml, *mml = NULL;
01346        BerVarray     vals;
01347 
01348        if ( rs->sr_err != LDAP_SUCCESS ) {
01349               return SLAP_CB_CONTINUE;
01350        }
01351 
01352        if ( MEMBEROF_REVERSE( mo ) ) {
01353               for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
01354                      if ( ml->sml_desc == mo->mo_ad_memberof ) {
01355                             mml = ml;
01356                             break;
01357                      }
01358               }
01359        }
01360 
01361        if ( mml != NULL ) {
01362               BerVarray     vals = mml->sml_nvalues;
01363 
01364               switch ( mml->sml_op ) {
01365               case LDAP_MOD_DELETE:
01366                      if ( vals != NULL ) {
01367                             for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01368                                    memberof_value_modify( op,
01369                                                  &vals[ i ], mo->mo_ad_member,
01370                                                  &op->o_req_dn, &op->o_req_ndn,
01371                                                  NULL, NULL );
01372                             }
01373                             break;
01374                      }
01375                      /* fall thru */
01376 
01377               case LDAP_MOD_REPLACE:
01378                      /* delete all ... */
01379                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
01380                      rc = backend_attribute( op, NULL, &op->o_req_ndn,
01381                                    mo->mo_ad_memberof, &vals, ACL_READ );
01382                      op->o_bd->bd_info = (BackendInfo *)on;
01383                      if ( rc == LDAP_SUCCESS ) {
01384                             for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01385                                    memberof_value_modify( op,
01386                                                  &vals[ i ], mo->mo_ad_member,
01387                                                  &op->o_req_dn, &op->o_req_ndn,
01388                                                  NULL, NULL );
01389                             }
01390                             ber_bvarray_free_x( vals, op->o_tmpmemctx );
01391                      }
01392 
01393                      if ( ml->sml_op == LDAP_MOD_DELETE || !mml->sml_values ) {
01394                             break;
01395                      }
01396                      /* fall thru */
01397 
01398               case LDAP_MOD_ADD:
01399                      assert( vals != NULL );
01400 
01401                      for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01402                             memberof_value_modify( op,
01403                                           &vals[ i ], mo->mo_ad_member,
01404                                           NULL, NULL,
01405                                           &op->o_req_dn, &op->o_req_ndn );
01406                      }
01407                      break;
01408 
01409               default:
01410                      assert( 0 );
01411               }
01412        }
01413 
01414        if ( mci->what & MEMBEROF_IS_GROUP )
01415        {
01416               for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
01417                      if ( ml->sml_desc != mo->mo_ad_member ) {
01418                             continue;
01419                      }
01420 
01421                      switch ( ml->sml_op ) {
01422                      case LDAP_MOD_DELETE:
01423                             vals = ml->sml_nvalues;
01424                             if ( vals != NULL ) {
01425                                    for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01426                                           memberof_value_modify( op,
01427                                                         &vals[ i ], mo->mo_ad_memberof,
01428                                                         &op->o_req_dn, &op->o_req_ndn,
01429                                                         NULL, NULL );
01430                                    }
01431                                    break;
01432                             }
01433                             /* fall thru */
01434        
01435                      case LDAP_MOD_REPLACE:
01436                             vals = mci->member;
01437 
01438                             /* delete all ... */
01439                             if ( vals != NULL ) {
01440                                    for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01441                                           memberof_value_modify( op,
01442                                                         &vals[ i ], mo->mo_ad_memberof,
01443                                                         &op->o_req_dn, &op->o_req_ndn,
01444                                                         NULL, NULL );
01445                                    }
01446                             }
01447        
01448                             if ( ml->sml_op == LDAP_MOD_DELETE || !ml->sml_values ) {
01449                                    break;
01450                             }
01451                             /* fall thru */
01452        
01453                      case LDAP_MOD_ADD:
01454                             assert( ml->sml_nvalues != NULL );
01455                             vals = ml->sml_nvalues;
01456                             for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01457                                    memberof_value_modify( op,
01458                                                  &vals[ i ], mo->mo_ad_memberof,
01459                                                  NULL, NULL,
01460                                                  &op->o_req_dn, &op->o_req_ndn );
01461                             }
01462                             break;
01463        
01464                      default:
01465                             assert( 0 );
01466                      }
01467               }
01468        }
01469 
01470        return SLAP_CB_CONTINUE;
01471 }
01472 
01473 /*
01474  * response callback that adds/deletes member values when a group member
01475  * is renamed.
01476  */
01477 static int
01478 memberof_res_modrdn( Operation *op, SlapReply *rs )
01479 {
01480        memberof_cbinfo_t *mci = op->o_callback->sc_private;
01481        slap_overinst *on = mci->on;
01482        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
01483 
01484        struct berval newPDN, newDN = BER_BVNULL, newPNDN, newNDN;
01485        int           i, rc;
01486        BerVarray     vals;
01487 
01488        struct berval save_dn, save_ndn;
01489 
01490        if ( rs->sr_err != LDAP_SUCCESS ) {
01491               return SLAP_CB_CONTINUE;
01492        }
01493 
01494        mci->what = MEMBEROF_IS_GROUP;
01495        if ( MEMBEROF_REFINT( mo ) ) {
01496               mci->what |= MEMBEROF_IS_MEMBER;
01497        }
01498 
01499        if ( op->orr_nnewSup ) {
01500               newPNDN = *op->orr_nnewSup;
01501 
01502        } else {
01503               dnParent( &op->o_req_ndn, &newPNDN );
01504        }
01505 
01506        build_new_dn( &newNDN, &newPNDN, &op->orr_nnewrdn, op->o_tmpmemctx ); 
01507 
01508        save_dn = op->o_req_dn;
01509        save_ndn = op->o_req_ndn;
01510 
01511        op->o_req_dn = newNDN;
01512        op->o_req_ndn = newNDN;
01513        rc = memberof_isGroupOrMember( op, mci );
01514        op->o_req_dn = save_dn;
01515        op->o_req_ndn = save_ndn;
01516 
01517        if ( rc != LDAP_SUCCESS || mci->what == MEMBEROF_IS_NONE ) {
01518               goto done;
01519        }
01520 
01521        if ( op->orr_newSup ) {
01522               newPDN = *op->orr_newSup;
01523 
01524        } else {
01525               dnParent( &op->o_req_dn, &newPDN );
01526        }
01527 
01528        build_new_dn( &newDN, &newPDN, &op->orr_newrdn, op->o_tmpmemctx ); 
01529 
01530        if ( mci->what & MEMBEROF_IS_GROUP ) {
01531               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01532               rc = backend_attribute( op, NULL, &newNDN,
01533                             mo->mo_ad_member, &vals, ACL_READ );
01534               op->o_bd->bd_info = (BackendInfo *)on;
01535 
01536               if ( rc == LDAP_SUCCESS ) {
01537                      for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01538                             memberof_value_modify( op,
01539                                           &vals[ i ], mo->mo_ad_memberof,
01540                                           &op->o_req_dn, &op->o_req_ndn,
01541                                           &newDN, &newNDN );
01542                      }
01543                      ber_bvarray_free_x( vals, op->o_tmpmemctx );
01544               }
01545        }
01546 
01547        if ( MEMBEROF_REFINT( mo ) && ( mci->what & MEMBEROF_IS_MEMBER ) ) {
01548               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01549               rc = backend_attribute( op, NULL, &newNDN,
01550                             mo->mo_ad_memberof, &vals, ACL_READ );
01551               op->o_bd->bd_info = (BackendInfo *)on;
01552 
01553               if ( rc == LDAP_SUCCESS ) {
01554                      for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
01555                             memberof_value_modify( op,
01556                                           &vals[ i ], mo->mo_ad_member,
01557                                           &op->o_req_dn, &op->o_req_ndn,
01558                                           &newDN, &newNDN );
01559                      }
01560                      ber_bvarray_free_x( vals, op->o_tmpmemctx );
01561               }
01562        }
01563 
01564 done:;
01565        if ( !BER_BVISNULL( &newDN ) ) {
01566               op->o_tmpfree( newDN.bv_val, op->o_tmpmemctx );
01567        }
01568        op->o_tmpfree( newNDN.bv_val, op->o_tmpmemctx );
01569 
01570        return SLAP_CB_CONTINUE;
01571 }
01572 
01573 
01574 static int
01575 memberof_db_init(
01576        BackendDB     *be,
01577        ConfigReply   *cr )
01578 {
01579        slap_overinst *on = (slap_overinst *)be->bd_info;
01580        memberof_t           *mo;
01581 
01582        mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) );
01583 
01584        /* safe default */
01585        mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION;
01586 
01587        on->on_bi.bi_private = (void *)mo;
01588 
01589        return 0;
01590 }
01591 
01592 enum {
01593        MO_DN = 1,
01594        MO_DANGLING,
01595        MO_REFINT,
01596        MO_GROUP_OC,
01597        MO_MEMBER_AD,
01598        MO_MEMBER_OF_AD,
01599 #if 0
01600        MO_REVERSE,
01601 #endif
01602 
01603        MO_DANGLING_ERROR,
01604 
01605        MO_LAST
01606 };
01607 
01608 static ConfigDriver mo_cf_gen;
01609 
01610 #define OID          "1.3.6.1.4.1.7136.2.666.4"
01611 #define       OIDAT         OID ".1.1"
01612 #define       OIDCFGAT      OID ".1.2"
01613 #define       OIDOC         OID ".2.1"
01614 #define       OIDCFGOC      OID ".2.2"
01615 
01616 
01617 static ConfigTable mo_cfg[] = {
01618        { "memberof-dn", "modifiersName",
01619               2, 2, 0, ARG_MAGIC|ARG_DN|MO_DN, mo_cf_gen,
01620               "( OLcfgOvAt:18.0 NAME 'olcMemberOfDN' "
01621                      "DESC 'DN to be used as modifiersName' "
01622                      "SYNTAX OMsDN SINGLE-VALUE )",
01623               NULL, NULL },
01624 
01625        { "memberof-dangling", "ignore|drop|error",
01626               2, 2, 0, ARG_MAGIC|MO_DANGLING, mo_cf_gen,
01627               "( OLcfgOvAt:18.1 NAME 'olcMemberOfDangling' "
01628                      "DESC 'Behavior with respect to dangling members, "
01629                             "constrained to ignore, drop, error' "
01630                      "SYNTAX OMsDirectoryString SINGLE-VALUE )",
01631               NULL, NULL },
01632 
01633        { "memberof-refint", "true|FALSE",
01634               2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REFINT, mo_cf_gen,
01635               "( OLcfgOvAt:18.2 NAME 'olcMemberOfRefInt' "
01636                      "DESC 'Take care of referential integrity' "
01637                      "SYNTAX OMsBoolean SINGLE-VALUE )",
01638               NULL, NULL },
01639 
01640        { "memberof-group-oc", "objectClass",
01641               2, 2, 0, ARG_MAGIC|MO_GROUP_OC, mo_cf_gen,
01642               "( OLcfgOvAt:18.3 NAME 'olcMemberOfGroupOC' "
01643                      "DESC 'Group objectClass' "
01644                      "SYNTAX OMsDirectoryString SINGLE-VALUE )",
01645               NULL, NULL },
01646 
01647        { "memberof-member-ad", "member attribute",
01648               2, 2, 0, ARG_MAGIC|MO_MEMBER_AD, mo_cf_gen,
01649               "( OLcfgOvAt:18.4 NAME 'olcMemberOfMemberAD' "
01650                      "DESC 'member attribute' "
01651                      "SYNTAX OMsDirectoryString SINGLE-VALUE )",
01652               NULL, NULL },
01653 
01654        { "memberof-memberof-ad", "memberOf attribute",
01655               2, 2, 0, ARG_MAGIC|MO_MEMBER_OF_AD, mo_cf_gen,
01656               "( OLcfgOvAt:18.5 NAME 'olcMemberOfMemberOfAD' "
01657                      "DESC 'memberOf attribute' "
01658                      "SYNTAX OMsDirectoryString SINGLE-VALUE )",
01659               NULL, NULL },
01660 
01661 #if 0
01662        { "memberof-reverse", "true|FALSE",
01663               2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REVERSE, mo_cf_gen,
01664               "( OLcfgOvAt:18.6 NAME 'olcMemberOfReverse' "
01665                      "DESC 'Take care of referential integrity "
01666                             "also when directly modifying memberOf' "
01667                      "SYNTAX OMsBoolean SINGLE-VALUE )",
01668               NULL, NULL },
01669 #endif
01670 
01671        { "memberof-dangling-error", "error code",
01672               2, 2, 0, ARG_MAGIC|MO_DANGLING_ERROR, mo_cf_gen,
01673               "( OLcfgOvAt:18.7 NAME 'olcMemberOfDanglingError' "
01674                      "DESC 'Error code returned in case of dangling back reference' "
01675                      "SYNTAX OMsDirectoryString SINGLE-VALUE )",
01676               NULL, NULL },
01677 
01678        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
01679 };
01680 
01681 static ConfigOCs mo_ocs[] = {
01682        { "( OLcfgOvOc:18.1 "
01683               "NAME 'olcMemberOf' "
01684               "DESC 'Member-of configuration' "
01685               "SUP olcOverlayConfig "
01686               "MAY ( "
01687                      "olcMemberOfDN "
01688                      "$ olcMemberOfDangling "
01689                      "$ olcMemberOfDanglingError"
01690                      "$ olcMemberOfRefInt "
01691                      "$ olcMemberOfGroupOC "
01692                      "$ olcMemberOfMemberAD "
01693                      "$ olcMemberOfMemberOfAD "
01694 #if 0
01695                      "$ olcMemberOfReverse "
01696 #endif
01697                      ") "
01698               ")",
01699               Cft_Overlay, mo_cfg, NULL, NULL },
01700        { NULL, 0, NULL }
01701 };
01702 
01703 static slap_verbmasks dangling_mode[] = {
01704        { BER_BVC( "ignore" ),             MEMBEROF_NONE },
01705        { BER_BVC( "drop" ),        MEMBEROF_FDANGLING_DROP },
01706        { BER_BVC( "error" ),              MEMBEROF_FDANGLING_ERROR },
01707        { BER_BVNULL,               0 }
01708 };
01709 
01710 static int
01711 memberof_make_group_filter( memberof_t *mo )
01712 {
01713        char          *ptr;
01714 
01715        if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) {
01716               ch_free( mo->mo_groupFilterstr.bv_val );
01717        }
01718 
01719        mo->mo_groupFilter.f_choice = LDAP_FILTER_EQUALITY;
01720        mo->mo_groupFilter.f_ava = &mo->mo_groupAVA;
01721        
01722        mo->mo_groupFilter.f_av_desc = slap_schema.si_ad_objectClass;
01723        mo->mo_groupFilter.f_av_value = mo->mo_oc_group->soc_cname;
01724 
01725        mo->mo_groupFilterstr.bv_len = STRLENOF( "(=)" )
01726               + slap_schema.si_ad_objectClass->ad_cname.bv_len
01727               + mo->mo_oc_group->soc_cname.bv_len;
01728        ptr = mo->mo_groupFilterstr.bv_val = ch_malloc( mo->mo_groupFilterstr.bv_len + 1 );
01729        *ptr++ = '(';
01730        ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
01731        *ptr++ = '=';
01732        ptr = lutil_strcopy( ptr, mo->mo_oc_group->soc_cname.bv_val );
01733        *ptr++ = ')';
01734        *ptr = '\0';
01735 
01736        return 0;
01737 }
01738 
01739 static int
01740 memberof_make_member_filter( memberof_t *mo )
01741 {
01742        char          *ptr;
01743 
01744        if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) {
01745               ch_free( mo->mo_memberFilterstr.bv_val );
01746        }
01747 
01748        mo->mo_memberFilter.f_choice = LDAP_FILTER_PRESENT;
01749        mo->mo_memberFilter.f_desc = mo->mo_ad_memberof;
01750 
01751        mo->mo_memberFilterstr.bv_len = STRLENOF( "(=*)" )
01752               + mo->mo_ad_memberof->ad_cname.bv_len;
01753        ptr = mo->mo_memberFilterstr.bv_val = ch_malloc( mo->mo_memberFilterstr.bv_len + 1 );
01754        *ptr++ = '(';
01755        ptr = lutil_strcopy( ptr, mo->mo_ad_memberof->ad_cname.bv_val );
01756        ptr = lutil_strcopy( ptr, "=*)" );
01757 
01758        return 0;
01759 }
01760 
01761 static int
01762 mo_cf_gen( ConfigArgs *c )
01763 {
01764        slap_overinst *on = (slap_overinst *)c->bi;
01765        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
01766 
01767        int           i, rc = 0;
01768 
01769        if ( c->op == SLAP_CONFIG_EMIT ) {
01770               struct berval bv = BER_BVNULL;
01771 
01772               switch( c->type ) {
01773               case MO_DN:
01774                      if ( mo->mo_dn.bv_val != NULL) {
01775                             value_add_one( &c->rvalue_vals, &mo->mo_dn );
01776                             value_add_one( &c->rvalue_nvals, &mo->mo_ndn );
01777                      }
01778                      break;
01779 
01780               case MO_DANGLING:
01781                      enum_to_verb( dangling_mode, (mo->mo_flags & MEMBEROF_FDANGLING_MASK), &bv );
01782                      if ( BER_BVISNULL( &bv ) ) {
01783                             /* there's something wrong... */
01784                             assert( 0 );
01785                             rc = 1;
01786 
01787                      } else {
01788                             value_add_one( &c->rvalue_vals, &bv );
01789                      }
01790                      break;
01791 
01792               case MO_DANGLING_ERROR:
01793                      if ( mo->mo_flags & MEMBEROF_FDANGLING_ERROR ) {
01794                             char buf[ SLAP_TEXT_BUFLEN ];
01795                             enum_to_verb( slap_ldap_response_code, mo->mo_dangling_err, &bv );
01796                             if ( BER_BVISNULL( &bv ) ) {
01797                                    bv.bv_len = snprintf( buf, sizeof( buf ), "0x%x", mo->mo_dangling_err );
01798                                    if ( bv.bv_len < sizeof( buf ) ) {
01799                                           bv.bv_val = buf;
01800                                    } else {
01801                                           rc = 1;
01802                                           break;
01803                                    }
01804                             }
01805                             value_add_one( &c->rvalue_vals, &bv );
01806                      } else {
01807                             rc = 1;
01808                      }
01809                      break;
01810 
01811               case MO_REFINT:
01812                      c->value_int = MEMBEROF_REFINT( mo );
01813                      break;
01814 
01815 #if 0
01816               case MO_REVERSE:
01817                      c->value_int = MEMBEROF_REVERSE( mo );
01818                      break;
01819 #endif
01820 
01821               case MO_GROUP_OC:
01822                      if ( mo->mo_oc_group != NULL ){
01823                             value_add_one( &c->rvalue_vals, &mo->mo_oc_group->soc_cname );
01824                      }
01825                      break;
01826 
01827               case MO_MEMBER_AD:
01828                      if ( mo->mo_ad_member != NULL ){
01829                             value_add_one( &c->rvalue_vals, &mo->mo_ad_member->ad_cname );
01830                      }
01831                      break;
01832 
01833               case MO_MEMBER_OF_AD:
01834                      if ( mo->mo_ad_memberof != NULL ){
01835                             value_add_one( &c->rvalue_vals, &mo->mo_ad_memberof->ad_cname );
01836                      }
01837                      break;
01838 
01839               default:
01840                      assert( 0 );
01841                      return 1;
01842               }
01843 
01844               return rc;
01845 
01846        } else if ( c->op == LDAP_MOD_DELETE ) {
01847               return 1;     /* FIXME */
01848 
01849        } else {
01850               switch( c->type ) {
01851               case MO_DN:
01852                      if ( !BER_BVISNULL( &mo->mo_dn ) ) {
01853                             ber_memfree( mo->mo_dn.bv_val );
01854                             ber_memfree( mo->mo_ndn.bv_val );
01855                      }
01856                      mo->mo_dn = c->value_dn;
01857                      mo->mo_ndn = c->value_ndn;
01858                      break;
01859 
01860               case MO_DANGLING:
01861                      i = verb_to_mask( c->argv[ 1 ], dangling_mode );
01862                      if ( BER_BVISNULL( &dangling_mode[ i ].word ) ) {
01863                             return 1;
01864                      }
01865 
01866                      mo->mo_flags &= ~MEMBEROF_FDANGLING_MASK;
01867                      mo->mo_flags |= dangling_mode[ i ].mask;
01868                      break;
01869 
01870               case MO_DANGLING_ERROR:
01871                      i = verb_to_mask( c->argv[ 1 ], slap_ldap_response_code );
01872                      if ( !BER_BVISNULL( &slap_ldap_response_code[ i ].word ) ) {
01873                             mo->mo_dangling_err = slap_ldap_response_code[ i ].mask;
01874                      } else if ( lutil_atoix( &mo->mo_dangling_err, c->argv[ 1 ], 0 ) ) {
01875                             return 1;
01876                      }
01877                      break;
01878 
01879               case MO_REFINT:
01880                      if ( c->value_int ) {
01881                             mo->mo_flags |= MEMBEROF_FREFINT;
01882 
01883                      } else {
01884                             mo->mo_flags &= ~MEMBEROF_FREFINT;
01885                      }
01886                      break;
01887 
01888 #if 0
01889               case MO_REVERSE:
01890                      if ( c->value_int ) {
01891                             mo->mo_flags |= MEMBEROF_FREVERSE;
01892 
01893                      } else {
01894                             mo->mo_flags &= ~MEMBEROF_FREVERSE;
01895                      }
01896                      break;
01897 #endif
01898 
01899               case MO_GROUP_OC: {
01900                      ObjectClass   *oc = NULL;
01901 
01902                      oc = oc_find( c->argv[ 1 ] );
01903                      if ( oc == NULL ) {
01904                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
01905                                    "unable to find group objectClass=\"%s\"",
01906                                    c->argv[ 1 ] );
01907                             Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
01908                                    c->log, c->cr_msg, 0 );
01909                             return 1;
01910                      }
01911 
01912                      mo->mo_oc_group = oc;
01913                      memberof_make_group_filter( mo );
01914                      } break;
01915 
01916               case MO_MEMBER_AD: {
01917                      AttributeDescription *ad = NULL;
01918                      const char           *text = NULL;
01919 
01920 
01921                      rc = slap_str2ad( c->argv[ 1 ], &ad, &text );
01922                      if ( rc != LDAP_SUCCESS ) {
01923                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
01924                                    "unable to find member attribute=\"%s\": %s (%d)",
01925                                    c->argv[ 1 ], text, rc );
01926                             Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
01927                                    c->log, c->cr_msg, 0 );
01928                             return 1;
01929                      }
01930 
01931                      if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX )             /* e.g. "member" */
01932                             && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */
01933                      {
01934                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
01935                                    "member attribute=\"%s\" must either "
01936                                    "have DN (%s) or nameUID (%s) syntax",
01937                                    c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
01938                             Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
01939                                    c->log, c->cr_msg, 0 );
01940                             return 1;
01941                      }
01942 
01943                      mo->mo_ad_member = ad;
01944                      } break;
01945 
01946               case MO_MEMBER_OF_AD: {
01947                      AttributeDescription *ad = NULL;
01948                      const char           *text = NULL;
01949 
01950 
01951                      rc = slap_str2ad( c->argv[ 1 ], &ad, &text );
01952                      if ( rc != LDAP_SUCCESS ) {
01953                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
01954                                    "unable to find memberof attribute=\"%s\": %s (%d)",
01955                                    c->argv[ 1 ], text, rc );
01956                             Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
01957                                    c->log, c->cr_msg, 0 );
01958                             return 1;
01959                      }
01960 
01961                      if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX )             /* e.g. "member" */
01962                             && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */
01963                      {
01964                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
01965                                    "memberof attribute=\"%s\" must either "
01966                                    "have DN (%s) or nameUID (%s) syntax",
01967                                    c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
01968                             Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
01969                                    c->log, c->cr_msg, 0 );
01970                             return 1;
01971                      }
01972 
01973                      mo->mo_ad_memberof = ad;
01974                      memberof_make_member_filter( mo );
01975                      } break;
01976 
01977               default:
01978                      assert( 0 );
01979                      return 1;
01980               }
01981        }
01982 
01983        return 0;
01984 }
01985 
01986 static int
01987 memberof_db_open(
01988        BackendDB     *be,
01989        ConfigReply   *cr )
01990 {
01991        slap_overinst *on = (slap_overinst *)be->bd_info;
01992        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
01993        
01994        int           rc;
01995        const char    *text = NULL;
01996 
01997        if( ! mo->mo_ad_memberof ){
01998               rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &mo->mo_ad_memberof, &text );
01999               if ( rc != LDAP_SUCCESS ) {
02000                      Debug( LDAP_DEBUG_ANY, "memberof_db_open: "
02001                                    "unable to find attribute=\"%s\": %s (%d)\n",
02002                                    SLAPD_MEMBEROF_ATTR, text, rc );
02003                      return rc;
02004               }
02005        }
02006 
02007        if( ! mo->mo_ad_member ){
02008               rc = slap_str2ad( SLAPD_GROUP_ATTR, &mo->mo_ad_member, &text );
02009               if ( rc != LDAP_SUCCESS ) {
02010                      Debug( LDAP_DEBUG_ANY, "memberof_db_open: "
02011                                    "unable to find attribute=\"%s\": %s (%d)\n",
02012                                    SLAPD_GROUP_ATTR, text, rc );
02013                      return rc;
02014               }
02015        }
02016 
02017        if( ! mo->mo_oc_group ){
02018               mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS );
02019               if ( mo->mo_oc_group == NULL ) {
02020                      Debug( LDAP_DEBUG_ANY,
02021                                    "memberof_db_open: "
02022                                    "unable to find objectClass=\"%s\"\n",
02023                                    SLAPD_GROUP_CLASS, 0, 0 );
02024                      return 1;
02025               }
02026        }
02027 
02028        if ( BER_BVISNULL( &mo->mo_dn ) && !BER_BVISNULL( &be->be_rootdn ) ) {
02029               ber_dupbv( &mo->mo_dn, &be->be_rootdn );
02030               ber_dupbv( &mo->mo_ndn, &be->be_rootndn );
02031        }
02032 
02033        if ( BER_BVISNULL( &mo->mo_groupFilterstr ) ) {
02034               memberof_make_group_filter( mo );
02035        }
02036 
02037        if ( BER_BVISNULL( &mo->mo_memberFilterstr ) ) {
02038               memberof_make_member_filter( mo );
02039        }
02040 
02041        return 0;
02042 }
02043 
02044 static int
02045 memberof_db_destroy(
02046        BackendDB     *be,
02047        ConfigReply   *cr )
02048 {
02049        slap_overinst *on = (slap_overinst *)be->bd_info;
02050        memberof_t    *mo = (memberof_t *)on->on_bi.bi_private;
02051 
02052        if ( mo ) {
02053               if ( !BER_BVISNULL( &mo->mo_dn ) ) {
02054                      ber_memfree( mo->mo_dn.bv_val );
02055                      ber_memfree( mo->mo_ndn.bv_val );
02056               }
02057 
02058               if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) {
02059                      ber_memfree( mo->mo_groupFilterstr.bv_val );
02060               }
02061 
02062               if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) {
02063                      ber_memfree( mo->mo_memberFilterstr.bv_val );
02064               }
02065 
02066               ber_memfree( mo );
02067        }
02068 
02069        return 0;
02070 }
02071 
02072 /* unused */
02073 static AttributeDescription *ad_memberOf;
02074 
02075 static struct {
02076        char   *desc;
02077        AttributeDescription **adp;
02078 } as[] = {
02079        { "( 1.2.840.113556.1.2.102 "
02080               "NAME 'memberOf' "
02081               "DESC 'Group that the entry belongs to' "
02082               "SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' "
02083               "EQUALITY distinguishedNameMatch " /* added */
02084               "USAGE dSAOperation "                     /* added; questioned */
02085               /* "NO-USER-MODIFICATION " */             /* add? */
02086               "X-ORIGIN 'iPlanet Delegated Administrator' )",
02087               &ad_memberOf },
02088        { NULL }
02089 };
02090 
02091 #if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC
02092 static
02093 #endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */
02094 int
02095 memberof_initialize( void )
02096 {
02097        int                  code, i;
02098 
02099        for ( i = 0; as[ i ].desc != NULL; i++ ) {
02100               code = register_at( as[ i ].desc, as[ i ].adp, 0 );
02101               if ( code ) {
02102                      Debug( LDAP_DEBUG_ANY,
02103                             "memberof_initialize: register_at #%d failed\n",
02104                             i, 0, 0 );
02105                      return code;
02106               }
02107        }
02108 
02109        memberof.on_bi.bi_type = "memberof";
02110 
02111        memberof.on_bi.bi_db_init = memberof_db_init;
02112        memberof.on_bi.bi_db_open = memberof_db_open;
02113        memberof.on_bi.bi_db_destroy = memberof_db_destroy;
02114 
02115        memberof.on_bi.bi_op_add = memberof_op_add;
02116        memberof.on_bi.bi_op_delete = memberof_op_delete;
02117        memberof.on_bi.bi_op_modify = memberof_op_modify;
02118        memberof.on_bi.bi_op_modrdn = memberof_op_modrdn;
02119 
02120        memberof.on_bi.bi_cf_ocs = mo_ocs;
02121 
02122        code = config_register_schema( mo_cfg, mo_ocs );
02123        if ( code ) return code;
02124 
02125        return overlay_register( &memberof );
02126 }
02127 
02128 #if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC
02129 int
02130 init_module( int argc, char *argv[] )
02131 {
02132        return memberof_initialize();
02133 }
02134 #endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */
02135 
02136 #endif /* SLAPD_OVER_MEMBEROF */