]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ndb/add.cpp
Partially revert prev commit, leave rs->sr_err == SLAPD_ABANDON
[openldap] / servers / slapd / back-ndb / add.cpp
index 44c182d82b13fdd1855461e151856ab62eb42fe5..4efdbcd14f19c96993b059bda794400fc2668d9b 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2008 The OpenLDAP Foundation.
+ * Copyright 2008-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@ ndb_back_add(Operation *op, SlapReply *rs )
 {
        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
        Entry           p = {0};
+       Attribute       poc;
        char textbuf[SLAP_TEXT_BUFLEN];
        size_t textlen = sizeof textbuf;
        AttributeDescription *children = slap_schema.si_ad_children;
@@ -37,6 +38,7 @@ ndb_back_add(Operation *op, SlapReply *rs )
        NdbArgs NA;
        NdbRdns rdns;
        struct berval matched;
+       struct berval pdn, pndn;
 
        int             num_retries = 0;
        int             success;
@@ -52,7 +54,7 @@ ndb_back_add(Operation *op, SlapReply *rs )
 
        /* check entry's schema */
        rs->sr_err = entry_schema_check( op, op->oq_add.rs_e, NULL,
-               get_relax(op), 1, &rs->sr_text, textbuf, textlen );
+               get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
        if ( rs->sr_err != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE,
                        LDAP_XSTRING(ndb_back_add) ": entry failed schema check: "
@@ -77,12 +79,14 @@ ndb_back_add(Operation *op, SlapReply *rs )
         * Get the parent dn and see if the corresponding entry exists.
         */
        if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
-               p.e_name = slap_empty_bv;
-               p.e_nname = slap_empty_bv;
+               pdn = slap_empty_bv;
+               pndn = slap_empty_bv;
        } else {
-               dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
-               dnParent( &op->oq_add.rs_e->e_name, &p.e_name );
+               dnParent( &op->ora_e->e_name, &pdn );
+               dnParent( &op->ora_e->e_nname, &pndn );
        }
+       p.e_name = op->ora_e->e_name;
+       p.e_nname = op->ora_e->e_nname;
 
        op->ora_e->e_id = NOID;
        rdns.nr_num = 0;
@@ -111,13 +115,9 @@ retry:     /* transaction retry */
        }
 
        /* get entry or parent */
-       {
-               Entry dummy;
-               dummy.e_name = op->ora_e->e_name;
-               NA.e = &dummy;
-               NA.ocs = &matched;
-               rs->sr_err = ndb_entry_get_info( op->o_bd, &NA, 0, &matched );
-       }
+       NA.e = &p;
+       NA.ocs = NULL;
+       rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
        switch( rs->sr_err ) {
        case 0:
                rs->sr_err = LDAP_ALREADY_EXISTS;
@@ -138,7 +138,18 @@ retry:     /* transaction retry */
                goto return_results;
        }
 
-       if ( ber_bvstrcasecmp( &p.e_nname, &matched ) ) {
+       if ( NA.ocs ) {
+               int i;
+               for ( i=0; !BER_BVISNULL( &NA.ocs[i] ); i++ );
+               poc.a_numvals = i;
+               poc.a_desc = slap_schema.si_ad_objectClass;
+               poc.a_vals = NA.ocs;
+               poc.a_nvals = poc.a_vals;
+               poc.a_next = NULL;
+               p.e_attrs = &poc;
+       }
+
+       if ( ber_bvstrcasecmp( &pndn, &matched ) ) {
                rs->sr_matched = matched.bv_val;
                Debug( LDAP_DEBUG_TRACE,
                        LDAP_XSTRING(ndb_back_add) ": parent "
@@ -146,9 +157,20 @@ retry:     /* transaction retry */
 
                rs->sr_text = "parent does not exist";
                rs->sr_err = LDAP_NO_SUCH_OBJECT;
+               if ( p.e_attrs && is_entry_referral( &p )) {
+is_ref:                        p.e_attrs = NULL;
+                       ndb_entry_get_data( op, &NA, 0 );
+                       rs->sr_ref = get_entry_referrals( op, &p );
+                       rs->sr_err = LDAP_REFERRAL;
+                       rs->sr_flags = REP_REF_MUSTBEFREED;
+                       attrs_free( p.e_attrs );
+                       p.e_attrs = NULL;
+               }
                goto return_results;
        }
 
+       p.e_name = pdn;
+       p.e_nname = pndn;
        rs->sr_err = access_allowed( op, &p,
                children, NULL, ACL_WADD, NULL );
 
@@ -158,10 +180,38 @@ retry:    /* transaction retry */
                        0, 0, 0 );
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
                rs->sr_text = "no write access to parent";
-               goto return_results;;
+               goto return_results;
+       }
+
+       if ( NA.ocs ) {
+               if ( is_entry_subentry( &p )) {
+                       /* parent is a subentry, don't allow add */
+                       Debug( LDAP_DEBUG_TRACE,
+                               LDAP_XSTRING(ndb_back_add) ": parent is subentry\n",
+                               0, 0, 0 );
+                       rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
+                       rs->sr_text = "parent is a subentry";
+                       goto return_results;
+               }
+
+               if ( is_entry_alias( &p ) ) {
+                       /* parent is an alias, don't allow add */
+                       Debug( LDAP_DEBUG_TRACE,
+                               LDAP_XSTRING(ndb_back_add) ": parent is alias\n",
+                               0, 0, 0 );
+                       rs->sr_err = LDAP_ALIAS_PROBLEM;
+                       rs->sr_text = "parent is an alias";
+                       goto return_results;
+               }
+
+               if ( is_entry_referral( &p ) ) {
+                       /* parent is a referral, don't allow add */
+                       rs->sr_matched = p.e_name.bv_val;
+                       goto is_ref;
+               }
        }
 
-       rs->sr_err = access_allowed( op, op->oq_add.rs_e,
+       rs->sr_err = access_allowed( op, op->ora_e,
                entry, NULL, ACL_WADD, NULL );
 
        if ( ! rs->sr_err ) {
@@ -173,6 +223,19 @@ retry:     /* transaction retry */
                goto return_results;;
        }
 
+       /* 
+        * Check ACL for attribute write access
+        */
+       if (!acl_check_modlist(op, op->ora_e, op->ora_modlist)) {
+               Debug( LDAP_DEBUG_TRACE,
+                       LDAP_XSTRING(bdb_add) ": no write access to attribute\n",
+                       0, 0, 0 );
+               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+               rs->sr_text = "no write access to attribute";
+               goto return_results;;
+       }
+
+
        /* acquire entry ID */
        if ( op->ora_e->e_id == NOID ) {
                rs->sr_err = ndb_next_id( op->o_bd, NA.ndb, &op->ora_e->e_id );
@@ -186,12 +249,28 @@ retry:    /* transaction retry */
                }
        }
 
+       if ( matched.bv_val )
+               rdns.nr_num++;
        NA.e = op->ora_e;
        /* dn2id index */
        rs->sr_err = ndb_entry_put_info( op->o_bd, &NA, 0 );
+       if ( rs->sr_err ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_info failed (%d)\n",
+                       rs->sr_err, 0, 0 );
+               rs->sr_text = "internal error";
+               goto return_results;
+       }
 
        /* id2entry index */
-       rs->sr_err = ndb_entry_put_data( op->o_bd, &NA, 0 );
+       rs->sr_err = ndb_entry_put_data( op->o_bd, &NA );
+       if ( rs->sr_err ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_data failed (%d) %s(%d)\n",
+                       rs->sr_err, NA.txn->getNdbError().message, NA.txn->getNdbError().code );
+               rs->sr_text = "internal error";
+               goto return_results;
+       }
 
        /* post-read */
        if( op->o_postread ) {
@@ -214,14 +293,16 @@ retry:    /* transaction retry */
        }
 
        if ( op->o_noop ) {
-               if (( rs->sr_err=NA.txn->execute( Rollback )) != 0 ) {
+               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
+                       NdbOperation::AbortOnError, 1 )) != 0 ) {
                        rs->sr_text = "txn (no-op) failed";
                } else {
                        rs->sr_err = LDAP_X_NO_OPERATION;
                }
 
        } else {
-               if(( rs->sr_err=NA.txn->execute( Commit )) != 0 ) {
+               if(( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
+                       NdbOperation::AbortOnError, 1 )) != 0 ) {
                        rs->sr_text = "txn_commit failed";
                } else {
                        rs->sr_err = LDAP_SUCCESS;