From 2f5e17d056f5c8d0722419841eedc67c05993595 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sat, 11 Dec 2004 17:48:15 +0000 Subject: [PATCH] improve usability of global ovrlays for write operations; may need to anticipate SLAPI accordingly. More work needed for add (overlays need to understand they're global and call slap_mods2entry() explicitly) --- servers/slapd/abandon.c | 5 ++- servers/slapd/add.c | 67 +++++++++++++++++----------- servers/slapd/connection.c | 2 +- servers/slapd/modify.c | 75 ++++++++++++++++++++++++++------ servers/slapd/overlays/chain.c | 27 ++++++++++++ servers/slapd/overlays/lastmod.c | 13 ------ servers/slapd/proto-slap.h | 6 ++- servers/slapd/sasl.c | 37 +++++++++------- servers/slapd/slapi/slapi_ops.c | 36 ++++++++++----- servers/slapd/syncrepl.c | 2 +- 10 files changed, 188 insertions(+), 82 deletions(-) diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index a3c1eb63c1..78fa52904e 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -110,7 +110,10 @@ fe_op_abandon( Operation *op, SlapReply *rs ) for ( i = 0; i < nbackends; i++ ) { op->o_bd = &backends[i]; - if( op->o_bd->be_abandon ) op->o_bd->be_abandon( op, rs ); + if ( op->o_bd->be_abandon ) { + (void)op->o_bd->be_abandon( op, rs ); + } } + return LDAP_SUCCESS; } diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 306b65ee69..2945064004 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -53,6 +53,9 @@ do_add( Operation *op, SlapReply *rs ) Modifications *modlist = NULL; Modifications **modtail = &modlist; Modifications tmp; + char textbuf[ SLAP_TEXT_BUFLEN ]; + size_t textlen = sizeof( textbuf ); + int rc = 0; Debug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 ); /* @@ -79,7 +82,7 @@ do_add( Operation *op, SlapReply *rs ) rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); - if( rs->sr_err != LDAP_SUCCESS ) { + if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "do_add: invalid dn (%s)\n", dn.bv_val, 0, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto done; @@ -135,7 +138,7 @@ do_add( Operation *op, SlapReply *rs ) goto done; } - if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { + if ( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "do_add: get_ctrls failed\n", 0, 0, 0 ); goto done; } @@ -149,41 +152,49 @@ do_add( Operation *op, SlapReply *rs ) Statslog( LDAP_DEBUG_STATS, "%s ADD dn=\"%s\"\n", op->o_log_prefix, e->e_name.bv_val, 0, 0, 0 ); - if( e->e_nname.bv_len == 0 ) { + if ( dn_match( &e->e_nname, &slap_empty_bv ) ) { /* protocolError may be a more appropriate error */ send_ldap_error( op, rs, LDAP_ALREADY_EXISTS, "root DSE already exists" ); goto done; - } else if ( bvmatch( &e->e_nname, &frontendDB->be_schemandn ) ) { + } else if ( dn_match( &e->e_nname, &frontendDB->be_schemandn ) ) { send_ldap_error( op, rs, LDAP_ALREADY_EXISTS, "subschema subentry already exists" ); goto done; } + rs->sr_err = slap_mods_check( modlist, &rs->sr_text, + textbuf, textlen, NULL ); + + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto done; + } + /* temporary; remove if not invoking backend function */ op->ora_e = e; op->ora_modlist = modlist; op->o_bd = frontendDB; - rs->sr_err = frontendDB->be_add( op, rs ); - if ( rs->sr_err == 0 ) { + rc = frontendDB->be_add( op, rs ); + if ( rc == 0 ) { e = NULL; } done:; slap_graduate_commit_csn( op ); - if( modlist != NULL ) { + if ( modlist != NULL ) { slap_mods_free( modlist ); } - if( e != NULL ) { + if ( e != NULL ) { entry_free( e ); } op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); - return rs->sr_err; + return rc; } int @@ -249,30 +260,36 @@ fe_op_add( Operation *op, SlapReply *rs ) if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif { - int update = op->o_bd->be_update_ndn.bv_len; - char textbuf[SLAP_TEXT_BUFLEN]; - size_t textlen = sizeof textbuf; - slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; + int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); + char textbuf[ SLAP_TEXT_BUFLEN ]; + size_t textlen = sizeof( textbuf ); + slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; - rs->sr_err = slap_mods_check( modlist, update, &rs->sr_text, - textbuf, textlen, NULL ); + if ( !update ) { + rs->sr_err = slap_mods_no_update_check( modlist, + &rs->sr_text, + textbuf, textlen ); - if( rs->sr_err != LDAP_SUCCESS ) { - send_ldap_result( op, rs ); - goto done; + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto done; + } } if ( !repl_user ) { - for( modtail = &modlist; - *modtail != NULL; - modtail = &(*modtail)->sml_next ) + /* go to the last mod */ + for ( modtail = &modlist; + *modtail != NULL; + modtail = &(*modtail)->sml_next ) { assert( (*modtail)->sml_op == LDAP_MOD_ADD ); assert( (*modtail)->sml_desc != NULL ); } - rs->sr_err = slap_mods_opattrs( op, modlist, modtail, - &rs->sr_text, textbuf, textlen, 1 ); - if( rs->sr_err != LDAP_SUCCESS ) { + + rs->sr_err = slap_mods_opattrs( op, modlist, + modtail, &rs->sr_text, + textbuf, textlen, 1 ); + if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto done; } @@ -280,7 +297,7 @@ fe_op_add( Operation *op, SlapReply *rs ) rs->sr_err = slap_mods2entry( modlist, &e, repl_user, 0, &rs->sr_text, textbuf, textlen ); - if( rs->sr_err != LDAP_SUCCESS ) { + if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto done; } diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 3cad16d760..6e309daf9c 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -1546,7 +1546,7 @@ connection_resched( Connection *conn ) ber_socket_t sd; ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); - /* us trylock to avoid possible deadlock */ + /* use trylock to avoid possible deadlock */ rc = ldap_pvt_thread_mutex_trylock( &connections_mutex ); if( rc ) { diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index f57f6cbb62..0aadd943c4 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -50,6 +50,8 @@ do_modify( Modifications *modlist = NULL; Modifications **modtail = &modlist; int increment = 0; + char textbuf[ SLAP_TEXT_BUFLEN ]; + size_t textlen = sizeof( textbuf ); Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 ); @@ -184,7 +186,15 @@ do_modify( goto cleanup; } - /* FIXME: temporary */ + rs->sr_err = slap_mods_check( modlist, &rs->sr_text, + textbuf, textlen, NULL ); + + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto cleanup; + } + + /* FIXME: needs review */ op->orm_modlist = modlist; op->orm_increment = increment; @@ -214,6 +224,7 @@ fe_op_modify( Operation *op, SlapReply *rs ) LDAPMod **modv = NULL; #endif int increment = op->orm_increment; + int rc = 0; if( op->o_req_ndn.bv_len == 0 ) { Debug( LDAP_DEBUG_ANY, "do_modify: root dse!\n", 0, 0, 0 ); @@ -404,19 +415,23 @@ fe_op_modify( Operation *op, SlapReply *rs ) if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif { - int update = op->o_bd->be_update_ndn.bv_len; - char textbuf[SLAP_TEXT_BUFLEN]; - size_t textlen = sizeof textbuf; - slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; + int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); + char textbuf[ SLAP_TEXT_BUFLEN ]; + size_t textlen = sizeof( textbuf ); + slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; - rs->sr_err = slap_mods_check( modlist, update, &rs->sr_text, - textbuf, textlen, NULL ); - if( rs->sr_err != LDAP_SUCCESS ) { - send_ldap_result( op, rs ); - goto cleanup; + if ( !update ) { + rs->sr_err = slap_mods_no_update_check( modlist, + &rs->sr_text, textbuf, textlen ); + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto cleanup; + } } + + if ( !repl_user ) { for( modtail = &modlist; *modtail != NULL; @@ -438,7 +453,8 @@ fe_op_modify( Operation *op, SlapReply *rs ) if ( !repl_user ) #endif { - /* but we log only the ones not from a replicator user */ + /* but multimaster slapd logs only the ones + * not from a replicator user */ cb.sc_next = op->o_callback; op->o_callback = &cb; } @@ -453,12 +469,17 @@ fe_op_modify( Operation *op, SlapReply *rs ) rs->sr_ref = referral_rewrite( defref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); - if (!rs->sr_ref) rs->sr_ref = defref; + if ( rs->sr_ref == NULL ) { + /* FIXME: must duplicate, because + * overlays may muck with it */ + rs->sr_ref = defref; + } rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); - if (rs->sr_ref != defref) { + if ( rs->sr_ref != defref ) { ber_bvarray_free( rs->sr_ref ); } + } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "shadow context; no update referral" ); @@ -487,12 +508,35 @@ cleanup:; return rs->sr_err; } +/* + * Do non-update constraint checking. + */ +int +slap_mods_no_update_check( + Modifications *ml, + const char **text, + char *textbuf, + size_t textlen ) +{ + for ( ; ml != NULL; ml = ml->sml_next ) { + if ( is_at_no_user_mod( ml->sml_desc->ad_type ) ) { + /* user modification disallowed */ + snprintf( textbuf, textlen, + "%s: no user modification allowed", + ml->sml_type.bv_val ); + *text = textbuf; + return LDAP_CONSTRAINT_VIOLATION; + } + } + + return LDAP_SUCCESS; +} + /* * Do basic attribute type checking and syntax validation. */ int slap_mods_check( Modifications *ml, - int update, const char **text, char *textbuf, size_t textlen, @@ -546,6 +590,8 @@ int slap_mods_check( return LDAP_UNDEFINED_TYPE; } +#if 0 + /* moved to slap_mods_no_update_check() */ if (!update && is_at_no_user_mod( ad->ad_type )) { /* user modification disallowed */ snprintf( textbuf, textlen, @@ -554,6 +600,7 @@ int slap_mods_check( *text = textbuf; return LDAP_CONSTRAINT_VIOLATION; } +#endif if ( is_at_obsolete( ad->ad_type ) && (( ml->sml_op != LDAP_MOD_REPLACE && diff --git a/servers/slapd/overlays/chain.c b/servers/slapd/overlays/chain.c index a1e2af73a6..5abc50f422 100644 --- a/servers/slapd/overlays/chain.c +++ b/servers/slapd/overlays/chain.c @@ -202,8 +202,35 @@ ldap_chain_response( Operation *op, SlapReply *rs ) } break; case LDAP_REQ_ADD: + { + int cleanup_attrs = 0; + + if ( op->ora_e->e_attrs == NULL ) { + char textbuf[ SLAP_TEXT_BUFLEN ]; + size_t textlen = sizeof( textbuf ); + + /* global overlay; create entry */ + /* NOTE: this is a hack to use the chain overlay + * as global. I expect to be able to remove this + * soon by using slap_mods2entry() earlier in + * do_add(), adding the operational attrs later + * if required. */ + rs->sr_err = slap_mods2entry( op->ora_modlist, + &op->ora_e, 0, 1, + &rs->sr_text, textbuf, textlen ); + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + rc = 1; + break; + } + } rc = lback->bi_op_add( op, rs ); + if ( cleanup_attrs ) { + attrs_free( op->ora_e->e_attrs ); + op->ora_e->e_attrs = NULL; + } break; + } case LDAP_REQ_DELETE: rc = lback->bi_op_delete( op, rs ); break; diff --git a/servers/slapd/overlays/lastmod.c b/servers/slapd/overlays/lastmod.c index 5594f2de32..09a674df3d 100644 --- a/servers/slapd/overlays/lastmod.c +++ b/servers/slapd/overlays/lastmod.c @@ -308,19 +308,6 @@ lastmod_op_func( Operation *op, SlapReply *rs ) return lastmod_exop( op, rs ); case LDAP_REQ_MODIFY: - /* if global overlay, modlist is not checked yet */ - if ( op->orm_modlist->sml_desc == NULL ) { - char textbuf[SLAP_TEXT_BUFLEN]; - size_t textlen = sizeof textbuf; - - rs->sr_err = slap_mods_check( op->orm_modlist, 0, &rs->sr_text, - textbuf, textlen, NULL ); - - if ( rs->sr_err ) { - goto return_error; - } - } - /* allow only changes to overlay status */ for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { if ( ad_cmp( ml->sml_desc, slap_schema.si_ad_modifiersName ) != 0 diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 73cb30fe40..60b9a488ae 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -787,9 +787,13 @@ LDAP_SLAPD_F (int) slap_modrdn2mods( /* * modify.c */ +LDAP_SLAPD_F( int ) slap_mods_no_update_check( + Modifications *ml, + const char **text, + char *textbuf, size_t textlen ); + LDAP_SLAPD_F( int ) slap_mods_check( Modifications *ml, - int update, const char **text, char *textbuf, size_t textlen, void *ctx ); diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index b5c6b0b990..0587c62e92 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -491,28 +491,33 @@ slap_auxprop_store( } *modtail = NULL; - rc = slap_mods_check( modlist, 0, &text, textbuf, textlen, NULL ); + rc = slap_mods_check( modlist, &text, textbuf, textlen, NULL ); if ( rc == LDAP_SUCCESS ) { - rc = slap_mods_opattrs( &op, modlist, modtail, &text, textbuf, - textlen, 1 ); - } + rc = slap_mods_no_update_check( modlist, &text, + textbuf, textlen ); - if ( rc == LDAP_SUCCESS ) { - op.o_hdr = conn->c_sasl_bindop->o_hdr; - op.o_tag = LDAP_REQ_MODIFY; - op.o_ndn = op.o_req_ndn; - op.o_callback = &cb; - op.o_time = slap_get_time(); - op.o_do_not_cache = 1; - op.o_is_auth_check = 1; - op.o_req_dn = op.o_req_ndn; - op.orm_modlist = modlist; + if ( rc == LDAP_SUCCESS ) { + rc = slap_mods_opattrs( &op, modlist, modtail, + &text, textbuf, textlen, 1 ); - rc = op.o_bd->be_modify( &op, &rs ); + if ( rc == LDAP_SUCCESS ) { + op.o_hdr = conn->c_sasl_bindop->o_hdr; + op.o_tag = LDAP_REQ_MODIFY; + op.o_ndn = op.o_req_ndn; + op.o_callback = &cb; + op.o_time = slap_get_time(); + op.o_do_not_cache = 1; + op.o_is_auth_check = 1; + op.o_req_dn = op.o_req_ndn; + op.orm_modlist = modlist; + + rc = op.o_bd->be_modify( &op, &rs ); + } + } } slap_mods_free( modlist ); - return rc ? SASL_FAIL : SASL_OK; + return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK; } #endif /* SASL_VERSION_FULL >= 2.1.16 */ diff --git a/servers/slapd/slapi/slapi_ops.c b/servers/slapd/slapi/slapi_ops.c index 4b7b02ae79..6a0f9ec04f 100644 --- a/servers/slapd/slapi/slapi_ops.c +++ b/servers/slapd/slapi/slapi_ops.c @@ -450,16 +450,24 @@ slapi_int_ldapmod_to_entry( } else { int repl_user = be_isupdate_dn( op->o_bd, &op->o_bd->be_rootdn ); if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) { - int update = op->o_bd->be_update_ndn.bv_len; - char textbuf[SLAP_TEXT_BUFLEN]; - size_t textlen = sizeof textbuf; + int update = !BER_BVISNULL( &op->o_bd->be_update_ndn ); + char textbuf[ SLAP_TEXT_BUFLEN ]; + size_t textlen = sizeof( textbuf ); - rc = slap_mods_check( modlist, update, &text, + rc = slap_mods_check( modlist, &text, textbuf, textlen, NULL ); if ( rc != LDAP_SUCCESS) { goto cleanup; } + if ( !update ) { + rc = slap_mods_no_update_check( modlist, + &text, textbuf, textlen ); + if ( rc != LDAP_SUCCESS) { + goto cleanup; + } + } + if ( !repl_user ) { rc = slap_mods_opattrs( op, modlist, modtail, &text, @@ -1014,18 +1022,26 @@ slapi_modify_internal( if ( op->o_bd->be_modify ) { int repl_user = be_isupdate( op ); if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) { - int update = op->o_bd->be_update_ndn.bv_len; - const char *text = NULL; - char textbuf[SLAP_TEXT_BUFLEN]; - size_t textlen = sizeof( textbuf ); - slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; + int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); + const char *text = NULL; + char textbuf[ SLAP_TEXT_BUFLEN ]; + size_t textlen = sizeof( textbuf ); + slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; - rs.sr_err = slap_mods_check( modlist, update, + rs.sr_err = slap_mods_check( modlist, &text, textbuf, textlen, NULL ); if ( rs.sr_err != LDAP_SUCCESS ) { goto cleanup; } + if ( !update ) { + rs.sr_err = slap_mods_no_update_check( modlist, + &text, textbuf, textlen ); + if ( rs.sr_err != LDAP_SUCCESS ) { + goto cleanup; + } + } + if ( !repl_user ) { rs.sr_err = slap_mods_opattrs( op, modlist, modtail, &text, textbuf, diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index ae06498e33..a78f6c8fa2 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -1105,7 +1105,7 @@ syncrepl_message_to_entry( goto done; } - rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL ); + rc = slap_mods_check( *modlist, &text, txtbuf, textlen, NULL ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",