Back to index

openldap  2.4.31
add.cpp
Go to the documentation of this file.
00001 /* add.cpp - ldap NDB back-end add 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 "back-ndb.h"
00027 
00028 extern "C" int
00029 ndb_back_add(Operation *op, SlapReply *rs )
00030 {
00031        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
00032        Entry         p = {0};
00033        Attribute     poc;
00034        char textbuf[SLAP_TEXT_BUFLEN];
00035        size_t textlen = sizeof textbuf;
00036        AttributeDescription *children = slap_schema.si_ad_children;
00037        AttributeDescription *entry = slap_schema.si_ad_entry;
00038        NdbArgs NA;
00039        NdbRdns rdns;
00040        struct berval matched;
00041        struct berval pdn, pndn;
00042 
00043        int           num_retries = 0;
00044        int           success;
00045 
00046        LDAPControl **postread_ctrl = NULL;
00047        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
00048        int num_ctrls = 0;
00049 
00050        Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(ndb_back_add) ": %s\n",
00051               op->oq_add.rs_e->e_name.bv_val, 0, 0);
00052 
00053        ctrls[num_ctrls] = 0;
00054        NA.txn = NULL;
00055 
00056        /* check entry's schema */
00057        rs->sr_err = entry_schema_check( op, op->oq_add.rs_e, NULL,
00058               get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
00059        if ( rs->sr_err != LDAP_SUCCESS ) {
00060               Debug( LDAP_DEBUG_TRACE,
00061                      LDAP_XSTRING(ndb_back_add) ": entry failed schema check: "
00062                      "%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
00063               goto return_results;
00064        }
00065 
00066        /* add opattrs to shadow as well, only missing attrs will actually
00067         * be added; helps compatibility with older OL versions */
00068        rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
00069        if ( rs->sr_err != LDAP_SUCCESS ) {
00070               Debug( LDAP_DEBUG_TRACE,
00071                      LDAP_XSTRING(ndb_back_add) ": entry failed op attrs add: "
00072                      "%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
00073               goto return_results;
00074        }
00075 
00076        /* Get our NDB handle */
00077        rs->sr_err = ndb_thread_handle( op, &NA.ndb );
00078 
00079        /*
00080         * Get the parent dn and see if the corresponding entry exists.
00081         */
00082        if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
00083               pdn = slap_empty_bv;
00084               pndn = slap_empty_bv;
00085        } else {
00086               dnParent( &op->ora_e->e_name, &pdn );
00087               dnParent( &op->ora_e->e_nname, &pndn );
00088        }
00089        p.e_name = op->ora_e->e_name;
00090        p.e_nname = op->ora_e->e_nname;
00091 
00092        op->ora_e->e_id = NOID;
00093        rdns.nr_num = 0;
00094        NA.rdns = &rdns;
00095 
00096        if( 0 ) {
00097 retry: /* transaction retry */
00098               NA.txn->close();
00099               NA.txn = NULL;
00100               if ( op->o_abandon ) {
00101                      rs->sr_err = SLAPD_ABANDON;
00102                      goto return_results;
00103               }
00104               ndb_trans_backoff( ++num_retries );
00105        }
00106 
00107        NA.txn = NA.ndb->startTransaction();
00108        rs->sr_text = NULL;
00109        if( !NA.txn ) {
00110               Debug( LDAP_DEBUG_TRACE,
00111                      LDAP_XSTRING(ndb_back_add) ": startTransaction failed: %s (%d)\n",
00112                      NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
00113               rs->sr_err = LDAP_OTHER;
00114               rs->sr_text = "internal error";
00115               goto return_results;
00116        }
00117 
00118        /* get entry or parent */
00119        NA.e = &p;
00120        NA.ocs = NULL;
00121        rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
00122        switch( rs->sr_err ) {
00123        case 0:
00124               rs->sr_err = LDAP_ALREADY_EXISTS;
00125               goto return_results;
00126        case LDAP_NO_SUCH_OBJECT:
00127               break;
00128 #if 0
00129        case DB_LOCK_DEADLOCK:
00130        case DB_LOCK_NOTGRANTED:
00131               goto retry;
00132 #endif
00133        case LDAP_BUSY:
00134               rs->sr_text = "ldap server busy";
00135               goto return_results;
00136        default:
00137               rs->sr_err = LDAP_OTHER;
00138               rs->sr_text = "internal error";
00139               goto return_results;
00140        }
00141 
00142        if ( NA.ocs ) {
00143               int i;
00144               for ( i=0; !BER_BVISNULL( &NA.ocs[i] ); i++ );
00145               poc.a_numvals = i;
00146               poc.a_desc = slap_schema.si_ad_objectClass;
00147               poc.a_vals = NA.ocs;
00148               poc.a_nvals = poc.a_vals;
00149               poc.a_next = NULL;
00150               p.e_attrs = &poc;
00151        }
00152 
00153        if ( ber_bvstrcasecmp( &pndn, &matched ) ) {
00154               rs->sr_matched = matched.bv_val;
00155               Debug( LDAP_DEBUG_TRACE,
00156                      LDAP_XSTRING(ndb_back_add) ": parent "
00157                      "does not exist\n", 0, 0, 0 );
00158 
00159               rs->sr_text = "parent does not exist";
00160               rs->sr_err = LDAP_NO_SUCH_OBJECT;
00161               if ( p.e_attrs && is_entry_referral( &p )) {
00162 is_ref:                     p.e_attrs = NULL;
00163                      ndb_entry_get_data( op, &NA, 0 );
00164                      rs->sr_ref = get_entry_referrals( op, &p );
00165                      rs->sr_err = LDAP_REFERRAL;
00166                      rs->sr_flags = REP_REF_MUSTBEFREED;
00167                      attrs_free( p.e_attrs );
00168                      p.e_attrs = NULL;
00169               }
00170               goto return_results;
00171        }
00172 
00173        p.e_name = pdn;
00174        p.e_nname = pndn;
00175        rs->sr_err = access_allowed( op, &p,
00176               children, NULL, ACL_WADD, NULL );
00177 
00178        if ( ! rs->sr_err ) {
00179               Debug( LDAP_DEBUG_TRACE,
00180                      LDAP_XSTRING(ndb_back_add) ": no write access to parent\n",
00181                      0, 0, 0 );
00182               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00183               rs->sr_text = "no write access to parent";
00184               goto return_results;
00185        }
00186 
00187        if ( NA.ocs ) {
00188               if ( is_entry_subentry( &p )) {
00189                      /* parent is a subentry, don't allow add */
00190                      Debug( LDAP_DEBUG_TRACE,
00191                             LDAP_XSTRING(ndb_back_add) ": parent is subentry\n",
00192                             0, 0, 0 );
00193                      rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
00194                      rs->sr_text = "parent is a subentry";
00195                      goto return_results;
00196               }
00197 
00198               if ( is_entry_alias( &p ) ) {
00199                      /* parent is an alias, don't allow add */
00200                      Debug( LDAP_DEBUG_TRACE,
00201                             LDAP_XSTRING(ndb_back_add) ": parent is alias\n",
00202                             0, 0, 0 );
00203                      rs->sr_err = LDAP_ALIAS_PROBLEM;
00204                      rs->sr_text = "parent is an alias";
00205                      goto return_results;
00206               }
00207 
00208               if ( is_entry_referral( &p ) ) {
00209                      /* parent is a referral, don't allow add */
00210                      rs->sr_matched = p.e_name.bv_val;
00211                      goto is_ref;
00212               }
00213        }
00214 
00215        rs->sr_err = access_allowed( op, op->ora_e,
00216               entry, NULL, ACL_WADD, NULL );
00217 
00218        if ( ! rs->sr_err ) {
00219               Debug( LDAP_DEBUG_TRACE,
00220                      LDAP_XSTRING(ndb_back_add) ": no write access to entry\n",
00221                      0, 0, 0 );
00222               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00223               rs->sr_text = "no write access to entry";
00224               goto return_results;;
00225        }
00226 
00227        /* 
00228         * Check ACL for attribute write access
00229         */
00230        if (!acl_check_modlist(op, op->ora_e, op->ora_modlist)) {
00231               Debug( LDAP_DEBUG_TRACE,
00232                      LDAP_XSTRING(bdb_add) ": no write access to attribute\n",
00233                      0, 0, 0 );
00234               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00235               rs->sr_text = "no write access to attribute";
00236               goto return_results;;
00237        }
00238 
00239 
00240        /* acquire entry ID */
00241        if ( op->ora_e->e_id == NOID ) {
00242               rs->sr_err = ndb_next_id( op->o_bd, NA.ndb, &op->ora_e->e_id );
00243               if( rs->sr_err != 0 ) {
00244                      Debug( LDAP_DEBUG_TRACE,
00245                             LDAP_XSTRING(ndb_back_add) ": next_id failed (%d)\n",
00246                             rs->sr_err, 0, 0 );
00247                      rs->sr_err = LDAP_OTHER;
00248                      rs->sr_text = "internal error";
00249                      goto return_results;
00250               }
00251        }
00252 
00253        if ( matched.bv_val )
00254               rdns.nr_num++;
00255        NA.e = op->ora_e;
00256        /* dn2id index */
00257        rs->sr_err = ndb_entry_put_info( op->o_bd, &NA, 0 );
00258        if ( rs->sr_err ) {
00259               Debug( LDAP_DEBUG_TRACE,
00260                      LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_info failed (%d)\n",
00261                      rs->sr_err, 0, 0 );
00262               rs->sr_text = "internal error";
00263               goto return_results;
00264        }
00265 
00266        /* id2entry index */
00267        rs->sr_err = ndb_entry_put_data( op->o_bd, &NA );
00268        if ( rs->sr_err ) {
00269               Debug( LDAP_DEBUG_TRACE,
00270                      LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_data failed (%d) %s(%d)\n",
00271                      rs->sr_err, NA.txn->getNdbError().message, NA.txn->getNdbError().code );
00272               rs->sr_text = "internal error";
00273               goto return_results;
00274        }
00275 
00276        /* post-read */
00277        if( op->o_postread ) {
00278               if( postread_ctrl == NULL ) {
00279                      postread_ctrl = &ctrls[num_ctrls++];
00280                      ctrls[num_ctrls] = NULL;
00281               }
00282               if ( slap_read_controls( op, rs, op->oq_add.rs_e,
00283                      &slap_post_read_bv, postread_ctrl ) )
00284               {
00285                      Debug( LDAP_DEBUG_TRACE,
00286                             "<=- " LDAP_XSTRING(ndb_back_add) ": post-read "
00287                             "failed!\n", 0, 0, 0 );
00288                      if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
00289                             /* FIXME: is it correct to abort
00290                              * operation if control fails? */
00291                             goto return_results;
00292                      }
00293               }
00294        }
00295 
00296        if ( op->o_noop ) {
00297               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
00298                      NdbOperation::AbortOnError, 1 )) != 0 ) {
00299                      rs->sr_text = "txn (no-op) failed";
00300               } else {
00301                      rs->sr_err = LDAP_X_NO_OPERATION;
00302               }
00303 
00304        } else {
00305               if(( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
00306                      NdbOperation::AbortOnError, 1 )) != 0 ) {
00307                      rs->sr_text = "txn_commit failed";
00308               } else {
00309                      rs->sr_err = LDAP_SUCCESS;
00310               }
00311        }
00312 
00313        if ( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
00314               Debug( LDAP_DEBUG_TRACE,
00315                      LDAP_XSTRING(ndb_back_add) ": %s : %s (%d)\n",
00316                      rs->sr_text, NA.txn->getNdbError().message, NA.txn->getNdbError().code );
00317               rs->sr_err = LDAP_OTHER;
00318               goto return_results;
00319        }
00320        NA.txn->close();
00321        NA.txn = NULL;
00322 
00323        Debug(LDAP_DEBUG_TRACE,
00324               LDAP_XSTRING(ndb_back_add) ": added%s id=%08lx dn=\"%s\"\n",
00325               op->o_noop ? " (no-op)" : "",
00326               op->oq_add.rs_e->e_id, op->oq_add.rs_e->e_dn );
00327 
00328        rs->sr_text = NULL;
00329        if( num_ctrls ) rs->sr_ctrls = ctrls;
00330 
00331 return_results:
00332        success = rs->sr_err;
00333        send_ldap_result( op, rs );
00334        slap_graduate_commit_csn( op );
00335 
00336        if( NA.txn != NULL ) {
00337               NA.txn->execute( Rollback );
00338               NA.txn->close();
00339        }
00340 
00341        if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
00342               slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00343               slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
00344        }
00345 
00346        return rs->sr_err;
00347 }