From: Kurt Zeilenga Date: Wed, 27 Sep 2000 22:28:59 +0000 (+0000) Subject: Rough in extended ops, modify, and modrdn. X-Git-Tag: LDBM_PRE_GIANT_RWLOCK~1876 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=ddb1124e42df2f5a71d93d986c806f4ee4783964;p=openldap Rough in extended ops, modify, and modrdn. General code cleanup. --- diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c index 0fbb162387..8fbef95a97 100644 --- a/servers/slapd/back-bdb/add.c +++ b/servers/slapd/back-bdb/add.c @@ -27,6 +27,7 @@ bdb_add( const char *text = NULL; AttributeDescription *children = slap_schema.si_ad_children; DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0); @@ -76,7 +77,10 @@ retry: rc = txn_abort( ltid ); goto return_results; } - op->o_private = ltid; + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; /* * Get the parent dn and see if the corresponding entry exists. @@ -88,8 +92,8 @@ retry: rc = txn_abort( ltid ); if( pdn != NULL && *pdn != '\0' ) { Entry *matched = NULL; - /* get parent with reader lock */ - rc = dn2entry_r( be, ltid, pdn, &p, &matched ); + /* get parent */ + rc = bdb_dn2entry( be, ltid, pdn, &p, &matched, 0 ); ch_free( pdn ); switch( rc ) { @@ -125,7 +129,7 @@ retry: rc = txn_abort( ltid ); 0, 0, 0 ); send_ldap_result( conn, op, rc = LDAP_REFERRAL, - matched_dn, NULL, refs, NULL ); + matched_dn, NULL, refs, NULL ); if( matched != NULL ) { ber_bvecfree( refs ); @@ -165,7 +169,7 @@ retry: rc = txn_abort( ltid ); 0, 0, 0 ); send_ldap_result( conn, op, rc = LDAP_REFERRAL, - matched_dn, NULL, refs, NULL ); + matched_dn, NULL, refs, NULL ); ber_bvecfree( refs ); free( matched_dn ); diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index c9fa58d905..dee9b15684 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -74,6 +74,12 @@ struct bdb_info { #define bi_id2entry bi_databases[BDB_ID2ENTRY] #define bi_dn2id bi_databases[BDB_DN2ID] +struct bdb_op_info { + BackendDB* boi_bdb; + DB_TXN* boi_txn; + int boi_err; +}; + LDAP_END_DECL #include "proto-bdb.h" diff --git a/servers/slapd/back-bdb/backbdb.dsp b/servers/slapd/back-bdb/backbdb.dsp index 49b043fc9d..e31cc1a786 100644 --- a/servers/slapd/back-bdb/backbdb.dsp +++ b/servers/slapd/back-bdb/backbdb.dsp @@ -163,6 +163,10 @@ SOURCE=.\error.c # End Source File # Begin Source File +SOURCE=.\extended.c +# End Source File +# Begin Source File + SOURCE=.\external.h # End Source File # Begin Source File @@ -179,10 +183,22 @@ SOURCE=.\init.c # End Source File # Begin Source File +SOURCE=.\modify.c +# End Source File +# Begin Source File + +SOURCE=.\modrdn.c +# End Source File +# Begin Source File + SOURCE=.\nextid.c # End Source File # Begin Source File +SOURCE=.\passwd.c +# End Source File +# Begin Source File + SOURCE=".\proto-bdb.h" # End Source File # Begin Source File diff --git a/servers/slapd/back-bdb/bind.c b/servers/slapd/back-bdb/bind.c index da28294b7d..bd9a8bf58f 100644 --- a/servers/slapd/back-bdb/bind.c +++ b/servers/slapd/back-bdb/bind.c @@ -17,13 +17,13 @@ int bdb_bind( - Backend *be, - Connection *conn, - Operation *op, - const char *dn, - const char *ndn, - int method, - struct berval *cred, + Backend *be, + Connection *conn, + Operation *op, + const char *dn, + const char *ndn, + int method, + struct berval *cred, char** edn ) { @@ -44,8 +44,8 @@ bdb_bind( *edn = NULL; - /* fetch entry */ - rc = dn2entry_r( be, NULL, ndn, &e, &matched ); + /* get entry */ + rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 ); switch(rc) { case DB_NOTFOUND: @@ -53,7 +53,7 @@ bdb_bind( break; default: send_ldap_result( conn, op, rc=LDAP_OTHER, - NULL, "internal error", NULL, NULL ); + NULL, "internal error", NULL, NULL ); return rc; } @@ -114,10 +114,10 @@ bdb_bind( if ( is_entry_alias( e ) ) { /* entry is an alias, don't allow bind */ Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, - 0, 0 ); + 0, 0 ); send_ldap_result( conn, op, rc = LDAP_ALIAS_PROBLEM, - NULL, "entry is alias", NULL, NULL ); + NULL, "entry is alias", NULL, NULL ); goto done; } @@ -128,7 +128,7 @@ bdb_bind( conn, op, e ); Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, - 0, 0 ); + 0, 0 ); if( refs != NULL ) { send_ldap_result( conn, op, rc = LDAP_REFERRAL, @@ -165,7 +165,7 @@ bdb_bind( if ( (a = attr_find( e->e_attrs, password )) == NULL ) { send_ldap_result( conn, op, rc = LDAP_INAPPROPRIATE_AUTH, - NULL, NULL, NULL, NULL ); + NULL, NULL, NULL, NULL ); goto done; } @@ -182,7 +182,7 @@ bdb_bind( case LDAP_AUTH_KRBV41: if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) { send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, - NULL, NULL, NULL, NULL ); + NULL, NULL, NULL, NULL ); goto done; } @@ -195,7 +195,7 @@ bdb_bind( } sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "." - : "", ad.pinst, ad.prealm ); + : "", ad.pinst, ad.prealm ); if ( (a = attr_find( e->e_attrs, krbattr )) == NULL ) { /* @@ -206,7 +206,7 @@ bdb_bind( break; } send_ldap_result( conn, op, rc = LDAP_INAPPROPRIATE_AUTH, - NULL, NULL, NULL, NULL ); + NULL, NULL, NULL, NULL ); goto done; } else { /* look for krbname match */ @@ -217,7 +217,7 @@ bdb_bind( if ( value_find( a->a_desc, a->a_vals, &krbval ) != 0 ) { send_ldap_result( conn, op, - rc = LDAP_INVALID_CREDENTIALS, + rc = LDAP_INVALID_CREDENTIALS, NULL, NULL, NULL, NULL ); goto done; } @@ -234,7 +234,7 @@ bdb_bind( default: send_ldap_result( conn, op, rc = LDAP_STRONG_AUTH_NOT_SUPPORTED, - NULL, "authentication method not supported", NULL, NULL ); + NULL, "authentication method not supported", NULL, NULL ); goto done; } diff --git a/servers/slapd/back-bdb/compare.c b/servers/slapd/back-bdb/compare.c index 98d95cdf5e..2764cdf9e8 100644 --- a/servers/slapd/back-bdb/compare.c +++ b/servers/slapd/back-bdb/compare.c @@ -15,11 +15,11 @@ int bdb_compare( - BackendDB *be, - Connection *conn, - Operation *op, - const char *dn, - const char *ndn, + BackendDB *be, + Connection *conn, + Operation *op, + const char *dn, + const char *ndn, AttributeAssertion *ava ) { @@ -32,7 +32,7 @@ bdb_compare( int manageDSAit = get_manageDSAit( op ); /* get entry */ - rc = dn2entry_r( be, NULL, ndn, &e, &matched ); + rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 ); switch( rc ) { case DB_NOTFOUND: @@ -74,10 +74,10 @@ bdb_compare( conn, op, e ); Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, - 0, 0 ); + 0, 0 ); send_ldap_result( conn, op, rc = LDAP_REFERRAL, - e->e_dn, NULL, refs, NULL ); + e->e_dn, NULL, refs, NULL ); ber_bvecfree( refs ); goto done; diff --git a/servers/slapd/back-bdb/config.c b/servers/slapd/back-bdb/config.c index c881bec923..b1bf856a97 100644 --- a/servers/slapd/back-bdb/config.c +++ b/servers/slapd/back-bdb/config.c @@ -14,18 +14,18 @@ int bdb_db_config( - BackendDB *be, - const char *fname, - int lineno, - int argc, - char **argv ) + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; if ( bdb == NULL ) { fprintf( stderr, "%s: line %d: " "bdb database info is null!\n", - fname, lineno ); + fname, lineno ); return 1; } @@ -34,7 +34,7 @@ bdb_db_config( if ( argc < 2 ) { fprintf( stderr, "%s: line %d: " "missing dir in \"directory \" line\n", - fname, lineno ); + fname, lineno ); return 1; } if ( bdb->bi_dbenv_home ) { @@ -47,7 +47,7 @@ bdb_db_config( if ( argc < 2 ) { fprintf( stderr, "%s: line %d: " "missing mode in \"mode \" line\n", - fname, lineno ); + fname, lineno ); return 1; } bdb->bi_dbenv_mode = strtol( argv[1], NULL, 0 ); @@ -59,13 +59,13 @@ bdb_db_config( if ( argc < 2 ) { fprintf( stderr, "%s: line %d: " "missing attr in \"index [pres,eq,approx,sub]\" line\n", - fname, lineno ); + fname, lineno ); return 1; } else if ( argc > 3 ) { fprintf( stderr, "%s: line %d: " "extra junk after \"index [pres,eq,approx,sub]\" " "line (ignored)\n", - fname, lineno ); + fname, lineno ); } rc = attr_index_config( li, fname, lineno, argc - 1, &argv[1] ); @@ -76,7 +76,7 @@ bdb_db_config( } else { fprintf( stderr, "%s: line %d: " "unknown directive \"%s\" in bdb database definition (ignored)\n", - fname, lineno, argv[0] ); + fname, lineno, argv[0] ); } return 0; diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c index 0b66029b57..2c9bf2af0c 100644 --- a/servers/slapd/back-bdb/delete.c +++ b/servers/slapd/back-bdb/delete.c @@ -15,11 +15,11 @@ int bdb_delete( - BackendDB *be, - Connection *conn, - Operation *op, - const char *dn, - const char *ndn + BackendDB *be, + Connection *conn, + Operation *op, + const char *dn, + const char *ndn ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; @@ -31,6 +31,7 @@ bdb_delete( int manageDSAit = get_manageDSAit( op ); AttributeDescription *children = slap_schema.si_ad_children; DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; Debug(LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n", dn, 0, 0); @@ -57,13 +58,62 @@ retry: rc = txn_abort( ltid ); goto return_results; } - op->o_private = ltid; + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; - pdn = dn_parent( be, e->e_ndn ); + /* get entry for read/modify/write */ + rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, DB_RMW ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if ( e == NULL ) { + char *matched_dn = NULL; + struct berval **refs = NULL; + + Debug( LDAP_DEBUG_ARGS, + "<=- bdb_delete: no such object %s\n", + dn, 0, 0); + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_entry_return( be, matched ); + } else { + refs = default_referral; + } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if ( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + + rc = -1; + goto done; + } + + pdn = dn_parent( be, ndn ); if( pdn != NULL && *pdn != '\0' ) { - /* get parent with reader lock */ - rc = dn2entry_r( be, ltid, pdn, &p, NULL ); + /* get parent */ + rc = bdb_dn2entry( be, ltid, pdn, &p, NULL, 0 ); ch_free( pdn ); @@ -116,53 +166,7 @@ retry: rc = txn_abort( ltid ); } } - /* get entry */ - rc = dn2entry_w( be, ltid, ndn, &e, &matched ); - - switch( rc ) { - case 0: - case DB_NOTFOUND: - break; - case DB_LOCK_DEADLOCK: - case DB_LOCK_NOTGRANTED: - goto retry; - default: - rc = LDAP_OTHER; - text = "internal error"; - goto return_results; - } - - if ( e == NULL ) { - char *matched_dn = NULL; - struct berval **refs = NULL; - - Debug( LDAP_DEBUG_ARGS, - "<=- bdb_delete: no such object %s\n", - dn, 0, 0); - - if ( matched != NULL ) { - matched_dn = ch_strdup( matched->e_dn ); - refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) - : NULL; - bdb_entry_return( be, matched ); - } else { - refs = default_referral; - } - - send_ldap_result( conn, op, LDAP_REFERRAL, - matched_dn, NULL, refs, NULL ); - - if ( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } - - rc = -1; - goto done; - } - - if ( !manageDSAit && is_entry_referral( e ) ) { + if ( !manageDSAit && is_entry_referral( e ) ) { /* parent is a referral, don't allow add */ /* parent is an alias, don't allow add */ struct berval **refs = get_entry_referrals( be, @@ -173,7 +177,7 @@ retry: rc = txn_abort( ltid ); 0, 0, 0 ); send_ldap_result( conn, op, LDAP_REFERRAL, - e->e_dn, NULL, refs, NULL ); + e->e_dn, NULL, refs, NULL ); ber_bvecfree( refs ); diff --git a/servers/slapd/back-bdb/dn2entry.c b/servers/slapd/back-bdb/dn2entry.c index c8a34fe55a..f0ba6c7731 100644 --- a/servers/slapd/back-bdb/dn2entry.c +++ b/servers/slapd/back-bdb/dn2entry.c @@ -19,11 +19,11 @@ int bdb_dn2entry( - BackendDB *be, + BackendDB *be, DB_TXN *tid, - const char *dn, + const char *dn, Entry **e, - Entry **matched, + Entry **matched, int flags ) { int rc; diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c index 2876f438f1..3479310f47 100644 --- a/servers/slapd/back-bdb/dn2id.c +++ b/servers/slapd/back-bdb/dn2id.c @@ -14,10 +14,10 @@ int bdb_dn2id_add( - BackendDB *be, + BackendDB *be, DB_TXN *txn, - const char *dn, - ID id + const char *dn, + ID id ) { int rc; @@ -102,10 +102,10 @@ done: int bdb_dn2id_delete( - BackendDB *be, + BackendDB *be, DB_TXN *txn, - const char *dn, - ID id ) + const char *dn, + ID id ) { int rc; DBT key; @@ -185,9 +185,9 @@ done: int bdb_dn2id( - BackendDB *be, + BackendDB *be, DB_TXN *txn, - const char *dn, + const char *dn, ID *id ) { int rc; @@ -221,9 +221,9 @@ bdb_dn2id( int bdb_dn2id_matched( - BackendDB *be, + BackendDB *be, DB_TXN *txn, - const char *in, + const char *in, ID *id, char **matchedDN ) { @@ -307,9 +307,9 @@ bdb_dn2id_matched( int bdb_dn2id_children( - BackendDB *be, + BackendDB *be, DB_TXN *txn, - const char *dn ) + const char *dn ) { int rc; DBT key, data; diff --git a/servers/slapd/back-bdb/extended.c b/servers/slapd/back-bdb/extended.c new file mode 100644 index 0000000000..04b96f823a --- /dev/null +++ b/servers/slapd/back-bdb/extended.c @@ -0,0 +1,52 @@ +/* extended.c - ldbm backend extended routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include +#include + +#include "back-bdb.h" +#include "external.h" + +struct exop { + char *oid; + SLAP_EXTENDED_FN extended; +} exop_table[] = { + { LDAP_EXOP_X_MODIFY_PASSWD, bdb_exop_passwd }, + { NULL, NULL } +}; + +int +bdb_extended( + Backend *be, + Connection *conn, + Operation *op, + const char *reqoid, + struct berval *reqdata, + char **rspoid, + struct berval **rspdata, + LDAPControl *** rspctrls, + const char** text, + struct berval *** refs +) +{ + int i; + + for( i=0; exop_table[i].oid != NULL; i++ ) { + if( strcmp( exop_table[i].oid, reqoid ) == 0 ) { + return (exop_table[i].extended)( + be, conn, op, + reqoid, reqdata, + rspoid, rspdata, rspctrls, + text, refs ); + } + } + + *text = "not supported within naming context"; + return LDAP_OPERATIONS_ERROR; +} \ No newline at end of file diff --git a/servers/slapd/back-bdb/external.h b/servers/slapd/back-bdb/external.h index db1ccac2c7..0784a7cdd3 100644 --- a/servers/slapd/back-bdb/external.h +++ b/servers/slapd/back-bdb/external.h @@ -56,11 +56,11 @@ extern int bdb_unbind LDAP_P(( BackendDB *bd, Connection *conn, Operation *op )); extern int bdb_referrals( - BackendDB *be, - Connection *conn, - Operation *op, - const char *dn, - const char *ndn, + BackendDB *be, + Connection *conn, + Operation *op, + const char *dn, + const char *ndn, const char **text ); LDAP_END_DECL diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c index 8fbff048d4..51751c230c 100644 --- a/servers/slapd/back-bdb/id2entry.c +++ b/servers/slapd/back-bdb/id2entry.c @@ -41,6 +41,35 @@ int bdb_id2entry_add( return rc; } +int bdb_id2entry_update( + BackendDB *be, + DB_TXN *tid, + Entry *e ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_id2entry->bdi_db; + DBT key, data; + struct berval *bv; + int rc; + + DBTzero( &key ); + key.data = (char *) &e->e_id; + key.size = sizeof(ID); + + rc = entry_encode( e, &bv ); + if( rc != LDAP_SUCCESS ) { + return -1; + } + + DBTzero( &data ); + bv2DBT( bv, &data ); + + rc = db->put( db, tid, &key, &data, 0 ); + + ber_bvfree( bv ); + return rc; +} + int bdb_id2entry( BackendDB *be, DB_TXN *tid, diff --git a/servers/slapd/back-bdb/idl.c b/servers/slapd/back-bdb/idl.c index 16146d12e5..acb67d6c52 100644 --- a/servers/slapd/back-bdb/idl.c +++ b/servers/slapd/back-bdb/idl.c @@ -128,11 +128,11 @@ static int idl_delete( ID *ids, ID id ) int bdb_idl_insert_key( - BackendDB *be, - DB *db, + BackendDB *be, + DB *db, DB_TXN *tid, - DBT *key, - ID id ) + DBT *key, + ID id ) { int rc; ID ids[BDB_IDL_DB_SIZE]; @@ -216,11 +216,11 @@ bdb_idl_insert_key( int bdb_idl_delete_key( - BackendDB *be, - DB *db, + BackendDB *be, + DB *db, DB_TXN *tid, - DBT *key, - ID id ) + DBT *key, + ID id ) { int rc; ID ids[BDB_IDL_DB_SIZE]; diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index 632d601aa8..77a4849280 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -242,20 +242,20 @@ bdb_db_destroy( BackendDB *be ) #ifdef SLAPD_BDB_DYNAMIC int back_bdb_LTX_init_module( int argc, char *argv[] ) { - BackendInfo bi; + BackendInfo bi; - memset( &bi, '\0', sizeof(bi) ); - bi.bi_type = "bdb"; - bi.bi_init = bdb_initialize; + memset( &bi, '\0', sizeof(bi) ); + bi.bi_type = "bdb"; + bi.bi_init = bdb_initialize; - backend_add( &bi ); - return 0; + backend_add( &bi ); + return 0; } #endif /* SLAPD_BDB_DYNAMIC */ int bdb_initialize( - BackendInfo *bi + BackendInfo *bi ) { static char *controls[] = { @@ -305,12 +305,12 @@ bdb_initialize( bi->bi_op_bind = bdb_bind; bi->bi_op_compare = bdb_compare; bi->bi_op_delete = bdb_delete; + bi->bi_op_modify = bdb_modify; + bi->bi_op_modrdn = bdb_modrdn; bi->bi_op_search = bdb_search; #if 0 bi->bi_op_unbind = bdb_unbind; - bi->bi_op_modify = bdb_modify; - bi->bi_op_modrdn = bdb_modrdn; bi->bi_op_abandon = bdb_abandon; bi->bi_extended = bdb_extended; @@ -318,8 +318,8 @@ bdb_initialize( bi->bi_acl_group = bdb_group; bi->bi_acl_attribute = bdb_attribute; - bi->bi_chk_referrals = bdb_referrals; #endif + bi->bi_chk_referrals = bdb_referrals; bi->bi_entry_release_rw = 0; diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c new file mode 100644 index 0000000000..46717f07a7 --- /dev/null +++ b/servers/slapd/back-bdb/modify.c @@ -0,0 +1,497 @@ +/* modify.c - bdb backend modify routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include +#include +#include + +#include "back-bdb.h" +#include "external.h" + +static int add_values( Entry *e, Modification *mod, char *dn ); +static int delete_values( Entry *e, Modification *mod, char *dn ); +static int replace_values( Entry *e, Modification *mod, char *dn ); + +int bdb_modify_internal( + BackendDB *be, + Connection *conn, + Operation *op, + DB_TXN *tid, + const char *dn, + Modifications *modlist, + Entry *e, + const char **text ) +{ + int rc, err; + Modification *mod; + Modifications *ml; + Attribute *save_attrs; + + Debug(LDAP_DEBUG_TRACE, "bdb_modify_internal: %s\n", dn, 0, 0); + + if ( !acl_check_modlist( be, conn, op, e, modlist )) { + return LDAP_INSUFFICIENT_ACCESS; + } + + save_attrs = e->e_attrs; + e->e_attrs = attrs_dup( e->e_attrs ); + + for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { + mod = &ml->sml_mod; + + switch ( mod->sm_op ) { + case LDAP_MOD_ADD: + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: add\n", 0, 0, 0); + err = add_values( e, mod, op->o_ndn ); + + if( err != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); + *text = "modify: add values failed"; + } + break; + + case LDAP_MOD_DELETE: + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: delete\n", 0, 0, 0); + err = delete_values( e, mod, op->o_ndn ); + assert( err != LDAP_TYPE_OR_VALUE_EXISTS ); + if( err != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); + *text = "modify: delete values failed"; + } + break; + + case LDAP_MOD_REPLACE: + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: replace\n", 0, 0, 0); + err = replace_values( e, mod, op->o_ndn ); + assert( err != LDAP_TYPE_OR_VALUE_EXISTS ); + if( err != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); + *text = "modify: replace values failed"; + } + break; + + case SLAP_MOD_SOFTADD: + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: softadd\n", 0, 0, 0); + /* Avoid problems in index_add_mods() + * We need to add index if necessary. + */ + mod->sm_op = LDAP_MOD_ADD; + err = add_values( e, mod, op->o_ndn ); + + if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { + err = LDAP_SUCCESS; + } + + if( err != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); + *text = "modify: (soft)add values failed"; + } + break; + + default: + Debug(LDAP_DEBUG_ANY, "bdb_modify_internal: invalid op %d\n", + mod->sm_op, 0, 0); + *text = "Invalid modify operation"; + err = LDAP_OTHER; + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); + } + + if ( err != LDAP_SUCCESS ) { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; + /* unlock entry, delete from cache */ + return err; + } + } + + /* check that the entry still obeys the schema */ + rc = entry_schema_check( e, save_attrs, text ); + if ( rc != LDAP_SUCCESS ) { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; + Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n", + *text, 0, 0 ); + return rc; + } + +#if 0 + /* delete indices for old attributes */ + rc = index_entry_del( be, tid, e, save_attrs); + + /* add indices for new attributes */ + rc = index_entry_add( be, tid, e, e->e_attrs); +#endif + + attrs_free( save_attrs ); + + return rc; +} + + +int +bdb_modify( + BackendDB *be, + Connection *conn, + Operation *op, + const char *dn, + const char *ndn, + Modifications *modlist +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + Entry *matched; + Entry *e; + int manageDSAit = get_manageDSAit( op ); + const char *text = NULL; + DB_TXN *ltid; + struct bdb_op_info opinfo; + + Debug(LDAP_DEBUG_ARGS, "bdb_back_modify: %s\n", dn, 0, 0); + + if (0) { + /* transaction retry */ +retry: rc = txn_abort( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + } + + /* begin transaction */ + rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + /* get entry */ + rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, 0 ); + + if ( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: dn2entry failed (%d)\n", + rc, 0, 0 ); + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + case DB_NOTFOUND: + break; + default: + rc = LDAP_OTHER; + } + text = "internal error"; + goto return_results; + } + + /* acquire and lock entry */ + if ( e == NULL ) { + char* matched_dn = NULL; + struct berval **refs = NULL; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_entry_return( be, matched ); + + } else { + refs = default_referral; + } + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if ( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + + return rc; + } + + if ( !manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: entry is referral\n", + 0, 0, 0 ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + goto done; + } + + /* Modify the entry */ + rc = bdb_modify_internal( be, conn, op, ltid, ndn, modlist, e, &text ); + + if( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: modify failed (%d)\n", + rc, 0, 0 ); + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + goto return_results; + } + + /* change the entry itself */ + rc = bdb_id2entry_update( be, ltid, e ); + if ( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: id2entry update failed (%d)\n", + rc, 0, 0 ); + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + text = "entry update failed"; + goto return_results; + } + + rc = txn_commit( ltid, 0 ); + ltid = NULL; + op->o_private = NULL; + + if( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: txn_commit failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + rc = LDAP_OTHER; + text = "commit failed"; + } else { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: added id=%08x dn=\"%s\"\n", + e->e_id, e->e_dn, 0 ); + rc = LDAP_SUCCESS; + text = NULL; + } + +return_results: + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + +done: + if( ltid != NULL ) { + txn_abort( ltid ); + op->o_private = NULL; + } + + bdb_entry_return( be, e ); + return rc; +} + +static int +add_values( + Entry *e, + Modification *mod, + char *dn +) +{ + int i; + Attribute *a; + + /* char *desc = mod->sm_desc->ad_cname->bv_val; */ + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + + a = attr_find( e->e_attrs, mod->sm_desc ); + + /* check if the values we're adding already exist */ + if ( a != NULL ) { + if( mr == NULL || !mr->smr_match ) { + /* do not allow add of additional attribute + if no equality rule exists */ + return LDAP_INAPPROPRIATE_MATCHING; + } + + for ( i = 0; mod->sm_bvalues[i] != NULL; i++ ) { + int rc; + int j; + const char *text = NULL; + struct berval *asserted; + + rc = value_normalize( mod->sm_desc, + SLAP_MR_EQUALITY, + mod->sm_bvalues[i], + &asserted, + &text ); + + if( rc != LDAP_SUCCESS ) return rc; + + for ( j = 0; a->a_vals[j] != NULL; j++ ) { + int match; + int rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_MODIFY_MATCHING, + a->a_vals[j], asserted, &text ); + + if( rc == LDAP_SUCCESS && match == 0 ) { + ber_bvfree( asserted ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + + ber_bvfree( asserted ); + } + } + + /* no - add them */ + if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) { + /* this should return result return of attr_merge */ + return LDAP_OTHER; + } + + return LDAP_SUCCESS; +} + +static int +delete_values( + Entry *e, + Modification *mod, + char *dn +) +{ + int i, j, k, found; + Attribute *a; + char *desc = mod->sm_desc->ad_cname->bv_val; + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + + /* delete the entire attribute */ + if ( mod->sm_bvalues == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify_delete: removing entire attribute %s\n", + desc, 0, 0 ); + return attr_delete( &e->e_attrs, mod->sm_desc ) + ? LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS; + } + + if( mr == NULL || !mr->smr_match ) { + /* disallow specific attributes from being deleted if + no equality rule */ + return LDAP_INAPPROPRIATE_MATCHING; + } + + /* delete specific values - find the attribute first */ + if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify_delete: could not find attribute %s\n", + desc, 0, 0 ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + + /* find each value to delete */ + for ( i = 0; mod->sm_bvalues[i] != NULL; i++ ) { + int rc; + const char *text = NULL; + + struct berval *asserted; + + rc = value_normalize( mod->sm_desc, + SLAP_MR_EQUALITY, + mod->sm_bvalues[i], + &asserted, + &text ); + + if( rc != LDAP_SUCCESS ) return rc; + + found = 0; + for ( j = 0; a->a_vals[j] != NULL; j++ ) { + int match; + int rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_MODIFY_MATCHING, + a->a_vals[j], asserted, &text ); + + if( rc == LDAP_SUCCESS && match != 0 ) { + continue; + } + + /* found a matching value */ + found = 1; + + /* delete it */ + ber_bvfree( a->a_vals[j] ); + for ( k = j + 1; a->a_vals[k] != NULL; k++ ) { + a->a_vals[k - 1] = a->a_vals[k]; + } + a->a_vals[k - 1] = NULL; + + break; + } + + ber_bvfree( asserted ); + + /* looked through them all w/o finding it */ + if ( ! found ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify_delete: could not find value for attr %s\n", + desc, 0, 0 ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + } + + /* if no values remain, delete the entire attribute */ + if ( a->a_vals[0] == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modify_delete: removing entire attribute %s\n", + desc, 0, 0 ); + if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { + return LDAP_NO_SUCH_ATTRIBUTE; + } + } + + return LDAP_SUCCESS; +} + +static int +replace_values( + Entry *e, + Modification *mod, + char *dn +) +{ + int rc = attr_delete( &e->e_attrs, mod->sm_desc ); + + if( rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE ) { + return rc; + } + + if ( mod->sm_bvalues != NULL && + attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) + { + return LDAP_OTHER; + } + + return LDAP_SUCCESS; +} diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c new file mode 100644 index 0000000000..456f1b49e2 --- /dev/null +++ b/servers/slapd/back-bdb/modrdn.c @@ -0,0 +1,534 @@ +/* modrdn.c - bdb backend modrdn routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include +#include + +#include "back-bdb.h" +#include "external.h" + +int +bdb_modrdn( + Backend *be, + Connection *conn, + Operation *op, + const char *dn, + const char *ndn, + const char *newrdn, + int deleteoldrdn, + const char *newSuperior +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + AttributeDescription *children = slap_schema.si_ad_children; + char *p_dn = NULL, *p_ndn = NULL; + char *new_dn = NULL, *new_ndn = NULL; + Entry *e, *p = NULL; + Entry *matched; + int rc; + const char *text = NULL; + DB_TXN * ltid; + struct bdb_op_info opinfo; + + ID id; + char *new_rdn_val = NULL; /* Val of new rdn */ + char *new_rdn_type = NULL; /* Type of new rdn */ + char *old_rdn = NULL; /* Old rdn's attr type & val */ + char *old_rdn_type = NULL; /* Type of old rdn attr. */ + char *old_rdn_val = NULL; /* Old rdn attribute value */ + + Entry *np = NULL; /* newSuperior Entry */ + char *np_dn = NULL; /* newSuperior dn */ + char *np_ndn = NULL; /* newSuperior ndn */ + char *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */ + + /* Used to interface with bdb_modify_internal() */ + struct berval add_bv; /* Stores new rdn att */ + struct berval *add_bvals[2]; /* Stores new rdn att */ + struct berval del_bv; /* Stores old rdn att */ + struct berval *del_bvals[2]; /* Stores old rdn att */ + Modifications mod[2]; /* Used to delete old rdn */ + + int manageDSAit = get_manageDSAit( op ); + + Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n", + dn, newrdn, (newSuperior ? newSuperior : "NULL") ); + + if (0) { + /* transaction retry */ +retry: rc = txn_abort( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + } + + /* begin transaction */ + rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_delete: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + /* get entry */ + rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if ( e == NULL ) { + char* matched_dn = NULL; + struct berval** refs = NULL; + + if( matched != NULL ) { + matched_dn = strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_entry_return( be, matched ); + } else { + refs = default_referral; + } + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if ( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + + goto done; + } + + if (!manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n", + 0, 0, 0 ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + goto done; + } + + p_ndn = dn_parent( be, e->e_ndn ); + if ( p_ndn != NULL ) { + /* Make sure parent entry exist and we can write its + * children. + */ + + rc = bdb_dn2entry( be, ltid, p_ndn, &p, NULL, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if( p == NULL) { + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n", + 0, 0, 0); + rc = LDAP_OTHER; + goto return_results; + } + + /* check parent for "children" acl */ + if ( ! access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE ) ) + { + Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to children of entry %s OK\n", + p_ndn, 0, 0 ); + + p_dn = dn_parent( be, e->e_dn ); + + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: parent dn=%s\n", + p_dn, 0, 0 ); + + } else { + /* no parent, modrdn entry directly under root */ + if( ! be_isroot( be, op->o_ndn ) ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: no parent & not root\n", + 0, 0, 0); + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: no parent, locked root\n", + 0, 0, 0 ); + } + + new_parent_dn = p_dn; /* New Parent unless newSuperior given */ + + if ( newSuperior != NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new parent \"%s\" requested...\n", + newSuperior, 0, 0 ); + + np_dn = ch_strdup( newSuperior ); + np_ndn = ch_strdup( np_dn ); + (void) dn_normalize( np_ndn ); + + /* newSuperior == oldParent?, if so ==> ERROR */ + /* newSuperior == entry being moved?, if so ==> ERROR */ + /* Get Entry with dn=newSuperior. Does newSuperior exist? */ + + rc = bdb_dn2entry( be, ltid, np_ndn, &np, NULL, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if( np == NULL) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: newSup(ndn=%s) not here!\n", + np_ndn, 0, 0); + rc = LDAP_OTHER; + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", + np, np->e_id, 0 ); + + /* check newSuperior for "children" acl */ + if ( !access_allowed( be, conn, op, np, children, NULL, ACL_WRITE ) ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: no wr to newSup children\n", + 0, 0, 0 ); + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + if ( is_entry_alias( np ) ) { + /* entry is an alias, don't allow bind */ + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n", + 0, 0, 0 ); + + rc = LDAP_ALIAS_PROBLEM; + goto return_results; + } + + if ( is_entry_referral( np ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n", + 0, 0, 0 ); + + rc = LDAP_OPERATIONS_ERROR; + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to new parent's children OK\n", + 0, 0, 0 ); + + new_parent_dn = np_dn; + } + + /* Build target dn and make sure target entry doesn't exist already. */ + build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn ); + + new_ndn = ch_strdup(new_dn); + (void) dn_normalize( new_ndn ); + + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n", + new_ndn, 0, 0 ); + + rc = bdb_dn2id ( be, ltid, new_ndn, &id ); + if( rc != 0 ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + } + + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new ndn=%s does not exist\n", + new_ndn, 0, 0 ); + + /* Get attribute type and attribute value of our new rdn, we will + * need to add that to our new entry + */ + + new_rdn_type = rdn_attr_type( newrdn ); + if ( new_rdn_type == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: can't figure out type of newrdn\n", + 0, 0, 0 ); + rc = LDAP_OPERATIONS_ERROR; + text = "unknown type used in RDN"; + goto return_results; + } + + new_rdn_val = rdn_attr_value( newrdn ); + if ( new_rdn_val == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: could not figure out val of newrdn\n", + 0, 0, 0 ); + rc = LDAP_OPERATIONS_ERROR; + text = "could not parse RDN value"; + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n", + new_rdn_val, new_rdn_type, 0 ); + + /* Retrieve the old rdn from the entry's dn */ + + if ( (old_rdn = dn_rdn( be, dn )) == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: can't figure out old_rdn from dn\n", + 0, 0, 0 ); + rc = LDAP_OTHER; + text = "could not parse old DN"; + goto return_results; + } + + if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_back_modrdn: can't figure out the old_rdn type\n", + 0, 0, 0 ); + rc = LDAP_OTHER; + text = "cannot parse RDN from old DN"; + goto return_results; + } + + if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) { + /* Not a big deal but we may say something */ + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n", + old_rdn_type, new_rdn_type, 0 ); + } + + /* Add new attribute value to the entry */ + add_bvals[0] = &add_bv; /* Array of bervals */ + add_bvals[1] = NULL; + + add_bv.bv_val = new_rdn_val; + add_bv.bv_len = strlen(new_rdn_val); + + mod[0].sml_desc = NULL; + rc = slap_str2ad( new_rdn_type, &mod[0].sml_desc, &text ); + + if( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: %s: %s (new)\n", + text, new_rdn_type, 0 ); + goto return_results; + } + mod[0].sml_bvalues = add_bvals; + mod[0].sml_op = SLAP_MOD_SOFTADD; + mod[0].sml_next = NULL; + + /* Remove old rdn value if required */ + + if (deleteoldrdn) { + /* Get value of old rdn */ + old_rdn_val = rdn_attr_value( old_rdn ); + if ( old_rdn_val == NULL) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: can't figure out old_rdn_val from old_rdn\n", + 0, 0, 0 ); + rc = LDAP_OTHER; + text = "could not parse value from old RDN"; + goto return_results; + } + + del_bvals[0] = &del_bv; /* Array of bervals */ + del_bvals[1] = NULL; + + /* Remove old value of rdn as an attribute. */ + del_bv.bv_val = old_rdn_val; + del_bv.bv_len = strlen(old_rdn_val); + + mod[1].sml_desc = NULL; + rc = slap_str2ad( old_rdn_type, &mod[1].sml_desc, &text ); + + if( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: %s: %s (old)\n", + text, old_rdn_type, 0 ); + goto return_results; + } + + mod[0].sml_next = &mod[1]; + mod[1].sml_bvalues = del_bvals; + mod[1].sml_op = LDAP_MOD_DELETE; + mod[1].sml_next = NULL; + } + + /* delete old one */ + rc = bdb_dn2id_delete( be, ltid, e->e_ndn, e->e_id ); + if ( rc != 0 ) { + rc = LDAP_OTHER; + text = "DN index delete fail"; + goto return_results; + } + + free( e->e_dn ); + free( e->e_ndn ); + e->e_dn = new_dn; + e->e_ndn = new_ndn; + new_dn = NULL; + new_ndn = NULL; + + /* add new one */ + rc = bdb_dn2id_add( be, ltid, e->e_ndn, e->e_id ); + if ( rc != 0 ) { + rc = LDAP_OTHER; + text = "DN index add failed"; + goto return_results; + } + + /* modify entry */ + rc = bdb_modify_internal( be, conn, op, ltid, dn, &mod[0], e, &text ); + + if( rc != LDAP_SUCCESS ) { + goto return_results; + } + + /* NOTE: after this you must not free new_dn or new_ndn! + * They are used by cache. + */ + + /* id2entry index */ + rc = bdb_id2entry_add( be, ltid, e ); + if ( rc != 0 ) { + rc = LDAP_OTHER; + text = "entry update failed"; + goto return_results; + } + + rc = LDAP_SUCCESS; + + rc = txn_commit( ltid, 0 ); + ltid = NULL; + op->o_private = NULL; + + if( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: txn_commit failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + rc = LDAP_OTHER; + text = "commit failed"; + } else { + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: added id=%08x dn=\"%s\"\n", + e->e_id, e->e_dn, 0 ); + rc = LDAP_SUCCESS; + text = NULL; + } + +return_results: + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + +done: + if( new_dn != NULL ) free( new_dn ); + if( new_ndn != NULL ) free( new_ndn ); + + if( p_dn != NULL ) free( p_dn ); + if( p_ndn != NULL ) free( p_ndn ); + + /* LDAP v2 supporting correct attribute handling. */ + if( new_rdn_type != NULL ) free(new_rdn_type); + if( new_rdn_val != NULL ) free(new_rdn_val); + if( old_rdn != NULL ) free(old_rdn); + if( old_rdn_type != NULL ) free(old_rdn_type); + if( old_rdn_val != NULL ) free(old_rdn_val); + + + /* LDAP v3 Support */ + if ( np_dn != NULL ) free( np_dn ); + if ( np_ndn != NULL ) free( np_ndn ); + + if( np != NULL ) { + /* free new parent and writer lock */ + bdb_entry_return( be, np ); + } + + if( p != NULL ) { + /* free parent and writer lock */ + bdb_entry_return( be, p ); + } + + /* free entry */ + if( e != NULL ) { + bdb_entry_return( be, e ); + } + + if( ltid != NULL ) { + txn_abort( ltid ); + op->o_private = NULL; + } + + return rc; +} diff --git a/servers/slapd/back-bdb/passwd.c b/servers/slapd/back-bdb/passwd.c index 1639a62979..2731bd5a73 100644 --- a/servers/slapd/back-bdb/passwd.c +++ b/servers/slapd/back-bdb/passwd.c @@ -15,23 +15,23 @@ int bdb_exop_passwd( - Backend *be, - Connection *conn, - Operation *op, + Backend *be, + Connection *conn, + Operation *op, const char *reqoid, - struct berval *reqdata, + struct berval *reqdata, char **rspoid, - struct berval **rspdata, + struct berval **rspdata, LDAPControl *** rspctrls, const char **text, - struct berval *** refs -) + struct berval *** refs ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; Entry *e = NULL; struct berval *hash = NULL; - DB_TXN *ltid; + DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; struct berval *id = NULL; struct berval *new = NULL; @@ -82,17 +82,48 @@ bdb_exop_passwd( goto done; } - /* fetch entry */ - rc = dn2entry_w( be, NULL, dn, &e, NULL ); + if (0) { + /* transaction retry */ +retry: rc = txn_abort( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + *text = "internal error"; + goto done; + } + } + + /* begin transaction */ + rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_exop_passwd: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + rc = LDAP_OTHER; + *text = "internal error"; + goto done; + } + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + /* get entry */ + rc = bdb_dn2entry( be, ltid, dn, &e, NULL, 0 ); switch(rc) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; case DB_NOTFOUND: case 0: break; default: - send_ldap_result( conn, op, rc=LDAP_OTHER, - NULL, "internal error", NULL, NULL ); - return rc; + rc = LDAP_OTHER; + *text = "internal error"; + goto done; } if( e == NULL ) { @@ -108,11 +139,11 @@ bdb_exop_passwd( goto done; } - rc = LDAP_OPERATIONS_ERROR; if( is_entry_referral( e ) ) { /* entry is an referral, don't allow operation */ *text = "authorization entry is referral"; + rc = LDAP_OPERATIONS_ERROR; goto done; } @@ -128,19 +159,39 @@ bdb_exop_passwd( ml.sml_op = LDAP_MOD_REPLACE; ml.sml_next = NULL; - rc = bdb_modify_internal( be, - conn, op, op->o_ndn, &ml, e, text ); + rc = bdb_modify_internal( be, conn, op, ltid, + op->o_ndn, &ml, e, text ); + + switch(rc) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + bdb_entry_return( be, e ); + e = NULL; + goto retry; + case 0: + break; + default: + rc = LDAP_OTHER; + *text = "entry modify failed"; + goto done; + } } - if( rc == LDAP_SUCCESS ) { - /* change the entry itself */ - if( bdb_id2entry_add( be, ltid, e ) != 0 ) { - *text = "entry update failed"; - rc = LDAP_OTHER; + /* change the entry itself */ + rc = bdb_id2entry_update( be, ltid, e ); + if( rc != 0 ) { + switch(rc) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + bdb_entry_return( be, e ); + goto retry; } + *text = "entry update failed"; + rc = LDAP_OTHER; + goto done; } - + done: if( e != NULL ) { bdb_entry_return( be, e ); @@ -158,5 +209,10 @@ done: ber_bvfree( hash ); } + if( ltid != NULL ) { + txn_abort( ltid ); + op->o_private = NULL; + } + return rc; } diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index 111b51685d..e4cc6e11fd 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -31,12 +31,6 @@ Entry *bdb_deref_internal_r LDAP_P(( int bdb_dn2entry LDAP_P(( BackendDB *be, DB_TXN *tid, const char *dn, Entry **e, Entry **matched, int flags )); -#define dn2entry_r(be, tid, dn, p, m) \ - bdb_dn2entry((be), (tid), (dn), (p), (m), 0 ) - -#define dn2entry_w(be, tid, dn, p, m) \ - bdb_dn2entry((be), (tid), (dn), (p), (m), DB_RMW ) - /* * dn2id.c */ @@ -88,6 +82,11 @@ int bdb_id2entry_add( DB_TXN *tid, Entry *e ); +int bdb_id2entry_update( + BackendDB *be, + DB_TXN *tid, + Entry *e ); + int bdb_id2entry_delete( BackendDB *be, DB_TXN *tid, @@ -123,6 +122,35 @@ int bdb_idl_delete_key( */ int bdb_next_id( BackendDB *be, DB_TXN *tid, ID *id ); +/* + * modify.c + */ +int bdb_modify_internal( + BackendDB *be, + Connection *conn, + Operation *op, + DB_TXN *tid, + const char *dn, + Modifications *modlist, + Entry *e, + const char **text ); + +/* + * passwd.c + */ +int +bdb_exop_passwd( + Backend *be, + Connection *conn, + Operation *op, + const char *reqoid, + struct berval *reqdata, + char **rspoid, + struct berval **rspdata, + LDAPControl *** rspctrls, + const char **text, + struct berval *** refs ); + /* * tools.c */ diff --git a/servers/slapd/back-bdb/referral.c b/servers/slapd/back-bdb/referral.c index ef8e5d7ca1..f4e2a08c70 100644 --- a/servers/slapd/back-bdb/referral.c +++ b/servers/slapd/back-bdb/referral.c @@ -14,11 +14,11 @@ int bdb_referrals( - BackendDB *be, - Connection *conn, - Operation *op, - const char *dn, - const char *ndn, + BackendDB *be, + Connection *conn, + Operation *op, + const char *dn, + const char *ndn, const char **text ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; @@ -35,8 +35,8 @@ bdb_referrals( return rc; } - /* fetch entry */ - rc = dn2entry_r( be, NULL, ndn, &e, &matched ); + /* get entry */ + rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 ); switch(rc) { case DB_NOTFOUND: @@ -44,7 +44,7 @@ bdb_referrals( break; default: send_ldap_result( conn, op, rc=LDAP_OTHER, - NULL, "internal error", NULL, NULL ); + NULL, "internal error", NULL, NULL ); return rc; } @@ -91,7 +91,7 @@ bdb_referrals( if( refs != NULL ) { send_ldap_result( conn, op, rc = LDAP_REFERRAL, - e->e_dn, NULL, refs, NULL ); + e->e_dn, NULL, refs, NULL ); } ber_bvecfree( refs ); diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 78a16e48a8..9ae8746ec9 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -14,14 +14,14 @@ #include "external.h" static int base_candidate( - BackendDB *be, + BackendDB *be, Entry *e, ID *ids ); static int search_candidates( BackendDB *be, Entry *e, Filter *filter, - int scope, + int scope, int deref, int manageDSAit, ID *ids ); @@ -31,19 +31,19 @@ static ID idl_next( ID *ids, ID *cursor ); int bdb_search( - BackendDB *be, - Connection *conn, - Operation *op, - const char *base, - const char *nbase, - int scope, - int deref, - int slimit, - int tlimit, - Filter *filter, - const char *filterstr, - char **attrs, - int attrsonly ) + BackendDB *be, + Connection *conn, + Operation *op, + const char *base, + const char *nbase, + int scope, + int deref, + int slimit, + int tlimit, + Filter *filter, + const char *filterstr, + char **attrs, + int attrsonly ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int abandon; @@ -72,8 +72,7 @@ bdb_search( } else #endif { - /* obtain entry */ - rc = dn2entry_r( be, NULL, nbase, &e, &matched ); + rc = bdb_dn2entry( be, NULL, nbase, &e, &matched, 0 ); } switch(rc) { @@ -82,7 +81,7 @@ bdb_search( break; default: send_ldap_result( conn, op, rc=LDAP_OTHER, - NULL, "internal error", NULL, NULL ); + NULL, "internal error", NULL, NULL ); return rc; } @@ -125,7 +124,7 @@ bdb_search( 0, 0, 0 ); send_ldap_result( conn, op, LDAP_REFERRAL, - matched_dn, NULL, refs, NULL ); + matched_dn, NULL, refs, NULL ); ber_bvecfree( refs ); free( matched_dn ); @@ -137,7 +136,7 @@ bdb_search( tlimit = -1; /* allow root to set no limit */ } else { tlimit = (tlimit > be->be_timelimit || tlimit < 1) ? - be->be_timelimit : tlimit; + be->be_timelimit : tlimit; stoptime = op->o_time + tlimit; } @@ -145,7 +144,7 @@ bdb_search( slimit = -1; /* allow root to set no limit */ } else { slimit = (slimit > be->be_sizelimit || slimit < 1) ? - be->be_sizelimit : slimit; + be->be_sizelimit : slimit; } if ( scope == LDAP_SCOPE_BASE ) { @@ -153,7 +152,7 @@ bdb_search( } else { rc = search_candidates( be, e, filter, - scope, deref, manageDSAit, candidates ); + scope, deref, manageDSAit, candidates ); } /* need normalized dn below */ @@ -178,7 +177,7 @@ bdb_search( for ( id = idl_first( candidates, &cursor ); id != NOID; - id = idl_next( candidates, &cursor ) ) + id = idl_next( candidates, &cursor ) ) { int scopeok = 0; @@ -357,7 +356,7 @@ done: static int base_candidate( - BackendDB *be, + BackendDB *be, Entry *e, ID *ids ) { @@ -373,20 +372,72 @@ static int search_candidates( BackendDB *be, Entry *e, Filter *filter, - int scope, + int scope, int deref, int manageDSAit, ID *ids ) { - Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" (0x%08lx)\n", - e->e_dn, (long) e->e_id, 0); + int rc; + Filter f, fand, rf, af, xf; + AttributeAssertion aa_ref, aa_alias; + + Debug(LDAP_DEBUG_TRACE, + "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", + e->e_dn, (long) e->e_id, scope ); + + xf.f_or = filter; + xf.f_choice = LDAP_FILTER_OR; + xf.f_next = NULL; + + if( !manageDSAit ) { + /* match referrals */ + static struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" }; + rf.f_choice = LDAP_FILTER_EQUALITY; + rf.f_ava = &aa_ref; + rf.f_av_desc = slap_schema.si_ad_objectClass; + rf.f_av_value = &bv_ref; + rf.f_next = xf.f_or; + xf.f_or = &rf; + } + +#ifdef BDB_ALIASES + if( deref & LDAP_DEREF_SEARCHING ) { + /* match aliases */ + static struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" }; + af.f_choice = LDAP_FILTER_EQUALITY; + af.f_ava = &aa_alias; + af.f_av_desc = slap_schema.si_ad_objectClass; + af.f_av_value = &bv_alias; + af.f_next = xf.f_or; + xf.f_or = ⁡ + } +#endif - /* return a RANGE IDL for now */ + f.f_next = NULL; + f.f_choice = LDAP_FILTER_AND; + f.f_and = &fand; + fand.f_choice = scope == LDAP_SCOPE_SUBTREE + ? SLAPD_FILTER_DN_SUBTREE + : SLAPD_FILTER_DN_ONE; + fand.f_dn = e->e_ndn; + fand.f_next = xf.f_or == filter ? filter : &xf ; + +#if 0 + rc = bdb_filter_candidates( be, &f, ids ); +#else + /* a quick hack */ ids[0] = NOID; ids[1] = e->e_id; ids[2] = e->e_id+128; + rc = 0; +#endif - return 0; + Debug(LDAP_DEBUG_TRACE, + "search_candidates: id=%ld first=%ld last=%ld\n", + ids[0], ids[1], + BDB_IDL_IS_RANGE( ids ) ? ids[2] : ids[ids[0]] ); + + return rc; } static ID idl_first( ID *ids, ID *cursor )