mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
Basic Modify framework, still in progress
This commit is contained in:
parent
18e19a3a52
commit
1ad2e448c5
@ -2872,13 +2872,15 @@ config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ConfigTable *
|
static ConfigTable *
|
||||||
config_find_table( CfOcInfo *co, AttributeDescription *ad )
|
config_find_table( CfOcInfo **colst, int nocs, AttributeDescription *ad )
|
||||||
{
|
{
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
for (i=0; co->co_table[i].name; i++)
|
for (j=0; j<nocs; j++) {
|
||||||
if ( co->co_table[i].ad == ad )
|
for (i=0; colst[j]->co_table[i].name; i++)
|
||||||
return &co->co_table[i];
|
if ( colst[j]->co_table[i].ad == ad )
|
||||||
|
return &colst[j]->co_table[i];
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3022,18 +3024,32 @@ sort_attrs( Entry *e, CfOcInfo **colst, int nocs )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_attr( ConfigTable *ct, ConfigArgs *ca, Attribute *a )
|
check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
|
||||||
{
|
{
|
||||||
|
Attribute *a = NULL;
|
||||||
|
AttributeDescription *ad;
|
||||||
|
BerVarray vals;
|
||||||
|
|
||||||
int i, rc = 0, sort = 0;
|
int i, rc = 0, sort = 0;
|
||||||
|
|
||||||
if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
|
if ( isAttr ) {
|
||||||
|
a = ptr;
|
||||||
|
ad = a->a_desc;
|
||||||
|
vals = a->a_vals;
|
||||||
|
} else {
|
||||||
|
Modifications *ml = ptr;
|
||||||
|
ad = ml->sml_desc;
|
||||||
|
vals = ml->sml_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( a && ad->ad_type->sat_flags & SLAP_AT_ORDERED ) {
|
||||||
sort = 1;
|
sort = 1;
|
||||||
rc = sort_vals( a );
|
rc = sort_vals( a );
|
||||||
if ( rc )
|
if ( rc )
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
for ( i=0; a->a_nvals[i].bv_val; i++ ) {
|
for ( i=0; vals[i].bv_val; i++ ) {
|
||||||
ca->line = a->a_nvals[i].bv_val;
|
ca->line = vals[i].bv_val;
|
||||||
if ( sort ) ca->line = strchr( ca->line, '}' ) + 1;
|
if ( sort ) ca->line = strchr( ca->line, '}' ) + 1;
|
||||||
rc = config_parse_vals( ct, ca, i );
|
rc = config_parse_vals( ct, ca, i );
|
||||||
if ( rc )
|
if ( rc )
|
||||||
@ -3165,12 +3181,42 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CfOcInfo **
|
||||||
|
count_ocs( Attribute *oc_at, int *nocs )
|
||||||
|
{
|
||||||
|
int i, j, n;
|
||||||
|
CfOcInfo co, *coptr, **colst;
|
||||||
|
|
||||||
|
/* count the objectclasses */
|
||||||
|
for ( i=0; oc_at->a_nvals[i].bv_val; i++ );
|
||||||
|
n = i;
|
||||||
|
colst = (CfOcInfo **)ch_malloc( n * sizeof(CfOcInfo *));
|
||||||
|
|
||||||
|
for ( i=0, j=0; i<n; i++) {
|
||||||
|
co.co_name = &oc_at->a_nvals[i];
|
||||||
|
coptr = avl_find( CfOcTree, &co, CfOcInfo_cmp );
|
||||||
|
|
||||||
|
/* ignore non-config objectclasses. probably should be
|
||||||
|
* an error, general data doesn't belong here.
|
||||||
|
*/
|
||||||
|
if ( !coptr ) continue;
|
||||||
|
|
||||||
|
/* Ignore the root objectclass, it has no implementation.
|
||||||
|
*/
|
||||||
|
if ( coptr->co_type == Cft_Abstract ) continue;
|
||||||
|
colst[j++] = coptr;
|
||||||
|
}
|
||||||
|
*nocs = j;
|
||||||
|
return colst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only the root can be Cft_Global, everything else must
|
||||||
/* Parse an LDAP entry into config directives */
|
/* Parse an LDAP entry into config directives */
|
||||||
static int
|
static int
|
||||||
config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
|
config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
|
||||||
{
|
{
|
||||||
CfEntryInfo *ce, *last;
|
CfEntryInfo *ce, *last;
|
||||||
CfOcInfo co, *coptr, **colst = NULL;
|
CfOcInfo **colst;
|
||||||
Attribute *a, *oc_at, *type_attr;
|
Attribute *a, *oc_at, *type_attr;
|
||||||
AttributeDescription *type_ad = NULL;
|
AttributeDescription *type_ad = NULL;
|
||||||
int i, j, nocs, rc;
|
int i, j, nocs, rc;
|
||||||
@ -3198,26 +3244,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
|
|||||||
oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
|
oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
|
||||||
if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
|
if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
|
||||||
|
|
||||||
/* count the objectclasses */
|
colst = count_ocs( oc_at, &nocs );
|
||||||
for ( i=0; oc_at->a_nvals[i].bv_val; i++ );
|
|
||||||
nocs = i;
|
|
||||||
colst = (CfOcInfo **)ch_malloc( nocs * sizeof(CfOcInfo *));
|
|
||||||
|
|
||||||
for ( i=0, j=0; i<nocs; i++) {
|
|
||||||
co.co_name = &oc_at->a_nvals[i];
|
|
||||||
coptr = avl_find( CfOcTree, &co, CfOcInfo_cmp );
|
|
||||||
|
|
||||||
/* ignore non-config objectclasses. probably should be
|
|
||||||
* an error, general data doesn't belong here.
|
|
||||||
*/
|
|
||||||
if ( !coptr ) continue;
|
|
||||||
|
|
||||||
/* Ignore the root objectclass, it has no implementation.
|
|
||||||
*/
|
|
||||||
if ( coptr->co_type == Cft_Abstract ) continue;
|
|
||||||
colst[j++] = coptr;
|
|
||||||
}
|
|
||||||
nocs = j;
|
|
||||||
|
|
||||||
/* Only the root can be Cft_Global, everything else must
|
/* Only the root can be Cft_Global, everything else must
|
||||||
* have a parent. Only limited nesting arrangements are allowed.
|
* have a parent. Only limited nesting arrangements are allowed.
|
||||||
@ -3347,26 +3374,19 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
|
|||||||
rc = LDAP_OBJECT_CLASS_VIOLATION;
|
rc = LDAP_OBJECT_CLASS_VIOLATION;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
for ( i=0; i<nocs; i++ ) {
|
type_ct = config_find_table( colst, nocs, type_ad );
|
||||||
type_ct = config_find_table( colst[i], type_ad );
|
|
||||||
if ( type_ct ) break;
|
|
||||||
}
|
|
||||||
if ( !type_ct ) {
|
if ( !type_ct ) {
|
||||||
rc = LDAP_OBJECT_CLASS_VIOLATION;
|
rc = LDAP_OBJECT_CLASS_VIOLATION;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
rc = check_attr( type_ct, &ca, type_attr );
|
rc = check_vals( type_ct, &ca, type_attr, 1);
|
||||||
if ( rc ) goto leave;
|
if ( rc ) goto leave;
|
||||||
}
|
}
|
||||||
for ( a=e->e_attrs; a; a=a->a_next ) {
|
for ( a=e->e_attrs; a; a=a->a_next ) {
|
||||||
if ( a == type_attr || a == oc_at ) continue;
|
if ( a == type_attr || a == oc_at ) continue;
|
||||||
ct = NULL;
|
ct = config_find_table( colst, nocs, a->a_desc );
|
||||||
for ( i=0; i<nocs; i++ ) {
|
|
||||||
ct = config_find_table( colst[i], a->a_desc );
|
|
||||||
if ( ct ) break;
|
|
||||||
}
|
|
||||||
if ( !ct ) continue; /* user data? */
|
if ( !ct ) continue; /* user data? */
|
||||||
rc = check_attr( ct, &ca, a );
|
rc = check_vals( ct, &ca, a, 1 );
|
||||||
if ( rc ) goto leave;
|
if ( rc ) goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3383,11 +3403,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
|
|||||||
}
|
}
|
||||||
for ( a=e->e_attrs; a; a=a->a_next ) {
|
for ( a=e->e_attrs; a; a=a->a_next ) {
|
||||||
if ( a == type_attr || a == oc_at ) continue;
|
if ( a == type_attr || a == oc_at ) continue;
|
||||||
ct = NULL;
|
ct = config_find_table( colst, nocs, a->a_desc );
|
||||||
for ( i=0; i<nocs; i++ ) {
|
|
||||||
ct = config_find_table( colst[i], a->a_desc );
|
|
||||||
if ( ct ) break;
|
|
||||||
}
|
|
||||||
if ( !ct ) continue; /* user data? */
|
if ( !ct ) continue; /* user data? */
|
||||||
for (i=0; a->a_vals[i].bv_val; i++) {
|
for (i=0; a->a_vals[i].bv_val; i++) {
|
||||||
ca.line = a->a_vals[i].bv_val;
|
ca.line = a->a_vals[i].bv_val;
|
||||||
@ -3471,19 +3487,117 @@ out:
|
|||||||
return rs->sr_err;
|
return rs->sr_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modify rules:
|
static int
|
||||||
* for single-valued attributes, should just use REPLACE.
|
config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
|
||||||
* any received DELETE/ADD on a single-valued attr will
|
char *textbuf, int textsize )
|
||||||
* be checked (if a DEL value is provided) and then
|
{
|
||||||
* rewritten as a REPLACE.
|
CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private;
|
||||||
* any DELETE received without a corresponding ADD will be
|
int rc = LDAP_UNWILLING_TO_PERFORM;
|
||||||
* rejected with LDAP_CONSTRAINT_VIOLATION.
|
Modifications *ml;
|
||||||
*/
|
Entry *e = ce->ce_entry;
|
||||||
|
Attribute *save_attrs = e->e_attrs, *oc_at;
|
||||||
|
ConfigArgs ca = {0};
|
||||||
|
ConfigTable *ct;
|
||||||
|
CfOcInfo **colst;
|
||||||
|
int i, nocs;
|
||||||
|
|
||||||
|
oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
|
||||||
|
if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
|
||||||
|
|
||||||
|
colst = count_ocs( oc_at, &nocs );
|
||||||
|
|
||||||
|
e->e_attrs = attrs_dup( e->e_attrs );
|
||||||
|
init_config_argv( &ca );
|
||||||
|
|
||||||
|
for (ml = op->orm_modlist; ml; ml=ml->sml_next) {
|
||||||
|
switch (ml->sml_op) {
|
||||||
|
case LDAP_MOD_DELETE:
|
||||||
|
case LDAP_MOD_REPLACE: {
|
||||||
|
BerVarray vals = NULL, nvals;
|
||||||
|
if ( ml->sml_op == LDAP_MOD_REPLACE ) {
|
||||||
|
vals = ml->sml_values;
|
||||||
|
nvals = ml->sml_nvalues;
|
||||||
|
ml->sml_values = NULL;
|
||||||
|
ml->sml_nvalues = NULL;
|
||||||
|
}
|
||||||
|
rc = modify_delete_values(e, &ml->sml_mod,
|
||||||
|
get_permissiveModify(op),
|
||||||
|
&rs->sr_text, textbuf, textsize );
|
||||||
|
if ( ml->sml_op == LDAP_MOD_REPLACE ) {
|
||||||
|
ml->sml_values = vals;
|
||||||
|
ml->sml_nvalues = nvals;
|
||||||
|
}
|
||||||
|
if ( !vals )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* FALLTHRU: LDAP_MOD_REPLACE && vals */
|
||||||
|
|
||||||
|
case LDAP_MOD_ADD:
|
||||||
|
case SLAP_MOD_SOFTADD: {
|
||||||
|
int mop = ml->sml_op;
|
||||||
|
ml->sml_op = LDAP_MOD_ADD;
|
||||||
|
for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) {
|
||||||
|
ct = config_find_table( colst, nocs, ml->sml_desc );
|
||||||
|
if ( !ct ) continue;
|
||||||
|
rc = check_vals( ct, &ca, ml, 0 );
|
||||||
|
if ( rc ) goto out;
|
||||||
|
}
|
||||||
|
rc = modify_add_values(e, &ml->sml_mod,
|
||||||
|
get_permissiveModify(op),
|
||||||
|
&rs->sr_text, textbuf, textsize );
|
||||||
|
ml->sml_op = mop;
|
||||||
|
if ( mop == SLAP_MOD_SOFTADD && rc == LDAP_TYPE_OR_VALUE_EXISTS )
|
||||||
|
rc = LDAP_SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LDAP_MOD_INCREMENT: /* FIXME */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(rc != LDAP_SUCCESS) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rc == LDAP_SUCCESS) {
|
||||||
|
/* check that the entry still obeys the schema */
|
||||||
|
rc = entry_schema_check(op->o_bd, e, NULL,
|
||||||
|
&rs->sr_text, textbuf, textsize );
|
||||||
|
}
|
||||||
|
if ( rc == LDAP_SUCCESS ) {
|
||||||
|
/* Basic syntax checks are OK. Do the actual settings. */
|
||||||
|
for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
|
||||||
|
/* Ignore single-value deletes */
|
||||||
|
if ( is_at_single_value( ml->sml_desc->ad_type ) &&
|
||||||
|
ml->sml_op == LDAP_MOD_DELETE ) continue;
|
||||||
|
|
||||||
|
ct = config_find_table( colst, nocs, ml->sml_desc );
|
||||||
|
if ( !ct ) continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if ( rc == LDAP_SUCCESS ) {
|
||||||
|
attrs_free( save_attrs );
|
||||||
|
} else {
|
||||||
|
attrs_free( e->e_attrs );
|
||||||
|
e->e_attrs = save_attrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
config_back_modify( Operation *op, SlapReply *rs )
|
config_back_modify( Operation *op, SlapReply *rs )
|
||||||
{
|
{
|
||||||
CfBackInfo *cfb;
|
CfBackInfo *cfb;
|
||||||
CfEntryInfo *ce, *last;
|
CfEntryInfo *ce, *last;
|
||||||
|
Modifications *ml;
|
||||||
|
char textbuf[SLAP_TEXT_BUFLEN];
|
||||||
|
struct berval rdn;
|
||||||
|
char *ptr;
|
||||||
|
AttributeDescription *rad = NULL;
|
||||||
|
|
||||||
if ( !be_isroot( op ) ) {
|
if ( !be_isroot( op ) ) {
|
||||||
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
||||||
@ -3499,6 +3613,40 @@ config_back_modify( Operation *op, SlapReply *rs )
|
|||||||
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get type of RDN */
|
||||||
|
rdn = ce->ce_entry->e_nname;
|
||||||
|
ptr = strchr( rdn.bv_val, '=' );
|
||||||
|
rdn.bv_len = ptr - rdn.bv_val;
|
||||||
|
slap_bv2ad( &rdn, &rad, &rs->sr_text );
|
||||||
|
|
||||||
|
/* Some basic validation... */
|
||||||
|
for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
|
||||||
|
/* Braindead single-value check - the ADD must immediately follow
|
||||||
|
* the DELETE. We don't check that there's only one ADD; for multiple
|
||||||
|
* ADDs only the last one will be saved. The drivers don't distinguish
|
||||||
|
* ADD from REPLACE.
|
||||||
|
*/
|
||||||
|
if ( is_at_single_value( ml->sml_desc->ad_type )) {
|
||||||
|
if (( ml->sml_op == LDAP_MOD_DELETE &&
|
||||||
|
( !ml->sml_next || ml->sml_next->sml_desc != ml->sml_desc ||
|
||||||
|
ml->sml_next->sml_op != LDAP_MOD_ADD )) ||
|
||||||
|
|
||||||
|
/* Also check for REPLACE with no values */
|
||||||
|
( ml->sml_op == LDAP_MOD_REPLACE && !ml->sml_values )) {
|
||||||
|
rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
|
||||||
|
rs->sr_text = "Single-Value Delete must be followed by Add";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Don't allow Modify of RDN; must use ModRdn for that. */
|
||||||
|
if ( ml->sml_desc == rad ) {
|
||||||
|
rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
|
||||||
|
rs->sr_text = "Use modrdn to change the entry name";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ldap_pvt_thread_pool_pause( &connection_pool );
|
ldap_pvt_thread_pool_pause( &connection_pool );
|
||||||
|
|
||||||
/* Strategy:
|
/* Strategy:
|
||||||
@ -3507,6 +3655,8 @@ config_back_modify( Operation *op, SlapReply *rs )
|
|||||||
* 3) perform the individual config operations.
|
* 3) perform the individual config operations.
|
||||||
* 4) store Modified entry in underlying LDIF backend.
|
* 4) store Modified entry in underlying LDIF backend.
|
||||||
*/
|
*/
|
||||||
|
rs->sr_err = config_modify_internal( ce, op, rs, textbuf, sizeof(textbuf) );
|
||||||
|
|
||||||
ldap_pvt_thread_pool_resume( &connection_pool );
|
ldap_pvt_thread_pool_resume( &connection_pool );
|
||||||
out:
|
out:
|
||||||
send_ldap_result( op, rs );
|
send_ldap_result( op, rs );
|
||||||
|
Loading…
Reference in New Issue
Block a user