Commit 9f054b64 authored by Howard Chu's avatar Howard Chu
Browse files

Support dynamic add/delete of attributeTypes and objectClasses

parent 8e928dbb
......@@ -110,9 +110,13 @@ at_bvfind( struct berval *name )
air = avl_find( attr_index, name, attr_index_name_cmp );
if ( air && ( slapMode & SLAP_TOOL_MODE ) && at_oc_cache ) {
avl_insert( &attr_cache, (caddr_t) air,
attr_index_cmp, avl_dup_error );
if ( air ) {
if ( air->air_at->sat_flags & SLAP_AT_DELETED ) {
air = NULL;
} else if (( slapMode & SLAP_TOOL_MODE ) && at_oc_cache ) {
avl_insert( &attr_cache, (caddr_t) air,
attr_index_cmp, avl_dup_error );
}
}
return air != NULL ? air->air_at : NULL;
......@@ -204,46 +208,96 @@ at_find_in_list(
return -1;
}
void
at_destroy( void )
static void
at_delete_names( AttributeType *at )
{
AttributeType *a;
avl_free(attr_index, ldap_memfree);
char **names = at->sat_names;
while (*names) {
struct aindexrec tmpair, *air;
ber_str2bv( *names, 0, 0, &tmpair.air_name );
tmpair.air_at = at;
air = (struct aindexrec *)avl_delete( &attr_index,
(caddr_t)&tmpair, attr_index_cmp );
assert( air != NULL );
ldap_memfree( air );
names++;
}
}
while( !LDAP_STAILQ_EMPTY(&attr_list) ) {
a = LDAP_STAILQ_FIRST(&attr_list);
LDAP_STAILQ_REMOVE_HEAD(&attr_list, sat_next);
/* Mark the attribute as deleted, remove from list, and remove all its
* names from the AVL tree. Leave the OID in the tree.
*/
int
at_delete( AttributeType *at )
{
at->sat_flags |= SLAP_AT_DELETED;
if ( a->sat_equality ) {
MatchingRule *mr;
LDAP_STAILQ_REMOVE(&attr_list,at,slap_attribute_type,sat_next);
mr = mr_find( a->sat_equality->smr_oid );
assert( mr != NULL );
if ( mr != a->sat_equality ) {
ch_free( a->sat_equality );
a->sat_equality = NULL;
}
at_delete_names( at );
return 0;
}
static void
at_clean( AttributeType *a )
{
if ( a->sat_equality ) {
MatchingRule *mr;
mr = mr_find( a->sat_equality->smr_oid );
assert( mr != NULL );
if ( mr != a->sat_equality ) {
ch_free( a->sat_equality );
a->sat_equality = NULL;
}
}
assert( a->sat_syntax != NULL );
if ( a->sat_syntax != NULL ) {
Syntax *syn;
assert( a->sat_syntax != NULL );
if ( a->sat_syntax != NULL ) {
Syntax *syn;
syn = syn_find( a->sat_syntax->ssyn_oid );
assert( syn != NULL );
if ( syn != a->sat_syntax ) {
ch_free( a->sat_syntax );
a->sat_syntax = NULL;
}
syn = syn_find( a->sat_syntax->ssyn_oid );
assert( syn != NULL );
if ( syn != a->sat_syntax ) {
ch_free( a->sat_syntax );
a->sat_syntax = NULL;
}
}
if ( a->sat_oidmacro ) ldap_memfree( a->sat_oidmacro );
if ( a->sat_subtypes ) ldap_memfree( a->sat_subtypes );
}
static void
at_destroy_one( void *v )
{
struct aindexrec *air = v;
AttributeType *a = air->air_at;
at_clean( a );
ad_destroy(a->sat_ad);
ldap_pvt_thread_mutex_destroy(&a->sat_ad_mutex);
ldap_attributetype_free((LDAPAttributeType *)a);
ldap_memfree(air);
}
if ( a->sat_oidmacro ) ldap_memfree( a->sat_oidmacro );
if ( a->sat_subtypes ) ldap_memfree( a->sat_subtypes );
ad_destroy(a->sat_ad);
ldap_pvt_thread_mutex_destroy(&a->sat_ad_mutex);
ldap_attributetype_free((LDAPAttributeType *)a);
void
at_destroy( void )
{
AttributeType *a;
while( !LDAP_STAILQ_EMPTY(&attr_list) ) {
a = LDAP_STAILQ_FIRST(&attr_list);
LDAP_STAILQ_REMOVE_HEAD(&attr_list, sat_next);
at_delete_names( a );
}
avl_free(attr_index, at_destroy_one);
if ( slap_schema.si_at_undefined ) {
ad_destroy(slap_schema.si_at_undefined->sat_ad);
}
......@@ -338,36 +392,72 @@ at_check_dup(
return SLAP_SCHERR_ATTR_DUP;
}
static struct aindexrec *air_old;
static int
at_dup_error( void *left, void *right )
{
air_old = left;
return -1;
}
static int
at_insert(
AttributeType *sat,
AttributeType **rat,
AttributeType *prev,
const char **err )
{
struct aindexrec *air;
char **names = NULL;
AttributeType *sat = *rat;
if ( sat->sat_oid ) {
air = (struct aindexrec *)
ch_calloc( 1, sizeof(struct aindexrec) );
ber_str2bv( sat->sat_oid, 0, 0, &air->air_name );
air->air_at = sat;
air_old = NULL;
if ( avl_insert( &attr_index, (caddr_t) air,
attr_index_cmp, avl_dup_error ) )
attr_index_cmp, at_dup_error ) )
{
AttributeType *old_sat;
int rc;
*err = sat->sat_oid;
old_sat = at_bvfind( &air->air_name );
assert( old_sat != NULL );
rc = at_check_dup( old_sat, sat );
assert( air_old != NULL );
old_sat = air_old->air_at;
/* replacing a deleted definition? */
if ( old_sat->sat_flags & SLAP_AT_DELETED ) {
AttributeType tmp;
/* Keep old oid, free new oid;
* Keep old ads, free new ads;
* Keep new everything else, free old
*/
tmp = *old_sat;
*old_sat = *sat;
old_sat->sat_oid = tmp.sat_oid;
tmp.sat_oid = sat->sat_oid;
old_sat->sat_ad = tmp.sat_ad;
tmp.sat_ad = sat->sat_ad;
*sat = tmp;
at_clean( sat );
at_destroy_one( air );
air = air_old;
sat = old_sat;
*rat = sat;
} else {
ldap_memfree( air );
ldap_memfree( air );
rc = at_check_dup( old_sat, sat );
return rc;
return rc;
}
}
/* FIX: temporal consistency check */
at_bvfind( &air->air_name );
......@@ -437,7 +527,11 @@ at_insert(
}
}
LDAP_STAILQ_INSERT_TAIL( &attr_list, sat, sat_next );
if ( prev ) {
LDAP_STAILQ_INSERT_AFTER( &attr_list, prev, sat, sat_next );
} else {
LDAP_STAILQ_INSERT_TAIL( &attr_list, sat, sat_next );
}
return 0;
}
......@@ -447,6 +541,7 @@ at_add(
LDAPAttributeType *at,
int user,
AttributeType **rsat,
AttributeType *prev,
const char **err )
{
AttributeType *sat = NULL;
......@@ -769,7 +864,7 @@ at_add(
sat->sat_substr = mr;
}
code = at_insert( sat, err );
code = at_insert( &sat, prev, err );
if ( code != 0 ) {
error_return:;
if ( sat ) {
......@@ -909,7 +1004,7 @@ register_at( char *def, AttributeDescription **rad, int dupok )
return code;
}
code = at_add( at, 0, NULL, &err );
code = at_add( at, 0, NULL, NULL, &err );
if ( code ) {
if ( code == SLAP_SCHERR_ATTR_DUP && dupok ) {
freeit = 1;
......
......@@ -259,7 +259,7 @@ static ConfigTable config_back_cf_table[] = {
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "attribute", "attribute", 2, 0, STRLENOF( "attribute" ),
ARG_PAREN|ARG_MAGIC|CFG_ATTR|ARG_NO_DELETE|ARG_NO_INSERT,
ARG_PAREN|ARG_MAGIC|CFG_ATTR,
&config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' "
"DESC 'OpenLDAP attributeTypes' "
"EQUALITY caseIgnoreMatch "
......@@ -387,7 +387,7 @@ static ConfigTable config_back_cf_table[] = {
ARG_MAGIC|CFG_MONITORING|ARG_DB|ARG_ON_OFF, &config_generic,
"( OLcfgDbAt:0.18 NAME 'olcMonitoring' "
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
{ "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC|ARG_NO_DELETE|ARG_NO_INSERT,
{ "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC,
&config_generic, "( OLcfgGlAt:32 NAME 'olcObjectClasses' "
"DESC 'OpenLDAP object classes' "
"EQUALITY caseIgnoreMatch "
......@@ -1108,6 +1108,49 @@ config_generic(ConfigArgs *c) {
}
break;
case CFG_OC: {
CfEntryInfo *ce = c->ca_entry->e_private;
/* can't modify the hardcoded schema */
if ( ce->ce_parent->ce_type == Cft_Global )
return 1;
}
break;
case CFG_ATTR: {
CfEntryInfo *ce = c->ca_entry->e_private;
/* can't modify the hardcoded schema */
if ( ce->ce_parent->ce_type == Cft_Global )
return 1;
}
cfn = c->private;
if ( c->valx < 0 ) {
AttributeType *at;
for( at = cfn->c_at_head; at; at_next( &at )) {
at_delete( at );
if ( at == cfn->c_at_tail )
break;
}
cfn->c_at_head = cfn->c_at_tail = NULL;
} else {
AttributeType *at, *prev = NULL;
int i;
for ( i=0, at=cfn->c_at_head; i<c->valx; i++) {
prev = at;
at_next( &at );
}
at_delete( at );
if ( cfn->c_at_tail == at ) {
cfn->c_at_tail = prev;
}
if ( cfn->c_at_head == at ) {
at_next( &at );
cfn->c_at_head = at;
}
}
break;
case CFG_LIMITS:
/* FIXME: there is no limits_free function */
case CFG_ATOPT:
......@@ -1116,9 +1159,7 @@ config_generic(ConfigArgs *c) {
/* FIXME: there is no way to remove attributes added by
a DSE file */
case CFG_OID:
case CFG_OC:
case CFG_DIT:
case CFG_ATTR:
case CFG_MODPATH:
default:
rc = 1;
......@@ -1243,6 +1284,8 @@ config_generic(ConfigArgs *c) {
case CFG_OID: {
OidMacro *om;
if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private )
cfn = c->private;
if(parse_oidm(c->fname, c->lineno, c->argc, c->argv, 1, &om))
return(1);
if (!cfn->c_om_head) cfn->c_om_head = om;
......@@ -1251,32 +1294,80 @@ config_generic(ConfigArgs *c) {
break;
case CFG_OC: {
ObjectClass *oc;
ObjectClass *oc, *prev;
if(parse_oc(c->fname, c->lineno, p, c->argv, &oc)) return(1);
if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private )
cfn = c->private;
if ( c->valx < 0 ) {
prev = cfn->c_oc_tail;
} else {
prev = NULL;
/* If adding anything after the first, prev is easy */
if ( c->valx ) {
int i;
for (i=0, oc = cfn->c_oc_head; i<c->valx; i++) {
prev = oc;
oc_next( &oc );
}
} else
/* If adding the first, and head exists, find its prev */
if (cfn->c_oc_head) {
for ( oc_start( &oc ); oc != cfn->c_oc_head; ) {
prev = oc;
oc_next( &oc );
}
}
/* else prev is NULL, append to end of global list */
}
if(parse_oc(c->fname, c->lineno, p, c->argv, &oc, prev)) return(1);
if (!cfn->c_oc_head) cfn->c_oc_head = oc;
cfn->c_oc_tail = oc;
if (cfn->c_oc_tail == prev) cfn->c_oc_tail = oc;
}
break;
case CFG_ATTR: {
AttributeType *at, *prev;
if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private )
cfn = c->private;
if ( c->valx < 0 ) {
prev = cfn->c_at_tail;
} else {
prev = NULL;
/* If adding anything after the first, prev is easy */
if ( c->valx ) {
int i;
for (i=0, at = cfn->c_at_head; i<c->valx; i++) {
prev = at;
at_next( &at );
}
} else
/* If adding the first, and head exists, find its prev */
if (cfn->c_at_head) {
for ( at_start( &at ); at != cfn->c_at_head; ) {
prev = at;
at_next( &at );
}
}
/* else prev is NULL, append to end of global list */
}
if(parse_at(c->fname, c->lineno, p, c->argv, &at, prev)) return(1);
if (!cfn->c_at_head) cfn->c_at_head = at;
if (cfn->c_at_tail == prev) cfn->c_at_tail = at;
}
break;
case CFG_DIT: {
ContentRule *cr;
if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private )
cfn = c->private;
if(parse_cr(c->fname, c->lineno, p, c->argv, &cr)) return(1);
if (!cfn->c_cr_head) cfn->c_cr_head = cr;
cfn->c_cr_tail = cr;
}
break;
case CFG_ATTR: {
AttributeType *at;
if(parse_at(c->fname, c->lineno, p, c->argv, &at)) return(1);
if (!cfn->c_at_head) cfn->c_at_head = at;
cfn->c_at_tail = at;
}
break;
case CFG_ATOPT:
ad_define_option(NULL, NULL, 0);
for(i = 1; i < c->argc; i++)
......@@ -1388,6 +1479,8 @@ config_generic(ConfigArgs *c) {
{
struct berval bv;
ber_str2bv( c->argv[1], 0, 1, &bv );
if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private )
cfn = c->private;
ber_bvarray_add( &cfn->c_dseFiles, &bv );
}
break;
......@@ -3416,7 +3509,7 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
AttributeDescription *ad;
BerVarray vals;
int i, rc = 0, sort = 0;
int i, rc = 0;
if ( isAttr ) {
a = ptr;
......@@ -3429,7 +3522,6 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
}
if ( a && ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )) {
sort = 1;
rc = ordered_value_sort( a, 1 );
if ( rc ) {
snprintf(ca->msg, sizeof( ca->msg ), "ordered_value_sort failed on attr %s\n",
......@@ -3439,7 +3531,7 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
}
for ( i=0; vals[i].bv_val; i++ ) {
ca->line = vals[i].bv_val;
if ( sort ) {
if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) {
char *idx = strchr( ca->line, '}' );
if ( idx ) ca->line = idx+1;
}
......@@ -4169,8 +4261,9 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
if ( rc ) rc = LDAP_OTHER;
}
if ( ml->sml_values ) {
d = d->next;
ch_free( dels );
dels = d->next;
dels = d;
}
if ( ml->sml_op == LDAP_MOD_REPLACE ) {
ml->sml_values = vals;
......
......@@ -386,23 +386,73 @@ oc_add_sups(
return 0;
}
static void
oc_delete_names( ObjectClass *oc )
{
char **names = oc->soc_names;
while (*names) {
struct oindexrec tmpoir, *oir;
ber_str2bv( *names, 0, 0, &tmpoir.oir_name );
tmpoir.oir_oc = oc;
oir = (struct oindexrec *)avl_delete( &oc_index,
(caddr_t)&tmpoir, oc_index_cmp );
assert( oir != NULL );
ldap_memfree( oir );
names++;
}
}
/* Mark the ObjectClass as deleted, remove from list, and remove all its
* names from the AVL tree. Leave the OID in the tree.
*/
int
oc_delete( ObjectClass *oc )
{
oc->soc_flags |= SLAP_OC_DELETED;
LDAP_STAILQ_REMOVE(&oc_list,oc,slap_object_class,soc_next);
oc_delete_names( oc );
return 0;
}
static void
oc_clean( ObjectClass *o )
{
if (o->soc_sups) ldap_memfree(o->soc_sups);
if (o->soc_required) ldap_memfree(o->soc_required);
if (o->soc_allowed) ldap_memfree(o->soc_allowed);
if (o->soc_oidmacro) ldap_memfree(o->soc_oidmacro);
}
static void
oc_destroy_one( void *v )
{
struct oindexrec *oir = v;
ObjectClass *o = oir->oir_oc;
oc_clean( o );
ldap_objectclass_free((LDAPObjectClass *)o);
ldap_memfree(oir);
}
void
oc_destroy( void )
{
ObjectClass *o;
avl_free(oc_index, ldap_memfree);
while( !LDAP_STAILQ_EMPTY(&oc_list) ) {
o = LDAP_STAILQ_FIRST(&oc_list);
LDAP_STAILQ_REMOVE_HEAD(&oc_list, soc_next);
if (o->soc_sups) ldap_memfree(o->soc_sups);
if (o->soc_required) ldap_memfree(o->soc_required);
if (o->soc_allowed) ldap_memfree(o->soc_allowed);
if (o->soc_oidmacro) ldap_memfree(o->soc_oidmacro);
ldap_objectclass_free((LDAPObjectClass *)o);
oc_delete_names( o );
}
avl_free( oc_index, oc_destroy_one );
while( !LDAP_STAILQ_EMPTY(&oc_undef_list) ) {
o = LDAP_STAILQ_FIRST(&oc_undef_list);
LDAP_STAILQ_REMOVE_HEAD(&oc_undef_list, soc_next);
......@@ -411,6 +461,40 @@ oc_destroy( void )
}
}
int
oc_start( ObjectClass **oc )
{
assert( oc != NULL );
*oc = LDAP_STAILQ_FIRST(&oc_list);
return (*oc != NULL);
}
int
oc_next( ObjectClass **oc )
{
assert( oc != NULL );
#if 1 /* pedantic check */
{
ObjectClass *tmp = NULL;
LDAP_STAILQ_FOREACH(tmp,&oc_list,soc_next) {
if ( tmp == *oc ) {
break;
}
}
assert( tmp != NULL );
}
#endif
*oc = LDAP_STAILQ_NEXT(*oc,soc_next);
return (*oc != NULL);
}
/*
* check whether the two ObjectClasses actually __are__ identical,
* or rather inconsistent
......@@ -462,38 +546,68 @@ oc_check_dup(
return SLAP_SCHERR_CLASS_DUP;
}
static struct oindexrec *oir_old;
static int
oc_dup_error( void *left, void *right )
{
oir_old = left;
return -1;
}
static int
oc_insert(
ObjectClass *soc,
ObjectClass **roc,
ObjectClass *prev,
const char **err )
{
struct oindexrec *oir;
char **names;
ObjectClass *soc = *roc;
if ( soc->soc_oid ) {
oir = (struct oindexrec *)
ch_calloc( 1, sizeof(struct oindexrec) );
oir->oir_name.bv_val = soc->soc_oid;
oir->oir_name.bv_len = strlen( soc->soc_oid );
ber_str2bv( soc->soc_oid, 0, 0, &oir->oir_name );
oir->oir_oc = soc;
assert( oir->oir_name.bv_val != NULL );