Back to index

openldap  2.4.31
delete.cpp
Go to the documentation of this file.
00001 /* delete.cpp - ndb backend delete routine */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2008-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was initially developed by Howard Chu for inclusion
00018  * in OpenLDAP Software. This work was sponsored by MySQL.
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #include <stdio.h>
00024 #include <ac/string.h>
00025 
00026 #include "lutil.h"
00027 #include "back-ndb.h"
00028 
00029 static struct berval glue_bv = BER_BVC("glue");
00030 
00031 int
00032 ndb_back_delete( Operation *op, SlapReply *rs )
00033 {
00034        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
00035        Entry  e = {0};
00036        Entry  p = {0};
00037        int           manageDSAit = get_manageDSAit( op );
00038        AttributeDescription *children = slap_schema.si_ad_children;
00039        AttributeDescription *entry = slap_schema.si_ad_entry;
00040 
00041        NdbArgs NA;
00042        NdbRdns rdns;
00043        struct berval matched;
00044 
00045        int    num_retries = 0;
00046 
00047        int     rc;
00048 
00049        LDAPControl **preread_ctrl = NULL;
00050        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
00051        int num_ctrls = 0;
00052 
00053        Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(ndb_back_delete) ": %s\n",
00054               op->o_req_dn.bv_val, 0, 0 );
00055 
00056        ctrls[num_ctrls] = 0;
00057 
00058        /* allocate CSN */
00059        if ( BER_BVISNULL( &op->o_csn ) ) {
00060               struct berval csn;
00061               char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
00062 
00063               csn.bv_val = csnbuf;
00064               csn.bv_len = sizeof(csnbuf);
00065               slap_get_csn( op, &csn, 1 );
00066        }
00067 
00068        if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
00069               dnParent( &op->o_req_dn, &p.e_name );
00070               dnParent( &op->o_req_ndn, &p.e_nname );
00071        }
00072 
00073        /* Get our NDB handle */
00074        rs->sr_err = ndb_thread_handle( op, &NA.ndb );
00075        rdns.nr_num = 0;
00076        NA.rdns = &rdns;
00077        NA.ocs = NULL;
00078        NA.e = &e;
00079        e.e_name = op->o_req_dn;
00080        e.e_nname = op->o_req_ndn;
00081 
00082        if( 0 ) {
00083 retry: /* transaction retry */
00084               NA.txn->close();
00085               NA.txn = NULL;
00086               Debug( LDAP_DEBUG_TRACE,
00087                      "==> " LDAP_XSTRING(ndb_back_delete) ": retrying...\n",
00088                      0, 0, 0 );
00089               if ( op->o_abandon ) {
00090                      rs->sr_err = SLAPD_ABANDON;
00091                      goto return_results;
00092               }
00093               if ( NA.ocs ) {
00094                      ber_bvarray_free( NA.ocs );
00095                      NA.ocs = NULL;
00096               }
00097               ndb_trans_backoff( ++num_retries );
00098        }
00099 
00100        /* begin transaction */
00101        NA.txn = NA.ndb->startTransaction();
00102        rs->sr_text = NULL;
00103        if( !NA.txn ) {
00104               Debug( LDAP_DEBUG_TRACE,
00105                      LDAP_XSTRING(ndb_back_delete) ": startTransaction failed: %s (%d)\n",
00106                      NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
00107               rs->sr_err = LDAP_OTHER;
00108               rs->sr_text = "internal error";
00109               goto return_results;
00110        }
00111 
00112        /* get entry */
00113        rs->sr_err = ndb_entry_get_info( op, &NA, 1, &matched );
00114        switch( rs->sr_err ) {
00115        case 0:
00116        case LDAP_NO_SUCH_OBJECT:
00117               break;
00118 #if 0
00119        case DB_LOCK_DEADLOCK:
00120        case DB_LOCK_NOTGRANTED:
00121               goto retry;
00122 #endif
00123        case LDAP_BUSY:
00124               rs->sr_text = "ldap server busy";
00125               goto return_results;
00126        default:
00127               rs->sr_err = LDAP_OTHER;
00128               rs->sr_text = "internal error";
00129               goto return_results;
00130        }
00131 
00132        if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ||
00133               ( !manageDSAit && bvmatch( NA.ocs, &glue_bv ))) {
00134               Debug( LDAP_DEBUG_ARGS,
00135                      "<=- " LDAP_XSTRING(ndb_back_delete) ": no such object %s\n",
00136                      op->o_req_dn.bv_val, 0, 0);
00137 
00138               if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
00139                      rs->sr_matched = matched.bv_val;
00140                      if ( NA.ocs )
00141                             ndb_check_referral( op, rs, &NA );
00142               } else {
00143                      rs->sr_matched = p.e_name.bv_val;
00144                      rs->sr_err = LDAP_NO_SUCH_OBJECT;
00145               }
00146               goto return_results;
00147        }
00148 
00149        /* check parent for "children" acl */
00150        rs->sr_err = access_allowed( op, &p,
00151               children, NULL, ACL_WDEL, NULL );
00152 
00153        if ( !rs->sr_err  ) {
00154               Debug( LDAP_DEBUG_TRACE,
00155                      "<=- " LDAP_XSTRING(ndb_back_delete) ": no write "
00156                      "access to parent\n", 0, 0, 0 );
00157               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00158               rs->sr_text = "no write access to parent";
00159               goto return_results;
00160        }
00161 
00162        rs->sr_err = ndb_entry_get_data( op, &NA, 1 );
00163 
00164        rs->sr_err = access_allowed( op, &e,
00165               entry, NULL, ACL_WDEL, NULL );
00166 
00167        if ( !rs->sr_err  ) {
00168               Debug( LDAP_DEBUG_TRACE,
00169                      "<=- " LDAP_XSTRING(ndb_back_delete) ": no write access "
00170                      "to entry\n", 0, 0, 0 );
00171               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00172               rs->sr_text = "no write access to entry";
00173               goto return_results;
00174        }
00175 
00176        if ( !manageDSAit && is_entry_referral( &e ) ) {
00177               /* entry is a referral, don't allow delete */
00178               rs->sr_ref = get_entry_referrals( op, &e );
00179 
00180               Debug( LDAP_DEBUG_TRACE,
00181                      LDAP_XSTRING(ndb_back_delete) ": entry is referral\n",
00182                      0, 0, 0 );
00183 
00184               rs->sr_err = LDAP_REFERRAL;
00185               rs->sr_matched = e.e_name.bv_val;
00186               rs->sr_flags = REP_REF_MUSTBEFREED;
00187               goto return_results;
00188        }
00189 
00190        if ( get_assert( op ) &&
00191               ( test_filter( op, &e, (Filter *)get_assertion( op )) != LDAP_COMPARE_TRUE ))
00192        {
00193               rs->sr_err = LDAP_ASSERTION_FAILED;
00194               goto return_results;
00195        }
00196 
00197        /* pre-read */
00198        if( op->o_preread ) {
00199               if( preread_ctrl == NULL ) {
00200                      preread_ctrl = &ctrls[num_ctrls++];
00201                      ctrls[num_ctrls] = NULL;
00202               }
00203               if( slap_read_controls( op, rs, &e,
00204                      &slap_pre_read_bv, preread_ctrl ) )
00205               {
00206                      Debug( LDAP_DEBUG_TRACE,
00207                             "<=- " LDAP_XSTRING(ndb_back_delete) ": pre-read "
00208                             "failed!\n", 0, 0, 0 );
00209                      if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
00210                             /* FIXME: is it correct to abort
00211                              * operation if control fails? */
00212                             goto return_results;
00213                      }
00214               }
00215        }
00216 
00217        /* Can't do it if we have kids */
00218        rs->sr_err = ndb_has_children( &NA, &rc );
00219        if ( rs->sr_err ) {
00220               Debug(LDAP_DEBUG_ARGS,
00221                      "<=- " LDAP_XSTRING(ndb_back_delete)
00222                      ": has_children failed: %s (%d)\n",
00223                      NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 );
00224               rs->sr_err = LDAP_OTHER;
00225               rs->sr_text = "internal error";
00226               goto return_results;
00227        }
00228        if ( rc == LDAP_COMPARE_TRUE ) {
00229               Debug(LDAP_DEBUG_ARGS,
00230                      "<=- " LDAP_XSTRING(ndb_back_delete)
00231                      ": non-leaf %s\n",
00232                      op->o_req_dn.bv_val, 0, 0);
00233               rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
00234               rs->sr_text = "subordinate objects must be deleted first";
00235               goto return_results;
00236        }
00237 
00238        /* delete info */
00239        rs->sr_err = ndb_entry_del_info( op->o_bd, &NA );
00240        if ( rs->sr_err != 0 ) {
00241               Debug(LDAP_DEBUG_TRACE,
00242                      "<=- " LDAP_XSTRING(ndb_back_delete) ": del_info failed: %s (%d)\n",
00243                      NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 );
00244               rs->sr_text = "DN index delete failed";
00245               rs->sr_err = LDAP_OTHER;
00246               goto return_results;
00247        }
00248 
00249        /* delete data */
00250        rs->sr_err = ndb_entry_del_data( op->o_bd, &NA );
00251        if ( rs->sr_err != 0 ) {
00252               Debug( LDAP_DEBUG_TRACE,
00253                      "<=- " LDAP_XSTRING(ndb_back_delete) ": del_data failed: %s (%d)\n",
00254                      NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 );
00255               rs->sr_text = "entry delete failed";
00256               rs->sr_err = LDAP_OTHER;
00257               goto return_results;
00258        }
00259 
00260        if( op->o_noop ) {
00261               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
00262                      NdbOperation::AbortOnError, 1 )) != 0 ) {
00263                      rs->sr_text = "txn (no-op) failed";
00264               } else {
00265                      rs->sr_err = LDAP_X_NO_OPERATION;
00266               }
00267        } else {
00268               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
00269                      NdbOperation::AbortOnError, 1 )) != 0 ) {
00270                      rs->sr_text = "txn_commit failed";
00271               } else {
00272                      rs->sr_err = LDAP_SUCCESS;
00273               }
00274        }
00275 
00276        if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
00277               Debug( LDAP_DEBUG_TRACE,
00278                      LDAP_XSTRING(ndb_back_delete) ": txn_%s failed: %s (%d)\n",
00279                      op->o_noop ? "abort (no-op)" : "commit",
00280                      NA.txn->getNdbError().message, NA.txn->getNdbError().code );
00281               rs->sr_err = LDAP_OTHER;
00282               rs->sr_text = "commit failed";
00283 
00284               goto return_results;
00285        }
00286        NA.txn->close();
00287        NA.txn = NULL;
00288 
00289        Debug( LDAP_DEBUG_TRACE,
00290               LDAP_XSTRING(ndb_back_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
00291               op->o_noop ? " (no-op)" : "",
00292               e.e_id, op->o_req_dn.bv_val );
00293        rs->sr_err = LDAP_SUCCESS;
00294        rs->sr_text = NULL;
00295        if( num_ctrls ) rs->sr_ctrls = ctrls;
00296 
00297 return_results:
00298        if ( NA.ocs ) {
00299               ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
00300               NA.ocs = NULL;
00301        }
00302 
00303        /* free entry */
00304        if( e.e_attrs != NULL ) {
00305               attrs_free( e.e_attrs );
00306               e.e_attrs = NULL;
00307        }
00308 
00309        if( NA.txn != NULL ) {
00310               NA.txn->execute( Rollback );
00311               NA.txn->close();
00312        }
00313 
00314        send_ldap_result( op, rs );
00315        slap_graduate_commit_csn( op );
00316 
00317        if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
00318               slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00319               slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
00320        }
00321        return rs->sr_err;
00322 }