]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldbm/delete.c
Debug output: printed soc_cname, should be soc_cname.bv_val
[openldap] / servers / slapd / back-ldbm / delete.c
index 2072e2bfd8590fb0072408178ba6585f933249b5..6db0d31dbf47be50e88496c1be6621d0850f28ff 100644 (file)
@@ -1,4 +1,18 @@
 /* delete.c - ldbm backend delete routine */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2005 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
 
 #include "portable.h"
 
 
 int
 ldbm_back_delete(
-    Backend    *be,
-    Connection *conn,
     Operation  *op,
-    char       *dn
-)
+    SlapReply  *rs )
 {
-       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char            *matched;
-        char            *pdn = NULL;
-       Entry           *e, *p;
+       struct ldbminfo *li = (struct ldbminfo *) op->o_bd->be_private;
+       Entry   *matched;
+       struct berval   pdn;
+       Entry   *e, *p = NULL;
+       int     rc = -1;
+       int             manageDSAit = get_manageDSAit( op );
+       AttributeDescription *children = slap_schema.si_ad_children;
+       AttributeDescription *entry = slap_schema.si_ad_entry;
 
-       Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", dn, 0, 0);
+       Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", op->o_req_dn.bv_val, 0, 0);
+
+       /* grab giant lock for writing */
+       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
 
        /* get entry with writer lock */
-       if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
+       e = dn2entry_w( op->o_bd, &op->o_req_ndn, &matched );
+
+       /* FIXME : dn2entry() should return non-glue entry */
+       if ( e == NULL || ( !manageDSAit && is_entry_glue( e ))) {
                Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: no such object %s\n",
-                       dn, 0, 0);
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+                       op->o_req_dn.bv_val, 0, 0);
+
                if ( matched != NULL ) {
-                       free( matched );
+                       rs->sr_matched = ch_strdup( matched->e_dn );
+                       rs->sr_ref = is_entry_referral( matched )
+                               ? get_entry_referrals( op, matched )
+                               : NULL;
+                       cache_return_entry_r( &li->li_cache, matched );
+
+               } else {
+                       rs->sr_ref = referral_rewrite( default_referral, NULL,
+                                                       &op->o_req_dn, LDAP_SCOPE_DEFAULT );
                }
+
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+
+               rs->sr_err = LDAP_REFERRAL;
+               send_ldap_result( op, rs );
+
+               if ( rs->sr_ref ) ber_bvarray_free( rs->sr_ref );
+               free( (char *)rs->sr_matched );
+               rs->sr_ref = NULL;
+               rs->sr_matched = NULL;
                return( -1 );
        }
 
-       Debug (LDAP_DEBUG_TRACE,
-               "rdwr_Xchk: readers_reading: %d writer_writing: %d\n",
-               e->e_rdwr.readers_reading, e->e_rdwr.writer_writing, 0);
+       /* check entry for "entry" acl */
+       if ( ! access_allowed( op, e, entry, NULL, ACL_WDEL, NULL ) )
+       {
+               Debug( LDAP_DEBUG_TRACE,
+                       "<=- ldbm_back_delete: no write access to entry\n", 0,
+                       0, 0 );
 
-       /* check for deleted */
+               send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
+                       "no write access to entry" );
 
-       if ( has_children( be, e ) ) {
-               Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: non leaf %s\n",
-                       dn, 0, 0);
-               send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "",
-                   "" );
-               goto error_return;
+               rc = LDAP_INSUFFICIENT_ACCESS;
+               goto return_results;
        }
 
-       if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn,
-           ACL_WRITE ) ) {
-               Debug(LDAP_DEBUG_ARGS,
-                       "<=- ldbm_back_delete: insufficient access %s\n",
-                       dn, 0, 0);
-               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
-               goto error_return;
+       if ( !manageDSAit && is_entry_referral( e ) ) {
+               /* parent is a referral, don't allow add */
+               /* parent is an alias, don't allow add */
+               rs->sr_ref = get_entry_referrals( op, e );
+
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                   0, 0 );
+
+               rs->sr_err = LDAP_REFERRAL;
+               rs->sr_matched = e->e_name.bv_val;
+               send_ldap_result( op, rs );
+
+               if ( rs->sr_ref ) ber_bvarray_free( rs->sr_ref );
+               rs->sr_ref = NULL;
+               rs->sr_matched = NULL;
+               rc = LDAP_REFERRAL;
+               goto return_results;
        }
 
-       Debug (LDAP_DEBUG_TRACE,
-               "rdwr_Xchk: readers_reading: %d writer_writing: %d\n",
-               e->e_rdwr.readers_reading, e->e_rdwr.writer_writing, 0);
-
-       /* XXX delete from parent's id2children entry XXX */
-       pdn = dn_parent( be, dn );
-       p = dn2entry_r( be, pdn, &matched );
-       free( pdn );
-       if ( id2children_remove( be, p, e ) != 0 ) {
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "","" );
-                goto error_return;
+       if ( has_children( op->o_bd, e ) ) {
+               Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: non leaf %s\n",
+                       op->o_req_dn.bv_val, 0, 0);
+
+               send_ldap_error( op, rs, LDAP_NOT_ALLOWED_ON_NONLEAF,
+                       "subordinate objects must be deleted first");
+               goto return_results;
+       }
+
+       /* delete from parent's id2children entry */
+       if( !be_issuffix( op->o_bd, &e->e_nname ) && (dnParent( &e->e_nname, &pdn ),
+               pdn.bv_len) ) {
+               if( (p = dn2entry_w( op->o_bd, &pdn, NULL )) == NULL) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- ldbm_back_delete: parent does not exist\n",
+                               0, 0, 0);
+
+                       send_ldap_error( op, rs, LDAP_OTHER,
+                               "could not locate parent of entry" );
+                       goto return_results;
+               }
+
+               /* check parent for "children" acl */
+               if ( ! access_allowed( op, p,
+                       children, NULL, ACL_WDEL, NULL ) )
+               {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- ldbm_back_delete: no access to parent\n", 0,
+                               0, 0 );
+
+                       send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
+                               "no write access to parent" );
+                       goto return_results;
+               }
+
+       } else {
+               /* no parent, must be root to delete */
+               if( ! be_isroot( op ) ) {
+                       if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
+                               || be_shadow_update( op ) ) {
+                               p = (Entry *)&slap_entry_root;
+                               
+                               rc = access_allowed( op, p,
+                                       children, NULL, ACL_WDEL, NULL );
+                               p = NULL;
+                                                               
+                               /* check parent for "children" acl */
+                               if ( ! rc ) {
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "<=- ldbm_back_delete: no "
+                                               "access to parent\n", 0, 0, 0 );
+
+                                       send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
+                                               "no write access to parent" );
+                                       goto return_results;
+                               }
+
+                       } else {
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "<=- ldbm_back_delete: no parent & "
+                                       "not root\n", 0, 0, 0);
+
+                               send_ldap_error( op, rs,
+                                       LDAP_INSUFFICIENT_ACCESS,
+                                       NULL );
+                               goto return_results;
+                       }
+               }
        }
 
        /* delete from dn2id mapping */
-       if ( dn2id_delete( be, e->e_dn ) != 0 ) {
+       if ( dn2id_delete( op->o_bd, &e->e_nname, e->e_id ) != 0 ) {
                Debug(LDAP_DEBUG_ARGS,
                        "<=- ldbm_back_delete: operations error %s\n",
-                       dn, 0, 0);
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               goto error_return;
+                       op->o_req_dn.bv_val, 0, 0);
+
+               send_ldap_error( op, rs, LDAP_OTHER,
+                       "DN index delete failed" );
+               goto return_results;
        }
 
        /* delete from disk and cache */
-       if ( id2entry_delete( be, e ) != 0 ) {
+       if ( id2entry_delete( op->o_bd, e ) != 0 ) {
                Debug(LDAP_DEBUG_ARGS,
                        "<=- ldbm_back_delete: operations error %s\n",
-                       dn, 0, 0);
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               goto error_return;
-       }
+                       op->o_req_dn.bv_val, 0, 0);
 
-       /* free entry and writer lock */
-       cache_return_entry_w( &li->li_cache, e );
-       if ( p != NULL )
-               cache_return_entry_r( &li->li_cache, p );
+               send_ldap_error( op, rs, LDAP_OTHER,
+                       "entry delete failed" );
+               goto return_results;
+       }
 
-       if ( matched != NULL ) free(matched);
+       /* delete attribute indices */
+       (void) index_entry_del( op, e );
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+       rs->sr_err = LDAP_SUCCESS;
+       send_ldap_result( op, rs );
+       rc = LDAP_SUCCESS;
 
-       return( 0 );
+return_results:;
+       if( p != NULL ) {
+               /* free parent and writer lock */
+               cache_return_entry_w( &li->li_cache, p );
+       }
 
-error_return:;
        /* free entry and writer lock */
        cache_return_entry_w( &li->li_cache, e );
 
-       if( p != NULL )
-               cache_return_entry_r( &li->li_cache, p );
-
-       if ( matched != NULL ) free(matched);
+       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
-       return( -1 );
+       return rc;
 }