From 6020a6d81d1f5decdb244e2bb082978272c0c4a7 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 24 Dec 2006 00:56:37 +0000 Subject: [PATCH] ITS#4337 implement modrdn for back-config --- servers/slapd/back-relay/config.c | 2 +- servers/slapd/backend.c | 55 ++- servers/slapd/backglue.c | 2 +- servers/slapd/backover.c | 95 ++++- servers/slapd/bconfig.c | 544 +++++++++++++++++++++------ servers/slapd/modrdn.c | 1 + servers/slapd/overlays/pcache.c | 2 +- servers/slapd/overlays/translucent.c | 2 +- servers/slapd/proto-slap.h | 11 +- servers/slapd/slapi/slapi_overlay.c | 2 +- 10 files changed, 590 insertions(+), 126 deletions(-) diff --git a/servers/slapd/back-relay/config.c b/servers/slapd/back-relay/config.c index b8f8583011..b11e37118c 100644 --- a/servers/slapd/back-relay/config.c +++ b/servers/slapd/back-relay/config.c @@ -114,7 +114,7 @@ relay_back_db_config( * where the overlay is instantiated by moving * around the "relay" directive, although this could * make slapd.conf a bit confusing. */ - if ( overlay_config( be, "rwm" ) ) { + if ( overlay_config( be, "rwm", -1, NULL ) ) { Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "%s: line %d: unable to install " "rwm overlay " diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 24294b14e3..3233f65e8f 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -530,13 +530,48 @@ BackendInfo* backend_info(const char *type) return NULL; } +void +backend_db_insert( + BackendDB *be, + int idx +) +{ + /* If idx < 0, just add to end of list */ + if ( idx < 0 ) { + LDAP_STAILQ_INSERT_TAIL(&backendDB, be, be_next); + } else if ( idx == 0 ) { + LDAP_STAILQ_INSERT_HEAD(&backendDB, be, be_next); + } else { + int i; + BackendDB *b2; + + b2 = LDAP_STAILQ_FIRST(&backendDB); + idx--; + for (i=0; i= nbackends ) + idx = -1; nbackends++; - LDAP_STAILQ_INSERT_TAIL(&backendDB, be, be_next); + backend_db_insert( be, idx ); } be->bd_info = bi; @@ -574,11 +612,16 @@ backend_db_init( if ( rc != 0 ) { fprintf( stderr, "database init failed (%s)\n", type ); - nbackends--; - return NULL; + /* If we created and linked this be, remove it and free it */ + if ( !b0 ) { + LDAP_STAILQ_REMOVE(&backendDB, be, slap_backend_db, be_next); + ch_free( be ); + be = NULL; + nbackends--; + } + } else { + bi->bi_nDB++; } - - bi->bi_nDB++; return( be ); } diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c index d9bee99bd8..6d516d3e5a 100644 --- a/servers/slapd/backglue.c +++ b/servers/slapd/backglue.c @@ -956,7 +956,7 @@ glue_sub_attach() /* If it's not already configured, set up the overlay */ if ( !SLAP_GLUE_INSTANCE( be )) { - rc = overlay_config( be, glue.on_bi.bi_type ); + rc = overlay_config( be, glue.on_bi.bi_type, -1, NULL ); if ( rc ) break; } diff --git a/servers/slapd/backover.c b/servers/slapd/backover.c index 95673a88bc..9a7b4df761 100644 --- a/servers/slapd/backover.c +++ b/servers/slapd/backover.c @@ -942,14 +942,77 @@ overlay_destroy_one( BackendDB *be, slap_overinst *on ) } } +void +overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev, + int idx ) +{ + slap_overinfo *oi = (slap_overinfo *)be->bd_info; + + if ( idx == -1 ) { + on2->on_next = oi->oi_list; + oi->oi_list = on2; + } else { + int i; + slap_overinst *on, *otmp1 = NULL, *otmp2; + + /* Since the list is in reverse order and is singly linked, + * we reverse it to find the idx insertion point. Adding + * on overlay at a specific point should be a pretty + * infrequent occurrence. + */ + for ( on = oi->oi_list; on; on=otmp2 ) { + otmp2 = on->on_next; + on->on_next = otmp1; + otmp1 = on; + } + oi->oi_list = NULL; + /* advance to insertion point */ + for ( i=0, on = otmp1; ion_next; + on->on_next = oi->oi_list; + oi->oi_list = on; + } + /* insert */ + on2->on_next = oi->oi_list; + oi->oi_list = on2; + if ( otmp1 ) { + *prev = &otmp1->on_next; + /* replace remainder of list */ + for ( on=otmp1; on; on=otmp1 ) { + otmp1 = on->on_next; + on->on_next = oi->oi_list; + oi->oi_list = on; + } + } + } +} + +void +overlay_move( BackendDB *be, slap_overinst *on, int idx ) +{ + slap_overinfo *oi = (slap_overinfo *)be->bd_info; + slap_overinst **onp; + + for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) { + if ( *onp == on ) { + *onp = on->on_next; + break; + } + } + overlay_insert( be, on, &onp, idx ); +} + /* add an overlay to a particular backend. */ int -overlay_config( BackendDB *be, const char *ov ) +overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res ) { - slap_overinst *on = NULL, *on2 = NULL; + slap_overinst *on = NULL, *on2 = NULL, **prev; slap_overinfo *oi = NULL; BackendInfo *bi = NULL; + if ( res ) + *res = NULL; + on = overlay_find( ov ); if ( !on ) { Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 ); @@ -1049,28 +1112,44 @@ overlay_config( BackendDB *be, const char *ov ) oi = be->bd_info->bi_private; } - /* Insert new overlay on head of list. Overlays are executed - * in reverse of config order... + /* Insert new overlay into list. By default overlays are + * added to head of list and executed in LIFO order. */ on2 = ch_calloc( 1, sizeof(slap_overinst) ); *on2 = *on; on2->on_info = oi; - on2->on_next = oi->oi_list; - oi->oi_list = on2; + + prev = &oi->oi_list; + /* Do we need to find the insertion point? */ + if ( idx >= 0 ) { + int i; + + /* count current overlays */ + for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ ); + + /* are we just appending a new one? */ + if ( idx >= i ) + idx = -1; + } + overlay_insert( be, on2, &prev, idx ); /* Any initialization needed? */ - if ( on->on_bi.bi_db_init ) { + if ( on2->on_bi.bi_db_init ) { int rc; be->bd_info = (BackendInfo *)on2; rc = on2->on_bi.bi_db_init( be ); be->bd_info = (BackendInfo *)oi; if ( rc ) { - oi->oi_list = on2->on_next; + *prev = on2->on_next; ch_free( on2 ); + on2 = NULL; return rc; } } + if ( res ) + *res = &on2->on_bi; + return 0; } diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 6efd2d2df6..a51dd04f2a 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -1228,7 +1228,7 @@ config_generic(ConfigArgs *c) { } else if ( !strcasecmp( c->argv[1], "frontend" )) { c->be = frontendDB; } else { - c->be = backend_db_init(c->argv[1], NULL); + c->be = backend_db_init(c->argv[1], NULL, c->valx); if ( !c->be ) { snprintf( c->msg, sizeof( c->msg ), "<%s> failed init", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", @@ -1934,26 +1934,21 @@ config_timelimit(ConfigArgs *c) { static int config_overlay(ConfigArgs *c) { - slap_overinfo *oi; if (c->op == SLAP_CONFIG_EMIT) { return 1; } else if ( c->op == LDAP_MOD_DELETE ) { assert(0); } - if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1])) { + if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1], + c->valx, &c->bi)) { /* log error */ Debug( LDAP_DEBUG_ANY, "%s: (optional) %s overlay \"%s\" configuration failed.\n", c->log, c->be == frontendDB ? "global " : "", &c->argv[1][1]); return 1; - } else if(overlay_config(c->be, c->argv[1])) { + } else if(overlay_config(c->be, c->argv[1], c->valx, &c->bi)) { return(1); } - /* Setup context for subsequent config directives. - * The newly added overlay is at the head of the list. - */ - oi = (slap_overinfo *)c->be->bd_info; - c->bi = &oi->oi_list->on_bi; return(0); } @@ -3218,8 +3213,11 @@ config_ldif_resp( Operation *op, SlapReply *rs ) sc->cfb->cb_root, sc->ca, &rdn, &CFOC_DATABASE, sc->ca->be->be_cf_ocs ); op->o_noop = i; + sc->got_frontend++; + } else { + sc->got_frontend++; + goto ok; } - sc->got_frontend++; } } /* Does the configDB exist? */ @@ -3246,6 +3244,7 @@ config_ldif_resp( Operation *op, SlapReply *rs ) sc->got_config++; } +ok: rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL, NULL ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "config error processing %s: %s\n", @@ -3285,7 +3284,7 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) { if ( !cfb->cb_db.bd_info ) return 0; /* FIXME: eventually this will be a fatal error */ - if ( backend_db_init( "ldif", &cfb->cb_db ) == NULL ) + if ( backend_db_init( "ldif", &cfb->cb_db, -1 ) == NULL ) return 1; cfb->cb_db.be_suffix = be->be_suffix; @@ -3421,7 +3420,7 @@ read_config(const char *fname, const char *dir) { int rc; /* Setup the config backend */ - be = backend_db_init( "config", NULL ); + be = backend_db_init( "config", NULL, 0 ); if ( !be ) return 1; @@ -3654,12 +3653,177 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr ) return rc; } +static int +config_rename_attr( SlapReply *rs, Entry *e, struct berval *rdn, + Attribute **at ) +{ + struct berval rtype, rval; + Attribute *a; + AttributeDescription *ad = NULL; + + dnRdn( &e->e_name, rdn ); + rval.bv_val = strchr(rdn->bv_val, '=' ) + 1; + rval.bv_len = rdn->bv_len - (rval.bv_val - rdn->bv_val); + rtype.bv_val = rdn->bv_val; + rtype.bv_len = rval.bv_val - rtype.bv_val - 1; + + /* Find attr */ + slap_bv2ad( &rtype, &ad, &rs->sr_text ); + a = attr_find( e->e_attrs, ad ); + if (!a ) return LDAP_NAMING_VIOLATION; + *at = a; + + return 0; +} + +static void +config_rename_kids( CfEntryInfo *ce ) +{ + CfEntryInfo *ce2; + struct berval rdn, nrdn; + + for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) { + dnRdn ( &ce2->ce_entry->e_name, &rdn ); + dnRdn ( &ce2->ce_entry->e_nname, &nrdn ); + free( ce2->ce_entry->e_name.bv_val ); + free( ce2->ce_entry->e_nname.bv_val ); + build_new_dn( &ce2->ce_entry->e_name, &ce->ce_entry->e_name, + &rdn, NULL ); + build_new_dn( &ce2->ce_entry->e_nname, &ce->ce_entry->e_nname, + &nrdn, NULL ); + config_rename_kids( ce2 ); + } +} + +static int +config_rename_one( Operation *op, SlapReply *rs, Entry *e, + CfEntryInfo *parent, Attribute *a, struct berval *newrdn, + struct berval *nnewrdn, int use_ldif ) +{ + char *ptr1; + int rc = 0; + struct berval odn, ondn; + + odn = e->e_name; + ondn = e->e_nname; + build_new_dn( &e->e_name, &parent->ce_entry->e_name, newrdn, NULL ); + build_new_dn( &e->e_nname, &parent->ce_entry->e_nname, nnewrdn, NULL ); + + /* Replace attr */ + free( a->a_vals[0].bv_val ); + ptr1 = strchr( newrdn->bv_val, '=' ) + 1; + a->a_vals[0].bv_len = newrdn->bv_len - (ptr1 - newrdn->bv_val); + a->a_vals[0].bv_val = ch_malloc( a->a_vals[0].bv_len + 1 ); + strcpy( a->a_vals[0].bv_val, ptr1 ); + + if ( a->a_nvals != a->a_vals ) { + free( a->a_nvals[0].bv_val ); + ptr1 = strchr( nnewrdn->bv_val, '=' ) + 1; + a->a_nvals[0].bv_len = nnewrdn->bv_len - (ptr1 - nnewrdn->bv_val); + a->a_nvals[0].bv_val = ch_malloc( a->a_nvals[0].bv_len + 1 ); + strcpy( a->a_nvals[0].bv_val, ptr1 ); + } + if ( use_ldif ) { + CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private; + BackendDB *be = op->o_bd; + slap_callback sc = { NULL, slap_null_cb, NULL, NULL }; + struct berval dn, ndn, xdn, xndn; + + op->o_bd = &cfb->cb_db; + + /* Save current rootdn; use the underlying DB's rootdn */ + dn = op->o_dn; + ndn = op->o_ndn; + xdn = op->o_req_dn; + xndn = op->o_req_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + op->o_req_dn = odn; + op->o_req_ndn = ondn; + + sc.sc_next = op->o_callback; + op->o_callback = ≻ + op->orr_newrdn = *newrdn; + op->orr_nnewrdn = *nnewrdn; + op->orr_deleteoldrdn = 1; + op->orr_modlist = NULL; + slap_modrdn2mods( op, rs ); + rc = op->o_bd->be_modrdn( op, rs ); + slap_mods_free( op->orr_modlist, 1 ); + + op->o_bd = be; + op->o_callback = sc.sc_next; + op->o_dn = dn; + op->o_ndn = ndn; + op->o_req_dn = xdn; + op->o_req_ndn = xndn; + } + free( odn.bv_val ); + free( ondn.bv_val ); + if ( e->e_private ) + config_rename_kids( e->e_private ); + return rc; +} + +static int +config_renumber_one( Operation *op, SlapReply *rs, CfEntryInfo *parent, + Entry *e, int idx, int tailindex, int use_ldif ) +{ + struct berval ival, newrdn, nnewrdn; + struct berval rdn; + Attribute *a; + char ibuf[32], *ptr1, *ptr2 = NULL; + int rc = 0; + + rc = config_rename_attr( rs, e, &rdn, &a ); + if ( rc ) return rc; + + ival.bv_val = ibuf; + ival.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, idx ); + if ( ival.bv_len >= sizeof( ibuf ) ) { + return LDAP_NAMING_VIOLATION; + } + + newrdn.bv_len = rdn.bv_len + ival.bv_len; + newrdn.bv_val = ch_malloc( newrdn.bv_len+1 ); + + if ( tailindex ) { + ptr1 = lutil_strncopy( newrdn.bv_val, rdn.bv_val, rdn.bv_len ); + ptr1 = lutil_strcopy( ptr1, ival.bv_val ); + } else { + int xlen; + ptr2 = ber_bvchr( &rdn, '}' ); + if ( ptr2 ) { + ptr2++; + } else { + ptr2 = rdn.bv_val + a->a_desc->ad_cname.bv_len + 1; + } + xlen = rdn.bv_len - (ptr2 - rdn.bv_val); + ptr1 = lutil_strncopy( newrdn.bv_val, a->a_desc->ad_cname.bv_val, + a->a_desc->ad_cname.bv_len ); + *ptr1++ = '='; + ptr1 = lutil_strcopy( ptr1, ival.bv_val ); + ptr1 = lutil_strncopy( ptr1, ptr2, xlen ); + *ptr1 = '\0'; + } + + /* Do the equivalent of ModRDN */ + /* Replace DN / NDN */ + newrdn.bv_len = ptr1 - newrdn.bv_val; + rdnNormalize( 0, NULL, NULL, &newrdn, &nnewrdn, NULL ); + rc = config_rename_one( op, rs, e, parent, a, &newrdn, &nnewrdn, use_ldif ); + + free( nnewrdn.bv_val ); + free( newrdn.bv_val ); + return rc; +} + static int check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, - SlapReply *rs, int *renum ) + SlapReply *rs, int *renum, int *ibase ) { CfEntryInfo *ce; - int index = -1, gotindex = 0, nsibs; + int index = -1, gotindex = 0, nsibs, rc = 0; int renumber = 0, tailindex = 0; char *ptr1, *ptr2 = NULL; struct berval rdn; @@ -3710,83 +3874,14 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, renumber = 1; } } + /* just make index = nsibs */ if ( !renumber ) { - struct berval ival, newrdn, nnewrdn; - struct berval rtype, rval; - Attribute *a; - AttributeDescription *ad = NULL; - char ibuf[32]; - const char *text; - - rval.bv_val = strchr(rdn.bv_val, '=' ) + 1; - rval.bv_len = rdn.bv_len - (rval.bv_val - rdn.bv_val); - rtype.bv_val = rdn.bv_val; - rtype.bv_len = rval.bv_val - rtype.bv_val - 1; - - /* Find attr */ - slap_bv2ad( &rtype, &ad, &text ); - a = attr_find( e->e_attrs, ad ); - if (!a ) return LDAP_NAMING_VIOLATION; - - ival.bv_val = ibuf; - ival.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, nsibs ); - if ( ival.bv_len >= sizeof( ibuf ) ) { - return LDAP_NAMING_VIOLATION; - } - - newrdn.bv_len = rdn.bv_len + ival.bv_len; - newrdn.bv_val = ch_malloc( newrdn.bv_len+1 ); - - if ( tailindex ) { - ptr1 = lutil_strncopy( newrdn.bv_val, rdn.bv_val, rdn.bv_len ); - ptr1 = lutil_strcopy( ptr1, ival.bv_val ); - } else { - int xlen; - if ( !gotindex ) { - ptr2 = rval.bv_val; - xlen = rval.bv_len; - } else { - xlen = rdn.bv_len - (ptr2 - rdn.bv_val); - } - ptr1 = lutil_strncopy( newrdn.bv_val, rtype.bv_val, - rtype.bv_len ); - *ptr1++ = '='; - ptr1 = lutil_strcopy( ptr1, ival.bv_val ); - ptr1 = lutil_strncopy( ptr1, ptr2, xlen ); - *ptr1 = '\0'; - } - - /* Do the equivalent of ModRDN */ - /* Replace DN / NDN */ - newrdn.bv_len = ptr1 - newrdn.bv_val; - rdnNormalize( 0, NULL, NULL, &newrdn, &nnewrdn, NULL ); - free( e->e_name.bv_val ); - build_new_dn( &e->e_name, &parent->ce_entry->e_name, - &newrdn, NULL ); - free( e->e_nname.bv_val ); - build_new_dn( &e->e_nname, &parent->ce_entry->e_nname, - &nnewrdn, NULL ); - - /* Replace attr */ - free( a->a_vals[0].bv_val ); - ptr1 = strchr( newrdn.bv_val, '=' ) + 1; - a->a_vals[0].bv_len = newrdn.bv_len - (ptr1 - newrdn.bv_val); - a->a_vals[0].bv_val = ch_malloc( a->a_vals[0].bv_len + 1 ); - strcpy( a->a_vals[0].bv_val, ptr1 ); - - if ( a->a_nvals != a->a_vals ) { - free( a->a_nvals[0].bv_val ); - ptr1 = strchr( nnewrdn.bv_val, '=' ) + 1; - a->a_nvals[0].bv_len = nnewrdn.bv_len - (ptr1 - nnewrdn.bv_val); - a->a_nvals[0].bv_val = ch_malloc( a->a_nvals[0].bv_len + 1 ); - strcpy( a->a_nvals[0].bv_val, ptr1 ); - } - free( nnewrdn.bv_val ); - free( newrdn.bv_val ); + rc = config_renumber_one( NULL, rs, parent, e, index, tailindex, 0 ); } } + if ( ibase ) *ibase = index; if ( renum ) *renum = renumber; - return 0; + return rc; } static ConfigOCs ** @@ -3897,14 +3992,17 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, CfEntryInfo *ce, *last; ConfigOCs **colst; Attribute *a, *oc_at; - int i, nocs, rc = 0; + int i, ibase = -1, nocs, rc = 0; struct berval pdn; ConfigTable *ct; char *ptr; - /* Make sure parent exists and entry does not */ + /* Make sure parent exists and entry does not. But allow + * Databases and Overlays to be inserted. + */ ce = config_find_base( cfb->cb_root, &e->e_nname, &last ); - if ( ce ) + if ( ce && ce->ce_type != Cft_Database && + ce->ce_type != Cft_Overlay ) return LDAP_ALREADY_EXISTS; dnParent( &e->e_nname, &pdn ); @@ -3995,12 +4093,13 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, * but only the other types support auto-renumbering of siblings. */ { - int renumber = renum ? *renum : 0; - rc = check_name_index( last, colst[0]->co_type, e, rs, renum ); + rc = check_name_index( last, colst[0]->co_type, e, rs, renum, + &ibase ); if ( rc ) { goto done; } - if ( renum && *renum && renumber == -1 ) { + if ( renum && *renum && colst[0]->co_type != Cft_Database && + colst[0]->co_type != Cft_Overlay ) { snprintf( ca->msg, sizeof( ca->msg ), "operation requires sibling renumbering" ); rc = LDAP_UNWILLING_TO_PERFORM; @@ -4027,12 +4126,24 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, ct = config_find_table( colst, nocs, a->a_desc ); if ( !ct ) continue; /* user data? */ for (i=0; a->a_vals[i].bv_val; i++) { + char *iptr = NULL; ca->line = a->a_vals[i].bv_val; if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) { ptr = strchr( ca->line, '}' ); - if ( ptr ) ca->line = ptr+1; + if ( ptr ) { + iptr = strchr( ca->line, '{' ); + ca->line = ptr+1; + } + } + if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_SIB ) { + if ( iptr ) { + ca->valx = strtol( iptr+1, NULL, 0 ); + } else { + ca->valx = -1; + } + } else { + ca->valx = i; } - ca->valx = i; rc = config_parse_add( ct, ca, i ); if ( rc ) { rc = LDAP_OTHER; @@ -4063,6 +4174,7 @@ ok: } } + ca->valx = ibase; ce = ch_calloc( 1, sizeof(CfEntryInfo) ); ce->ce_parent = last; ce->ce_entry = entry_dup( e ); @@ -4071,6 +4183,7 @@ ok: ce->ce_be = ca->be; ce->ce_bi = ca->bi; ce->ce_private = ca->private; + ca->ca_entry = ce->ce_entry; if ( !last ) { cfb->cb_root = ce; } else if ( last->ce_kids ) { @@ -4098,6 +4211,76 @@ done: return rc; } +#define BIGTMP 10000 +static int +config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce, + int base, int rebase, int max, int use_ldif ) +{ + CfEntryInfo *ce2, *ce3, *cetmp = NULL, *cerem = NULL; + ConfigType etype = ce->ce_type; + int count = 0, rc = 0; + + /* Reverse ce list */ + for (ce2 = ce->ce_sibs;ce2;ce2 = ce3) { + if (ce2->ce_type != etype) { + cerem = ce2; + break; + } + ce3 = ce2->ce_sibs; + ce2->ce_sibs = cetmp; + cetmp = ce2; + count++; + if ( max && count >= max ) { + cerem = ce3; + break; + } + } + + /* Move original to a temp name until increments are done */ + if ( rebase ) { + ce->ce_entry->e_private = NULL; + rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry, + base+BIGTMP, 0, use_ldif ); + ce->ce_entry->e_private = ce; + } + /* start incrementing */ + for (ce2=cetmp; ce2; ce2=ce3) { + ce3 = ce2->ce_sibs; + ce2->ce_sibs = cerem; + cerem = ce2; + if ( rc == 0 ) + rc = config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry, + count+base, 0, use_ldif ); + count--; + } + if ( rebase ) + rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry, + base, 0, use_ldif ); + return rc; +} + +static int +config_rename_del( Operation *op, SlapReply *rs, CfEntryInfo *ce, + CfEntryInfo *ce2, int old, int use_ldif ) +{ + int count = 0; + + /* Renumber original to a temp value */ + ce->ce_entry->e_private = NULL; + config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry, + old+BIGTMP, 0, use_ldif ); + ce->ce_entry->e_private = ce; + + /* start decrementing */ + for (; ce2 != ce; ce2=ce2->ce_sibs) { + config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry, + count+old, 0, use_ldif ); + count++; + } + return config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry, + count+old, 0, use_ldif ); +} + /* Parse an LDAP entry into config directives, then store in underlying * database. */ @@ -4122,17 +4305,27 @@ config_back_add( Operation *op, SlapReply *rs ) * 1) check for existence of entry * 2) check for sibling renumbering * 3) perform internal add - * 4) store entry in underlying database - * 5) perform any necessary renumbering + * 4) perform any necessary renumbering + * 5) store entry in underlying database */ - /* NOTE: by now we do not accept adds that require renumbering */ - renumber = -1; rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber, op ); if ( rs->sr_err != LDAP_SUCCESS ) { rs->sr_text = ca.msg; goto out2; } + if ( renumber ) { + CfEntryInfo *ce = ca.ca_entry->e_private; + req_add_s addr = op->oq_add; + op->o_tag = LDAP_REQ_MODRDN; + rs->sr_err = config_rename_add( op, rs, ce, ca.valx, 0, 0, cfb->cb_use_ldif ); + op->o_tag = LDAP_REQ_ADD; + op->oq_add = addr; + if ( rs->sr_err != LDAP_SUCCESS ) { + goto out2; + } + } + if ( cfb->cb_use_ldif ) { BackendDB *be = op->o_bd; slap_callback sc = { NULL, slap_null_cb, NULL, NULL }; @@ -4155,10 +4348,6 @@ config_back_add( Operation *op, SlapReply *rs ) op->o_ndn = ndn; } - if ( renumber ) { - /* TODO */ - } - out2:; ldap_pvt_thread_pool_resume( &connection_pool ); @@ -4521,6 +4710,8 @@ config_back_modrdn( Operation *op, SlapReply *rs ) { CfBackInfo *cfb; CfEntryInfo *ce, *last; + struct berval rdn; + int ixold, ixnew; cfb = (CfBackInfo *)op->o_bd->be_private; @@ -4555,10 +4746,153 @@ config_back_modrdn( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_UNWILLING_TO_PERFORM; goto out; } + + /* If newRDN == oldRDN, quietly succeed */ + dnRdn( &op->o_req_ndn, &rdn ); + if ( dn_match( &rdn, &op->orr_nnewrdn )) { + rs->sr_err = LDAP_SUCCESS; + goto out; + } + + /* Current behavior, subject to change as needed: + * + * For backends and overlays, we only allow renumbering. + * For schema, we allow renaming with the same number. + * Otherwise, the op is not allowed. + */ + + if ( ce->ce_type == Cft_Schema ) { + char *ptr1, *ptr2; + int len; + + /* Can't alter the main cn=schema entry */ + if ( ce->ce_parent->ce_type == Cft_Global ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "renaming not allowed for this entry"; + goto out; + } + + /* We could support this later if desired */ + ptr1 = ber_bvchr( &rdn, '}' ); + ptr2 = ber_bvchr( &op->orr_newrdn, '}' ); + len = ptr1 - rdn.bv_val; + if ( len != ptr2 - op->orr_newrdn.bv_val || + strncmp( rdn.bv_val, op->orr_newrdn.bv_val, len )) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "schema reordering not supported"; + goto out; + } + } else if ( ce->ce_type == Cft_Database || + ce->ce_type == Cft_Overlay ) { + char *ptr1, *ptr2, *iptr1, *iptr2; + int len1, len2; + + iptr2 = ber_bvchr( &op->orr_newrdn, '=' ) + 1; + if ( *iptr2 != '{' ) { + rs->sr_err = LDAP_NAMING_VIOLATION; + rs->sr_text = "new ordering index is required"; + goto out; + } + iptr2++; + iptr1 = ber_bvchr( &rdn, '{' ) + 1; + ptr1 = ber_bvchr( &rdn, '}' ); + ptr2 = ber_bvchr( &op->orr_newrdn, '}' ); + if ( !ptr2 ) { + rs->sr_err = LDAP_NAMING_VIOLATION; + rs->sr_text = "new ordering index is required"; + goto out; + } + + len1 = ptr1 - rdn.bv_val; + len2 = ptr2 - op->orr_newrdn.bv_val; + + if ( rdn.bv_len - len1 != op->orr_newrdn.bv_len - len2 || + strncmp( ptr1, ptr2, rdn.bv_len - len1 )) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "changing database/overlay type not allowed"; + goto out; + } + ixold = strtol( iptr1, NULL, 0 ); + ixnew = strtol( iptr2, &ptr1, 0 ); + if ( ptr1 != ptr2 || ixold < 0 || ixnew < 0 ) { + rs->sr_err = LDAP_NAMING_VIOLATION; + goto out; + } + /* config DB is always 0, cannot be changed */ + if ( ce->ce_type == Cft_Database && ( ixold == 0 || ixnew == 0 )) { + rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + goto out; + } + } else { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "renaming not supported for this entry"; + goto out; + } + ldap_pvt_thread_pool_pause( &connection_pool ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "renaming not implemented yet within naming context"; + if ( ce->ce_type == Cft_Schema ) { + struct berval rdn; + Attribute *a; + rs->sr_err = config_rename_attr( rs, ce->ce_entry, &rdn, &a ); + if ( rs->sr_err == LDAP_SUCCESS ) { + rs->sr_err = config_rename_one( op, rs, ce->ce_entry, + ce->ce_parent, a, &op->orr_newrdn, &op->orr_nnewrdn, + cfb->cb_use_ldif ); + } + } else { + CfEntryInfo *ce2, *cebase, **cprev, **cbprev, *ceold; + req_modrdn_s modr = op->oq_modrdn; + int i; + + /* Advance to first of this type */ + cprev = &ce->ce_parent->ce_kids; + for ( ce2 = *cprev; ce2 && ce2->ce_type != ce->ce_type; ) { + cprev = &ce2->ce_sibs; + ce2 = ce2->ce_sibs; + } + /* Skip the -1 entry */ + if ( ce->ce_type == Cft_Database ) { + cprev = &ce2->ce_sibs; + ce2 = ce2->ce_sibs; + } + cebase = ce2; + cbprev = cprev; + + /* Remove from old slot */ + for ( ce2 = *cprev; ce2 && ce2 != ce; ce2 = ce2->ce_sibs ) + cprev = &ce2->ce_sibs; + *cprev = ce->ce_sibs; + ceold = ce->ce_sibs; + + /* Insert into new slot */ + cprev = cbprev; + for ( i=0; ice_sibs; + } + ce->ce_sibs = *cprev; + *cprev = ce; + + ixnew = i; + + /* NOTE: These should be encoded in the OC tables, not inline here */ + if ( ce->ce_type == Cft_Database ) + backend_db_move( ce->ce_be, ixnew ); + else if ( ce->ce_type == Cft_Overlay ) + overlay_move( ce->ce_be, (slap_overinst *)ce->ce_bi, ixnew ); + + if ( ixold < ixnew ) { + rs->sr_err = config_rename_del( op, rs, ce, ceold, ixold, + cfb->cb_use_ldif ); + } else { + rs->sr_err = config_rename_add( op, rs, ce, ixnew, 1, + ixold - ixnew, cfb->cb_use_ldif ); + } + op->oq_modrdn = modr; + } ldap_pvt_thread_pool_resume( &connection_pool ); out: diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index 258519349e..c2ac4c77ac 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -417,6 +417,7 @@ slap_modrdn2mods( goto done; } } + rs->sr_text = NULL; /* Add new attribute values to the entry */ for ( a_cnt = 0; new_rdn[a_cnt]; a_cnt++ ) { diff --git a/servers/slapd/overlays/pcache.c b/servers/slapd/overlays/pcache.c index ab93f7667f..530a2bb341 100644 --- a/servers/slapd/overlays/pcache.c +++ b/servers/slapd/overlays/pcache.c @@ -1926,7 +1926,7 @@ pc_cf_gen( ConfigArgs *c ) return( 1 ); } - if ( !backend_db_init( c->argv[1], &cm->db )) { + if ( !backend_db_init( c->argv[1], &cm->db, -1 )) { snprintf( c->msg, sizeof( c->msg ), "unknown backend type (arg #1)" ); Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->msg, 0 ); return( 1 ); diff --git a/servers/slapd/overlays/translucent.c b/servers/slapd/overlays/translucent.c index c94d04b00a..0ef846b2b3 100644 --- a/servers/slapd/overlays/translucent.c +++ b/servers/slapd/overlays/translucent.c @@ -699,7 +699,7 @@ static int translucent_db_init(BackendDB *be) { ov->db.be_private = NULL; ov->db.be_pcl_mutexp = &ov->db.be_pcl_mutex; - if ( !backend_db_init( "ldap", &ov->db )) { + if ( !backend_db_init( "ldap", &ov->db, -1 )) { Debug( LDAP_DEBUG_CONFIG, "translucent: unable to open captive back-ldap\n", 0, 0, 0); return 1; } diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 5f8b8743ad..a0674ca2f3 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -323,7 +323,9 @@ LDAP_SLAPD_F (void) backend_destroy_one LDAP_P((BackendDB *bd, int dynamic)); LDAP_SLAPD_F (BackendInfo *) backend_info LDAP_P(( const char *type )); LDAP_SLAPD_F (BackendDB *) backend_db_init LDAP_P(( const char *type, - BackendDB *be )); + BackendDB *be, int idx )); +LDAP_SLAPD_F (void) backend_db_insert LDAP_P((BackendDB *bd, int idx)); +LDAP_SLAPD_F (void) backend_db_move LDAP_P((BackendDB *bd, int idx)); LDAP_SLAPD_F (BackendDB *) select_backend LDAP_P(( struct berval * dn, @@ -411,7 +413,8 @@ LDAP_SLAPD_F (int) glue_sub_del( BackendDB *be ); * backover.c */ LDAP_SLAPD_F (int) overlay_register LDAP_P(( slap_overinst *on )); -LDAP_SLAPD_F (int) overlay_config LDAP_P(( BackendDB *be, const char *ov )); +LDAP_SLAPD_F (int) overlay_config LDAP_P(( BackendDB *be, const char *ov, + int idx, BackendInfo **res )); LDAP_SLAPD_F (void) overlay_destroy_one LDAP_P(( BackendDB *be, slap_overinst *on )); @@ -428,6 +431,10 @@ LDAP_SLAPD_F (int) overlay_op_walk LDAP_P(( slap_operation_t which, slap_overinfo *oi, slap_overinst *on )); +LDAP_SLAPD_F (void) overlay_insert LDAP_P(( + BackendDB *be, slap_overinst *on, slap_overinst ***prev, int idx )); +LDAP_SLAPD_F (void) overlay_move LDAP_P(( + BackendDB *be, slap_overinst *on, int idx )); /* * bconfig.c diff --git a/servers/slapd/slapi/slapi_overlay.c b/servers/slapd/slapi/slapi_overlay.c index cdd6e0f7c1..d359307bc0 100644 --- a/servers/slapd/slapi/slapi_overlay.c +++ b/servers/slapd/slapi/slapi_overlay.c @@ -935,7 +935,7 @@ int slapi_over_config( BackendDB *be ) slapi_over_initialized = 1; } - return overlay_config( be, SLAPI_OVERLAY_NAME ); + return overlay_config( be, SLAPI_OVERLAY_NAME, -1, NULL ); } #endif /* LDAP_SLAPI */ -- 2.39.5