#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "slap.h"
#include "config.h"
#include "lutil.h"
#ifndef SLAPD_MEMBEROF_ATTR
#define SLAPD_MEMBEROF_ATTR "memberOf"
#endif
typedef struct autogroup_filter_t {
struct berval agf_dn;
struct berval agf_ndn;
struct berval agf_filterstr;
Filter *agf_filter;
int agf_scope;
AttributeName *agf_anlist;
struct autogroup_filter_t *agf_next;
} autogroup_filter_t;
typedef struct autogroup_def_t {
ObjectClass *agd_oc;
AttributeDescription *agd_member_url_ad;
AttributeDescription *agd_member_ad;
struct autogroup_def_t *agd_next;
} autogroup_def_t;
typedef struct autogroup_entry_t {
BerValue age_dn;
BerValue age_ndn;
autogroup_filter_t *age_filter;
autogroup_def_t *age_def;
ldap_pvt_thread_mutex_t age_mutex;
int age_mustrefresh;
int age_modrdn_olddnmodified;
struct autogroup_entry_t *age_next;
} autogroup_entry_t;
typedef struct autogroup_info_t {
autogroup_def_t *agi_def;
autogroup_entry_t *agi_entry;
AttributeDescription *agi_memberof_ad;
ldap_pvt_thread_mutex_t agi_mutex;
} autogroup_info_t;
typedef struct autogroup_sc_t {
autogroup_info_t *ags_info;
autogroup_def_t *ags_def;
} autogroup_sc_t;
typedef struct autogroup_ga_t {
autogroup_entry_t *agg_group;
autogroup_filter_t *agg_filter;
Entry *agg_entry;
Modifications *agg_mod;
Modifications *agg_mod_last;
} autogroup_ga_t;
static int
autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
SlapReply sreply = {REP_RESULT};
BerValue *vals, *nvals;
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
Operation o = *op;
assert( dn != NULL );
assert( ndn != NULL );
Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
dn->bv_val, age->age_dn.bv_val, 0);
vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
ber_dupbv( vals, dn );
BER_BVZERO( &vals[ 1 ] );
ber_dupbv( nvals, ndn );
BER_BVZERO( &nvals[ 1 ] );
modlist->sml_op = LDAP_MOD_ADD;
modlist->sml_desc = age->age_def->agd_member_ad;
modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
modlist->sml_values = vals;
modlist->sml_nvalues = nvals;
modlist->sml_numvals = 1;
modlist->sml_flags = SLAP_MOD_INTERNAL;
modlist->sml_next = NULL;
o.o_tag = LDAP_REQ_MODIFY;
o.o_callback = &cb;
o.orm_modlist = modlist;
o.o_req_dn = age->age_dn;
o.o_req_ndn = age->age_ndn;
o.o_permissive_modify = 1;
o.o_managedsait = SLAP_CONTROL_CRITICAL;
o.o_relax = SLAP_CONTROL_CRITICAL;
o.o_bd->bd_info = (BackendInfo *)on->on_info;
(void)op->o_bd->be_modify( &o, &sreply );
o.o_bd->bd_info = (BackendInfo *)on;
slap_mods_free( modlist, 1 );
return sreply.sr_err;
}
static int
autogroup_add_member_values_to_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Modifications modlist;
SlapReply sreply = {REP_RESULT};
Attribute *attr;
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
Operation o = *op;
assert( e != NULL );
Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
e->e_name.bv_val, age->age_dn.bv_val, 0);
attr = attrs_find( e->e_attrs, attrdesc );
if (!attr) {
return LDAP_SUCCESS;
}
modlist.sml_op = LDAP_MOD_ADD;
modlist.sml_desc = age->age_def->agd_member_ad;
modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
modlist.sml_values = attr->a_vals;
modlist.sml_nvalues = attr->a_nvals;
modlist.sml_numvals = attr->a_numvals;
modlist.sml_flags = SLAP_MOD_INTERNAL;
modlist.sml_next = NULL;
o.o_tag = LDAP_REQ_MODIFY;
o.o_callback = &cb;
o.orm_modlist = &modlist;
o.o_req_dn = age->age_dn;
o.o_req_ndn = age->age_ndn;
o.o_permissive_modify = 1;
o.o_managedsait = SLAP_CONTROL_CRITICAL;
o.o_relax = SLAP_CONTROL_CRITICAL;
o.o_bd->bd_info = (BackendInfo *)on->on_info;
(void)op->o_bd->be_modify( &o, &sreply );
o.o_bd->bd_info = (BackendInfo *)on;
return sreply.sr_err;
}
static int
autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
SlapReply sreply = {REP_RESULT};
BerValue *vals, *nvals;
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
Operation o = *op;
if ( dn == NULL || ndn == NULL ) {
Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
age->age_dn.bv_val, 0 ,0);
modlist->sml_values = NULL;
modlist->sml_nvalues = NULL;
modlist->sml_numvals = 0;
} else {
Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
dn->bv_val, age->age_dn.bv_val, 0);
vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
ber_dupbv( vals, dn );
BER_BVZERO( &vals[ 1 ] );
ber_dupbv( nvals, ndn );
BER_BVZERO( &nvals[ 1 ] );
modlist->sml_values = vals;
modlist->sml_nvalues = nvals;
modlist->sml_numvals = 1;
}
modlist->sml_op = LDAP_MOD_DELETE;
modlist->sml_desc = age->age_def->agd_member_ad;
modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
modlist->sml_flags = SLAP_MOD_INTERNAL;
modlist->sml_next = NULL;
o.o_callback = &cb;
o.o_tag = LDAP_REQ_MODIFY;
o.orm_modlist = modlist;
o.o_req_dn = age->age_dn;
o.o_req_ndn = age->age_ndn;
o.o_relax = SLAP_CONTROL_CRITICAL;
o.o_managedsait = SLAP_CONTROL_CRITICAL;
o.o_permissive_modify = 1;
o.o_bd->bd_info = (BackendInfo *)on->on_info;
(void)op->o_bd->be_modify( &o, &sreply );
o.o_bd->bd_info = (BackendInfo *)on;
slap_mods_free( modlist, 1 );
return sreply.sr_err;
}
static int
autogroup_delete_member_values_from_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Modifications modlist;
SlapReply sreply = {REP_RESULT};
Attribute *attr;
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
Operation o = *op;
assert( e != NULL );
Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n",
e->e_name.bv_val, age->age_dn.bv_val, 0);
attr = attrs_find( e->e_attrs, attrdesc );
if (!attr) {
return LDAP_SUCCESS;
}
modlist.sml_op = LDAP_MOD_DELETE;
modlist.sml_desc = age->age_def->agd_member_ad;
modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
modlist.sml_values = attr->a_vals;
modlist.sml_nvalues = attr->a_nvals;
modlist.sml_numvals = attr->a_numvals;
modlist.sml_flags = SLAP_MOD_INTERNAL;
modlist.sml_next = NULL;
o.o_tag = LDAP_REQ_MODIFY;
o.o_callback = &cb;
o.orm_modlist = &modlist;
o.o_req_dn = age->age_dn;
o.o_req_ndn = age->age_ndn;
o.o_permissive_modify = 1;
o.o_managedsait = SLAP_CONTROL_CRITICAL;
o.o_relax = SLAP_CONTROL_CRITICAL;
o.o_bd->bd_info = (BackendInfo *)on->on_info;
(void)op->o_bd->be_modify( &o, &sreply );
o.o_bd->bd_info = (BackendInfo *)on;
return sreply.sr_err;
}
static int
autogroup_member_search_cb( Operation *op, SlapReply *rs )
{
assert( op->o_tag == LDAP_REQ_SEARCH );
if ( rs->sr_type == REP_SEARCH ) {
autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
autogroup_entry_t *age = agg->agg_group;
autogroup_filter_t *agf = agg->agg_filter;
Modification mod;
const char *text = NULL;
char textbuf[1024];
struct berval *vals, *nvals;
int numvals;
Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
if ( agf->agf_anlist ) {
Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
if (attr) {
vals = attr->a_vals;
nvals = attr->a_nvals;
numvals = attr->a_numvals;
} else {
return 0;
}
} else {
struct berval lvals[ 2 ], lnvals[ 2 ];
lvals[ 0 ] = rs->sr_entry->e_name;
BER_BVZERO( &lvals[ 1 ] );
lnvals[ 0 ] = rs->sr_entry->e_nname;
BER_BVZERO( &lnvals[ 1 ] );
vals = lvals;
nvals = lnvals;
numvals = 1;
}
mod.sm_op = LDAP_MOD_ADD;
mod.sm_desc = age->age_def->agd_member_ad;
mod.sm_type = age->age_def->agd_member_ad->ad_cname;
mod.sm_values = vals;
mod.sm_nvalues = nvals;
mod.sm_numvals = numvals;
modify_add_values( agg->agg_entry, &mod, 1, &text, textbuf, sizeof( textbuf ) );
}
return 0;
}
static int
autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
{
assert( op->o_tag == LDAP_REQ_SEARCH );
if ( rs->sr_type == REP_SEARCH ) {
autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
autogroup_entry_t *age = agg->agg_group;
autogroup_filter_t *agf = agg->agg_filter;
Modifications *modlist;
struct berval *vals, *nvals;
int numvals;
Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
if ( agf->agf_anlist ) {
Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
if (attr) {
vals = attr->a_vals;
nvals = attr->a_nvals;
numvals = attr->a_numvals;
} else {
return 0;
}
} else {
struct berval lvals[ 2 ], lnvals[ 2 ];
lvals[ 0 ] = rs->sr_entry->e_name;
BER_BVZERO( &lvals[ 1 ] );
lnvals[ 0 ] = rs->sr_entry->e_nname;
BER_BVZERO( &lnvals[ 1 ] );
vals = lvals;
nvals = lnvals;
numvals = 1;
}
if ( numvals ) {
modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
modlist->sml_op = LDAP_MOD_ADD;
modlist->sml_desc = age->age_def->agd_member_ad;
modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
modlist->sml_numvals = numvals;
modlist->sml_flags = SLAP_MOD_INTERNAL;
modlist->sml_next = NULL;
if ( agg->agg_mod == NULL ) {
agg->agg_mod = modlist;
agg->agg_mod_last = modlist;
} else {
agg->agg_mod_last->sml_next = modlist;
agg->agg_mod_last = modlist;
}
}
}
return 0;
}
static int
autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Operation o = *op;
SlapReply rs = { REP_SEARCH };
slap_callback cb = { 0 };
slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
autogroup_ga_t agg;
Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
age->age_dn.bv_val, 0, 0);
o.ors_attrsonly = 0;
o.o_tag = LDAP_REQ_SEARCH;
o.o_req_dn = agf->agf_dn;
o.o_req_ndn = agf->agf_ndn;
o.ors_filterstr = agf->agf_filterstr;
o.ors_filter = agf->agf_filter;
o.ors_scope = agf->agf_scope;
o.ors_deref = LDAP_DEREF_NEVER;
o.ors_limit = NULL;
o.ors_tlimit = SLAP_NO_LIMIT;
o.ors_slimit = SLAP_NO_LIMIT;
o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
agg.agg_group = age;
agg.agg_filter = agf;
agg.agg_mod = NULL;
agg.agg_mod_last = NULL;
agg.agg_entry = e;
cb.sc_private = &agg;
if ( modify == 1 ) {
cb.sc_response = autogroup_member_search_modify_cb;
} else {
cb.sc_response = autogroup_member_search_cb;
}
cb.sc_cleanup = NULL;
cb.sc_next = NULL;
o.o_callback = &cb;
o.o_bd->bd_info = (BackendInfo *)on->on_info;
op->o_bd->be_search( &o, &rs );
o.o_bd->bd_info = (BackendInfo *)on;
if ( modify == 1 && agg.agg_mod ) {
rs_reinit( &rs, REP_RESULT );
o = *op;
o.o_callback = &null_cb;
o.o_tag = LDAP_REQ_MODIFY;
o.orm_modlist = agg.agg_mod;
o.o_req_dn = age->age_dn;
o.o_req_ndn = age->age_ndn;
o.o_relax = SLAP_CONTROL_CRITICAL;
o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
o.o_permissive_modify = 1;
o.o_bd->bd_info = (BackendInfo *)on->on_info;
(void)op->o_bd->be_modify( &o, &rs );
o.o_bd->bd_info = (BackendInfo *)on;
slap_mods_free(agg.agg_mod, 1);
}
return 0;
}
static int
autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
{
autogroup_entry_t **agep = &agi->agi_entry;
autogroup_filter_t *agf, *agf_prev = NULL;
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
LDAPURLDesc *lud = NULL;
Attribute *a;
BerValue *bv, dn;
int rc = 0, match = 1, null_entry = 0;
if ( e == NULL ) {
if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
LDAP_SUCCESS || e == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
return 1;
}
null_entry = 1;
}
Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
e->e_name.bv_val, 0, 0);
if ( agi->agi_entry != NULL ) {
for ( ; *agep ; agep = &(*agep)->age_next ) {
dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
if ( match == 0 ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
return 1;
}
;
}
}
*agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
(*agep)->age_def = agd;
(*agep)->age_filter = NULL;
(*agep)->age_mustrefresh = 0;
(*agep)->age_modrdn_olddnmodified = 0;
ber_dupbv( &(*agep)->age_dn, &e->e_name );
ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
if ( null_entry == 1 ) {
a = attrs_dup( a );
overlay_entry_release_ov( op, e, 0, on );
}
if( a == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
} else {
for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
ch_free( agf );
continue;
}
agf->agf_scope = lud->lud_scope;
if ( lud->lud_dn == NULL ) {
BER_BVSTR( &dn, "" );
} else {
ber_str2bv( lud->lud_dn, 0, 0, &dn );
}
rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
goto cleanup;
}
if ( lud->lud_filter != NULL ) {
ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
agf->agf_filter = str2filter( lud->lud_filter );
}
if ( lud->lud_attrs != NULL ) {
int i;
for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
;
}
if ( i > 1 ) {
Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n",
bv->bv_val, 0, 0);
ldap_free_urldesc( lud );
ch_free( agf );
continue;
}
agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
if ( agf->agf_anlist == NULL ) {
Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
lud->lud_attrs[0], 0, 0 );
ldap_free_urldesc( lud );
ch_free( agf );
continue;
}
}
agf->agf_next = NULL;
if( (*agep)->age_filter == NULL ) {
(*agep)->age_filter = agf;
}
if( agf_prev != NULL ) {
agf_prev->agf_next = agf;
}
agf_prev = agf;
if ( scan == 1 ){
autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
}
Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
ldap_free_urldesc( lud );
continue;
cleanup:;
ldap_free_urldesc( lud );
ch_free( agf );
}
}
if ( null_entry == 1 ) {
attrs_free( a );
}
return rc;
}
static int
autogroup_group_add_cb( Operation *op, SlapReply *rs )
{
assert( op->o_tag == LDAP_REQ_SEARCH );
if ( rs->sr_type == REP_SEARCH ) {
autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
}
return 0;
}
static int
autogroup_add_entry( Operation *op, SlapReply *rs)
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
autogroup_def_t *agd = agi->agi_def;
autogroup_entry_t *age;
autogroup_filter_t *agf;
int rc = 0;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
op->ora_e->e_name.bv_val, 0, 0);
ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
for ( ; agd ; agd = agd->agd_next ) {
if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
Modification mod;
const char *text = NULL;
char textbuf[1024];
mod.sm_op = LDAP_MOD_DELETE;
mod.sm_desc = agd->agd_member_ad;
mod.sm_type = agd->agd_member_ad->ad_cname;
mod.sm_values = NULL;
mod.sm_nvalues = NULL;
modify_delete_values( op->ora_e, &mod, 1, &text, textbuf, sizeof( textbuf ) );
autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
}
for ( age = agi->agi_entry; age ; age = age->age_next ) {
ldap_pvt_thread_mutex_lock( &age->age_mutex );
for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
rc = test_filter( op, op->ora_e, agf->agf_filter );
if ( rc == LDAP_COMPARE_TRUE ) {
if ( agf->agf_anlist ) {
autogroup_add_member_values_to_group( op, op->ora_e, age, agf->agf_anlist[0].an_desc );
} else {
autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
}
break;
}
}
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
}
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
static int
autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
{
autogroup_entry_t *age = agi->agi_entry,
*age_prev = NULL,
*age_next;
int rc = 1;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
age->age_dn.bv_val, 0, 0);
for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
age_next = age->age_next;
if ( age == e ) {
autogroup_filter_t *agf = age->age_filter,
*agf_next;
if ( age_prev != NULL ) {
age_prev->age_next = age_next;
} else {
agi->agi_entry = NULL;
}
ch_free( age->age_dn.bv_val );
ch_free( age->age_ndn.bv_val );
for( agf_next = agf ; agf_next ; agf = agf_next ){
agf_next = agf->agf_next;
filter_free( agf->agf_filter );
ch_free( agf->agf_filterstr.bv_val );
ch_free( agf->agf_dn.bv_val );
ch_free( agf->agf_ndn.bv_val );
anlist_free( agf->agf_anlist, 1, NULL );
ch_free( agf );
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
ldap_pvt_thread_mutex_destroy( &age->age_mutex );
ch_free( age );
rc = 0;
return rc;
}
}
Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
return rc;
}
static int
autogroup_delete_entry( Operation *op, SlapReply *rs)
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
autogroup_entry_t *age, *age_prev, *age_next;
autogroup_filter_t *agf;
Entry *e;
int matched_group = 0, rc = 0;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
LDAP_SUCCESS || e == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) {
age = age_next;
ldap_pvt_thread_mutex_lock( &age->age_mutex );
age_next = age->age_next;
if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
int match = 1;
matched_group = 1;
dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
if ( match == 0 ) {
autogroup_delete_group( agi, age );
break;
}
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
}
if ( matched_group == 1 ) {
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
for ( age = agi->agi_entry ; age ; age = age->age_next ) {
ldap_pvt_thread_mutex_lock( &age->age_mutex );
for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
rc = test_filter( op, e, agf->agf_filter );
if ( rc == LDAP_COMPARE_TRUE ) {
if ( agf->agf_anlist ) {
age->age_mustrefresh = 1;
} else {
autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
}
break;
}
}
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
}
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
static int
autogroup_response( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
autogroup_def_t *agd = agi->agi_def;
autogroup_entry_t *age;
autogroup_filter_t *agf;
BerValue new_dn, new_ndn, pdn;
Entry *e, *group;
Attribute *a, *ea;
int is_olddn, is_newdn, is_value_refresh, dn_equal;
if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
for ( age = agi->agi_entry ; age ; age = age->age_next ) {
ldap_pvt_thread_mutex_lock( &age->age_mutex );
if ( age->age_mustrefresh ) {
autogroup_delete_member_from_group( op, NULL, NULL, age) ;
for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
}
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
}
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
}
} else if ( op->o_tag == LDAP_REQ_MODRDN ) {
if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
if ( op->oq_modrdn.rs_newSup ) {
pdn = *op->oq_modrdn.rs_newSup;
} else {
dnParent( &op->o_req_dn, &pdn );
}
build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
if ( op->oq_modrdn.rs_nnewSup ) {
pdn = *op->oq_modrdn.rs_nnewSup;
} else {
dnParent( &op->o_req_ndn, &pdn );
}
build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
LDAP_SUCCESS || e == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
if ( a == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
for ( ; agd; agd = agd->agd_next ) {
if ( value_find_ex( slap_schema.si_ad_objectClass,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
a->a_nvals, &agd->agd_oc->soc_cname,
op->o_tmpmemctx ) == 0 )
{
for ( age = agi->agi_entry ; age ; age = age->age_next ) {
int match = 1;
dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
if ( match == 0 ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
ber_dupbv( &age->age_dn, &new_dn );
ber_dupbv( &age->age_ndn, &new_ndn );
op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
}
}
}
for ( age = agi->agi_entry ; age ; age = age->age_next ) {
is_olddn = 0;
is_newdn = 0;
is_value_refresh = 0;
ldap_pvt_thread_mutex_lock( &age->age_mutex );
if ( age->age_filter && age->age_filter->agf_anlist ) {
ea = attrs_find( e->e_attrs, age->age_filter->agf_anlist[0].an_desc );
}
else {
ea = NULL;
}
if ( age->age_modrdn_olddnmodified ) {
is_olddn = 1;
is_value_refresh = 1;
age->age_modrdn_olddnmodified = 0;
} else {
if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
LDAP_SUCCESS || group == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
if ( a != NULL ) {
if ( value_find_ex( age->age_def->agd_member_ad,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
{
is_olddn = 1;
}
}
overlay_entry_release_ov( op, group, 0, on );
}
for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
is_newdn = 1;
break;
}
}
if ( is_value_refresh ) {
if ( is_olddn != is_newdn ) {
autogroup_delete_member_from_group( op, NULL, NULL, age) ;
for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
}
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
continue;
}
if ( is_olddn == 1 && is_newdn == 0 ) {
if ( ea )
autogroup_delete_member_values_from_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
else
autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
} else
if ( is_olddn == 0 && is_newdn == 1 ) {
for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
if ( ea )
autogroup_add_member_values_to_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
else
autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
break;
}
}
} else
if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
if ( ea ) {
autogroup_delete_member_from_group( op, NULL, NULL, age) ;
for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
}
}
else {
autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
}
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
}
op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
}
}
if ( op->o_tag == LDAP_REQ_MODIFY ) {
if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
LDAP_SUCCESS || e == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
if ( a == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
for ( ; agd; agd = agd->agd_next ) {
if ( value_find_ex( slap_schema.si_ad_objectClass,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
a->a_nvals, &agd->agd_oc->soc_cname,
op->o_tmpmemctx ) == 0 )
{
Modifications *m;
int match = 1;
m = op->orm_modlist;
for ( age = agi->agi_entry ; age ; age = age->age_next ) {
ldap_pvt_thread_mutex_lock( &age->age_mutex );
dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
if ( match == 0 ) {
for ( ; m ; m = m->sml_next ) {
if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
autogroup_def_t *group_agd = age->age_def;
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
op->o_req_dn.bv_val, 0, 0);
overlay_entry_release_ov( op, e, 0, on );
autogroup_delete_member_from_group( op, NULL, NULL, age );
autogroup_delete_group( agi, age );
autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
break;
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
}
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
}
for ( age = agi->agi_entry ; age ; age = age->age_next ) {
is_olddn = 0;
is_newdn = 0;
ldap_pvt_thread_mutex_lock( &age->age_mutex );
if ( age->age_filter && age->age_filter->agf_anlist ) {
ea = attrs_find( e->e_attrs, age->age_filter->agf_anlist[0].an_desc );
}
else {
ea = NULL;
}
if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
LDAP_SUCCESS || group == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
age->age_dn.bv_val, 0, 0);
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
if ( a != NULL ) {
if ( value_find_ex( age->age_def->agd_member_ad,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
{
is_olddn = 1;
}
}
overlay_entry_release_ov( op, group, 0, on );
for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
is_newdn = 1;
break;
}
}
}
if ( is_olddn == 1 && is_newdn == 0 ) {
if(ea)
autogroup_delete_member_values_from_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
else
autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
} else
if ( is_olddn == 0 && is_newdn == 1 ) {
if(ea)
autogroup_add_member_values_to_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
else
autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
}
ldap_pvt_thread_mutex_unlock( &age->age_mutex );
}
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
}
}
return SLAP_CB_CONTINUE;
}
static int
autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad )
{
int result = 0;
if ( f == NULL ) return 0;
switch ( f->f_choice & SLAPD_FILTER_MASK ) {
case LDAP_FILTER_AND:
case LDAP_FILTER_OR:
case LDAP_FILTER_NOT:
for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) {
result = result || autogroup_memberOf_filter( f, dn, memberof_ad );
}
break;
case LDAP_FILTER_EQUALITY:
result = ( f->f_ava->aa_desc == memberof_ad &&
ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 );
break;
default:
break;
}
return result;
}
static int
autogroup_modify_entry( Operation *op, SlapReply *rs)
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
autogroup_def_t *agd = agi->agi_def;
autogroup_entry_t *age;
Entry *e;
Attribute *a;
if ( get_manageDSAit( op ) ) {
return SLAP_CB_CONTINUE;
}
Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
LDAP_SUCCESS || e == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
for ( age = agi->agi_entry; age ; age = age->age_next ) {
autogroup_filter_t *agf;
for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
if ( agf->agf_anlist ) {
Modifications *m;
for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
int rc = test_filter( op, e, agf->agf_filter );
if ( rc == LDAP_COMPARE_TRUE ) {
age->age_mustrefresh = 1;
}
}
}
}
}
if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) {
age->age_mustrefresh = 1;
}
}
}
a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
if ( a == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
for ( ; agd; agd = agd->agd_next ) {
if ( value_find_ex( slap_schema.si_ad_objectClass,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
a->a_nvals, &agd->agd_oc->soc_cname,
op->o_tmpmemctx ) == 0 )
{
Modifications *m;
int match = 1;
m = op->orm_modlist;
for ( age = agi->agi_entry ; age ; age = age->age_next ) {
dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
if ( match == 0 ) {
for ( ; m ; m = m->sml_next ) {
if ( m->sml_desc == age->age_def->agd_member_ad ) {
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
return LDAP_CONSTRAINT_VIOLATION;
}
}
break;
}
}
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
}
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
static int
autogroup_modrdn_entry( Operation *op, SlapReply *rs)
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
autogroup_entry_t *age;
Entry *e;
if ( get_manageDSAit( op ) ) {
return SLAP_CB_CONTINUE;
}
Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
LDAP_SUCCESS || e == NULL ) {
Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
for ( age = agi->agi_entry; age ; age = age->age_next ) {
autogroup_filter_t *agf;
for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
if ( agf->agf_anlist ) {
if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
int rc = test_filter( op, e, agf->agf_filter );
if ( rc == LDAP_COMPARE_TRUE ) {
age->age_modrdn_olddnmodified = 1;
}
}
}
}
}
overlay_entry_release_ov( op, e, 0, on );
ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
return SLAP_CB_CONTINUE;
}
static int
autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
{
char *ptr;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
op->ors_filterstr.bv_len = STRLENOF( "(=)" )
+ slap_schema.si_ad_objectClass->ad_cname.bv_len
+ agd->agd_oc->soc_cname.bv_len;
ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
*ptr++ = '(';
ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
*ptr++ = '=';
ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
*ptr++ = ')';
*ptr = '\0';
op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
return 0;
}
enum {
AG_ATTRSET = 1,
AG_MEMBER_OF_AD,
AG_LAST
};
static ConfigDriver ag_cfgen;
static ConfigTable agcfg[] = {
{ "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
"( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
"DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"X-ORDERED 'VALUES' )",
NULL, NULL },
{ "autogroup-memberof-ad", "memberOf attribute",
2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen,
"( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' "
"DESC 'memberOf attribute' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
static ConfigOCs agocs[] = {
{ "( OLcfgCtOc:2.1 "
"NAME 'olcAutomaticGroups' "
"DESC 'Automatic groups configuration' "
"SUP olcOverlayConfig "
"MAY ( "
"olcAGattrSet "
"$ olcAGmemberOfAd "
")"
")",
Cft_Overlay, agcfg, NULL, NULL },
{ NULL, 0, NULL }
};
static int
ag_cfgen( ConfigArgs *c )
{
slap_overinst *on = (slap_overinst *)c->bi;
autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
autogroup_def_t *agd;
autogroup_entry_t *age;
int rc = 0, i;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
if( agi == NULL ) {
agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
ldap_pvt_thread_mutex_init( &agi->agi_mutex );
agi->agi_def = NULL;
agi->agi_entry = NULL;
on->on_bi.bi_private = (void *)agi;
}
agd = agi->agi_def;
age = agi->agi_entry;
if ( c->op == SLAP_CONFIG_EMIT ) {
switch( c->type ){
case AG_ATTRSET:
for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
struct berval bv;
char *ptr = c->cr_msg;
assert(agd->agd_oc != NULL);
assert(agd->agd_member_url_ad != NULL);
assert(agd->agd_member_ad != NULL);
ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
SLAP_X_ORDERED_FMT "%s %s %s", i,
agd->agd_oc->soc_cname.bv_val,
agd->agd_member_url_ad->ad_cname.bv_val,
agd->agd_member_ad->ad_cname.bv_val );
bv.bv_val = c->cr_msg;
bv.bv_len = ptr - bv.bv_val;
value_add_one ( &c->rvalue_vals, &bv );
}
break;
case AG_MEMBER_OF_AD:
if ( agi->agi_memberof_ad != NULL ){
value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname );
}
break;
default:
assert( 0 );
return 1;
}
return rc;
}else if ( c->op == LDAP_MOD_DELETE ) {
if ( c->valx < 0) {
autogroup_def_t *agd_next;
autogroup_entry_t *age_next;
autogroup_filter_t *agf = age->age_filter,
*agf_next;
for ( agd_next = agd; agd_next; agd = agd_next ) {
agd_next = agd->agd_next;
ch_free( agd );
}
for ( age_next = age ; age_next ; age = age_next ) {
age_next = age->age_next;
ch_free( age->age_dn.bv_val );
ch_free( age->age_ndn.bv_val );
for( agf_next = agf ; agf_next ; agf = agf_next ){
agf_next = agf->agf_next;
filter_free( agf->agf_filter );
ch_free( agf->agf_filterstr.bv_val );
ch_free( agf->agf_dn.bv_val );
ch_free( agf->agf_ndn.bv_val );
anlist_free( agf->agf_anlist, 1, NULL );
ch_free( agf );
}
ldap_pvt_thread_mutex_init( &age->age_mutex );
ch_free( age );
}
ch_free( agi );
on->on_bi.bi_private = NULL;
} else {
autogroup_def_t **agdp;
autogroup_entry_t *age_next, *age_prev;
autogroup_filter_t *agf,
*agf_next;
for ( i = 0, agdp = &agi->agi_def;
i < c->valx; i++ )
{
if ( *agdp == NULL) {
return 1;
}
agdp = &(*agdp)->agd_next;
}
agd = *agdp;
*agdp = agd->agd_next;
for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
age_next = age->age_next;
if( age->age_def == agd ) {
agf = age->age_filter;
ch_free( age->age_dn.bv_val );
ch_free( age->age_ndn.bv_val );
for ( agf_next = agf; agf_next ; agf = agf_next ) {
agf_next = agf->agf_next;
filter_free( agf->agf_filter );
ch_free( agf->agf_filterstr.bv_val );
ch_free( agf->agf_dn.bv_val );
ch_free( agf->agf_ndn.bv_val );
anlist_free( agf->agf_anlist, 1, NULL );
ch_free( agf );
}
ldap_pvt_thread_mutex_destroy( &age->age_mutex );
ch_free( age );
age = age_prev;
if( age_prev != NULL ) {
age_prev->age_next = age_next;
}
}
}
ch_free( agd );
agd = agi->agi_def;
}
return rc;
}
switch(c->type){
case AG_ATTRSET: {
autogroup_def_t **agdp,
*agd_next = NULL;
ObjectClass *oc = NULL;
AttributeDescription *member_url_ad = NULL,
*member_ad = NULL;
const char *text;
oc = oc_find( c->argv[ 1 ] );
if( oc == NULL ){
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
"unable to find ObjectClass \"%s\"",
c->argv[ 1 ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
return 1;
}
rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
if( rc != LDAP_SUCCESS ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
"unable to find AttributeDescription \"%s\"",
c->argv[ 2 ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
return 1;
}
if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
"AttributeDescription \"%s\" ",
"must be of a subtype \"labeledURI\"",
c->argv[ 2 ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
return 1;
}
rc = slap_str2ad( c->argv[3], &member_ad, &text );
if( rc != LDAP_SUCCESS ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
"unable to find AttributeDescription \"%s\"",
c->argv[ 3 ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
return 1;
}
for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
"URL attributeDescription \"%s\" already mapped",
member_ad->ad_cname.bv_val );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
}
}
if ( c->valx > 0 ) {
int i;
for ( i = 0, agdp = &agi->agi_def ;
i < c->valx; i++ )
{
if ( *agdp == NULL ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
"invalid index {%d}",
c->valx );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
return 1;
}
agdp = &(*agdp)->agd_next;
}
agd_next = *agdp;
} else {
for ( agdp = &agi->agi_def; *agdp;
agdp = &(*agdp)->agd_next )
;
}
*agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
(*agdp)->agd_oc = oc;
(*agdp)->agd_member_url_ad = member_url_ad;
(*agdp)->agd_member_ad = member_ad;
(*agdp)->agd_next = agd_next;
} break;
case AG_MEMBER_OF_AD: {
AttributeDescription *memberof_ad = NULL;
const char *text;
rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text );
if( rc != LDAP_SUCCESS ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"\"autogroup-memberof-ad <memberof-ad>\": "
"unable to find AttributeDescription \"%s\"",
c->argv[ 1 ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
return 1;
}
if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX )
&& !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) )
{
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"memberof attribute=\"%s\" must either "
"have DN (%s) or nameUID (%s) syntax",
c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
c->log, c->cr_msg, 0 );
return 1;
}
agi->agi_memberof_ad = memberof_ad;
} break;
default:
rc = 1;
break;
}
return rc;
}
extern int slapMode;
static int
autogroup_db_open(
BackendDB *be,
ConfigReply *cr )
{
slap_overinst *on = (slap_overinst *) be->bd_info;
autogroup_info_t *agi = on->on_bi.bi_private;
autogroup_def_t *agd;
autogroup_sc_t ags;
Operation *op;
slap_callback cb = { 0 };
void *thrctx = ldap_pvt_thread_pool_context();
Connection conn = { 0 };
OperationBuffer opbuf;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
return 0;
}
connection_fake_init( &conn, &opbuf, thrctx );
op = &opbuf.ob_op;
op->ors_attrsonly = 0;
op->o_tag = LDAP_REQ_SEARCH;
op->o_dn = be->be_rootdn;
op->o_ndn = be->be_rootndn;
op->o_req_dn = be->be_suffix[0];
op->o_req_ndn = be->be_nsuffix[0];
op->ors_scope = LDAP_SCOPE_SUBTREE;
op->ors_deref = LDAP_DEREF_NEVER;
op->ors_limit = NULL;
op->ors_tlimit = SLAP_NO_LIMIT;
op->ors_slimit = SLAP_NO_LIMIT;
op->ors_attrs = slap_anlist_no_attrs;
op->o_bd = be;
op->o_bd->bd_info = (BackendInfo *)on->on_info;
ags.ags_info = agi;
cb.sc_private = &ags;
cb.sc_response = autogroup_group_add_cb;
cb.sc_cleanup = NULL;
cb.sc_next = NULL;
op->o_callback = &cb;
for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
SlapReply rs = { REP_RESULT };
autogroup_build_def_filter(agd, op);
ags.ags_def = agd;
op->o_bd->be_search( op, &rs );
filter_free_x( op, op->ors_filter, 1 );
op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
}
if( ! agi->agi_memberof_ad ){
int rc;
const char *text = NULL;
rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "autogroup_db_open: "
"unable to find attribute=\"%s\": %s (%d)\n",
SLAPD_MEMBEROF_ATTR, text, rc );
return rc;
}
}
return 0;
}
static int
autogroup_db_close(
BackendDB *be,
ConfigReply *cr )
{
slap_overinst *on = (slap_overinst *) be->bd_info;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
if ( on->on_bi.bi_private ) {
autogroup_info_t *agi = on->on_bi.bi_private;
autogroup_entry_t *age = agi->agi_entry,
*age_next;
autogroup_filter_t *agf, *agf_next;
for ( age_next = age; age_next; age = age_next ) {
age_next = age->age_next;
ch_free( age->age_dn.bv_val );
ch_free( age->age_ndn.bv_val );
agf = age->age_filter;
for ( agf_next = agf; agf_next; agf = agf_next ) {
agf_next = agf->agf_next;
filter_free( agf->agf_filter );
ch_free( agf->agf_filterstr.bv_val );
ch_free( agf->agf_dn.bv_val );
ch_free( agf->agf_ndn.bv_val );
anlist_free( agf->agf_anlist, 1, NULL );
ch_free( agf );
}
ldap_pvt_thread_mutex_destroy( &age->age_mutex );
ch_free( age );
}
}
return 0;
}
static int
autogroup_db_destroy(
BackendDB *be,
ConfigReply *cr )
{
slap_overinst *on = (slap_overinst *) be->bd_info;
Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
if ( on->on_bi.bi_private ) {
autogroup_info_t *agi = on->on_bi.bi_private;
autogroup_def_t *agd = agi->agi_def,
*agd_next;
for ( agd_next = agd; agd_next; agd = agd_next ) {
agd_next = agd->agd_next;
ch_free( agd );
}
ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
ch_free( agi );
}
return 0;
}
static slap_overinst autogroup = { { NULL } };
static
int
autogroup_initialize(void)
{
int rc = 0;
autogroup.on_bi.bi_type = "autogroup";
autogroup.on_bi.bi_db_open = autogroup_db_open;
autogroup.on_bi.bi_db_close = autogroup_db_close;
autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
autogroup.on_bi.bi_op_add = autogroup_add_entry;
autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
autogroup.on_response = autogroup_response;
autogroup.on_bi.bi_cf_ocs = agocs;
rc = config_register_schema( agcfg, agocs );
if ( rc ) {
return rc;
}
return overlay_register( &autogroup );
}
int
init_module( int argc, char *argv[] )
{
return autogroup_initialize();
}