Back to index

openldap  2.4.31
attr.c
Go to the documentation of this file.
00001 /* attr.c - backend routines for dealing with attributes */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-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 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 
00021 #include <ac/socket.h>
00022 #include <ac/string.h>
00023 
00024 #include "slap.h"
00025 #include "back-mdb.h"
00026 #include "config.h"
00027 #include "lutil.h"
00028 
00029 /* Find the ad, return -1 if not found,
00030  * set point for insertion if ins is non-NULL
00031  */
00032 int
00033 mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
00034 {
00035        unsigned base = 0, cursor = 0;
00036        unsigned n = mdb->mi_nattrs;
00037        int val = 0;
00038        
00039        while ( 0 < n ) {
00040               unsigned pivot = n >> 1;
00041               cursor = base + pivot;
00042 
00043               val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
00044               if ( val < 0 ) {
00045                      n = pivot;
00046               } else if ( val > 0 ) {
00047                      base = cursor + 1;
00048                      n -= pivot + 1;
00049               } else {
00050                      return cursor;
00051               }
00052        }
00053        if ( ins ) {
00054               if ( val > 0 )
00055                      ++cursor;
00056               *ins = cursor;
00057        }
00058        return -1;
00059 }
00060 
00061 static int
00062 ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
00063 {
00064        int x;
00065        int i = mdb_attr_slot( mdb, a->ai_desc, &x );
00066 
00067        /* Is it a dup? */
00068        if ( i >= 0 )
00069               return -1;
00070 
00071        mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) * 
00072               sizeof( AttrInfo * ));
00073        if ( x < mdb->mi_nattrs )
00074               AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
00075                      ( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
00076        mdb->mi_attrs[x] = a;
00077        mdb->mi_nattrs++;
00078        return 0;
00079 }
00080 
00081 AttrInfo *
00082 mdb_attr_mask(
00083        struct mdb_info      *mdb,
00084        AttributeDescription *desc )
00085 {
00086        int i = mdb_attr_slot( mdb, desc, NULL );
00087        return i < 0 ? NULL : mdb->mi_attrs[i];
00088 }
00089 
00090 /* Open all un-opened index DB handles */
00091 int
00092 mdb_attr_dbs_open(
00093        BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
00094 {
00095        struct mdb_info *mdb = (struct mdb_info *) be->be_private;
00096        MDB_txn *txn;
00097        int i, flags;
00098        int rc;
00099 
00100        txn = tx0;
00101        if ( txn == NULL ) {
00102               rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
00103               if ( rc ) {
00104                      snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
00105                             "txn_begin failed: %s (%d).",
00106                             be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
00107                      Debug( LDAP_DEBUG_ANY,
00108                             LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
00109                             cr->msg, 0, 0 );
00110                      return rc;
00111               }
00112        } else {
00113               rc = 0;
00114        }
00115 
00116        flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
00117        if ( !(slapMode & SLAP_TOOL_READONLY) )
00118               flags |= MDB_CREATE;
00119 
00120        for ( i=0; i<mdb->mi_nattrs; i++ ) {
00121               if ( mdb->mi_attrs[i]->ai_dbi )    /* already open */
00122                      continue;
00123               rc = mdb_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
00124                      flags, &mdb->mi_attrs[i]->ai_dbi );
00125               if ( rc ) {
00126                      snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
00127                             "mdb_open(%s) failed: %s (%d).",
00128                             be->be_suffix[0].bv_val,
00129                             mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
00130                             mdb_strerror(rc), rc );
00131                      Debug( LDAP_DEBUG_ANY,
00132                             LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
00133                             cr->msg, 0, 0 );
00134                      break;
00135               }
00136        }
00137 
00138        /* Only commit if this is our txn */
00139        if ( tx0 == NULL ) {
00140               if ( !rc ) {
00141                      rc = mdb_txn_commit( txn );
00142                      if ( rc ) {
00143                             snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
00144                                    "txn_commit failed: %s (%d).",
00145                                    be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
00146                             Debug( LDAP_DEBUG_ANY,
00147                                    LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
00148                                    cr->msg, 0, 0 );
00149                      }
00150               } else {
00151                      mdb_txn_abort( txn );
00152               }
00153        }
00154 
00155        return rc;
00156 }
00157 
00158 void
00159 mdb_attr_dbs_close(
00160        struct mdb_info *mdb
00161 )
00162 {
00163        int i;
00164        for ( i=0; i<mdb->mi_nattrs; i++ )
00165               if ( mdb->mi_attrs[i]->ai_dbi )
00166                      mdb_close( mdb->mi_dbenv, mdb->mi_attrs[i]->ai_dbi );
00167 }
00168 
00169 int
00170 mdb_attr_index_config(
00171        struct mdb_info      *mdb,
00172        const char           *fname,
00173        int                  lineno,
00174        int                  argc,
00175        char          **argv,
00176        struct        config_reply_s *c_reply)
00177 {
00178        int rc = 0;
00179        int    i;
00180        slap_mask_t mask;
00181        char **attrs;
00182        char **indexes = NULL;
00183 
00184        attrs = ldap_str2charray( argv[0], "," );
00185 
00186        if( attrs == NULL ) {
00187               fprintf( stderr, "%s: line %d: "
00188                      "no attributes specified: %s\n",
00189                      fname, lineno, argv[0] );
00190               return LDAP_PARAM_ERROR;
00191        }
00192 
00193        if ( argc > 1 ) {
00194               indexes = ldap_str2charray( argv[1], "," );
00195 
00196               if( indexes == NULL ) {
00197                      fprintf( stderr, "%s: line %d: "
00198                             "no indexes specified: %s\n",
00199                             fname, lineno, argv[1] );
00200                      rc = LDAP_PARAM_ERROR;
00201                      goto done;
00202               }
00203        }
00204 
00205        if( indexes == NULL ) {
00206               mask = mdb->mi_defaultmask;
00207 
00208        } else {
00209               mask = 0;
00210 
00211               for ( i = 0; indexes[i] != NULL; i++ ) {
00212                      slap_mask_t index;
00213                      rc = slap_str2index( indexes[i], &index );
00214 
00215                      if( rc != LDAP_SUCCESS ) {
00216                             if ( c_reply )
00217                             {
00218                                    snprintf(c_reply->msg, sizeof(c_reply->msg),
00219                                           "index type \"%s\" undefined", indexes[i] );
00220 
00221                                    fprintf( stderr, "%s: line %d: %s\n",
00222                                           fname, lineno, c_reply->msg );
00223                             }
00224                             rc = LDAP_PARAM_ERROR;
00225                             goto done;
00226                      }
00227 
00228                      mask |= index;
00229               }
00230        }
00231 
00232        if( !mask ) {
00233               if ( c_reply )
00234               {
00235                      snprintf(c_reply->msg, sizeof(c_reply->msg),
00236                             "no indexes selected" );
00237                      fprintf( stderr, "%s: line %d: %s\n",
00238                             fname, lineno, c_reply->msg );
00239               }
00240               rc = LDAP_PARAM_ERROR;
00241               goto done;
00242        }
00243 
00244        for ( i = 0; attrs[i] != NULL; i++ ) {
00245               AttrInfo      *a;
00246               AttributeDescription *ad;
00247               const char *text;
00248 #ifdef LDAP_COMP_MATCH
00249               ComponentReference* cr = NULL;
00250               AttrInfo *a_cr = NULL;
00251 #endif
00252 
00253               if( strcasecmp( attrs[i], "default" ) == 0 ) {
00254                      mdb->mi_defaultmask |= mask;
00255                      continue;
00256               }
00257 
00258 #ifdef LDAP_COMP_MATCH
00259               if ( is_component_reference( attrs[i] ) ) {
00260                      rc = extract_component_reference( attrs[i], &cr );
00261                      if ( rc != LDAP_SUCCESS ) {
00262                             if ( c_reply )
00263                             {
00264                                    snprintf(c_reply->msg, sizeof(c_reply->msg),
00265                                           "index component reference\"%s\" undefined",
00266                                           attrs[i] );
00267                                    fprintf( stderr, "%s: line %d: %s\n",
00268                                           fname, lineno, c_reply->msg );
00269                             }
00270                             goto done;
00271                      }
00272                      cr->cr_indexmask = mask;
00273                      /*
00274                       * After extracting a component reference
00275                       * only the name of a attribute will be remaining
00276                       */
00277               } else {
00278                      cr = NULL;
00279               }
00280 #endif
00281               ad = NULL;
00282               rc = slap_str2ad( attrs[i], &ad, &text );
00283 
00284               if( rc != LDAP_SUCCESS ) {
00285                      if ( c_reply )
00286                      {
00287                             snprintf(c_reply->msg, sizeof(c_reply->msg),
00288                                    "index attribute \"%s\" undefined",
00289                                    attrs[i] );
00290 
00291                             fprintf( stderr, "%s: line %d: %s\n",
00292                                    fname, lineno, c_reply->msg );
00293                      }
00294                      goto done;
00295               }
00296 
00297               if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
00298                      if (c_reply) {
00299                             snprintf(c_reply->msg, sizeof(c_reply->msg),
00300                                    "index of attribute \"%s\" disallowed", attrs[i] );
00301                             fprintf( stderr, "%s: line %d: %s\n",
00302                                    fname, lineno, c_reply->msg );
00303                      }
00304                      rc = LDAP_UNWILLING_TO_PERFORM;
00305                      goto done;
00306               }
00307 
00308               if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
00309                      ad->ad_type->sat_approx
00310                             && ad->ad_type->sat_approx->smr_indexer
00311                             && ad->ad_type->sat_approx->smr_filter ) )
00312               {
00313                      if (c_reply) {
00314                             snprintf(c_reply->msg, sizeof(c_reply->msg),
00315                                    "approx index of attribute \"%s\" disallowed", attrs[i] );
00316                             fprintf( stderr, "%s: line %d: %s\n",
00317                                    fname, lineno, c_reply->msg );
00318                      }
00319                      rc = LDAP_INAPPROPRIATE_MATCHING;
00320                      goto done;
00321               }
00322 
00323               if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
00324                      ad->ad_type->sat_equality
00325                             && ad->ad_type->sat_equality->smr_indexer
00326                             && ad->ad_type->sat_equality->smr_filter ) )
00327               {
00328                      if (c_reply) {
00329                             snprintf(c_reply->msg, sizeof(c_reply->msg),
00330                                    "equality index of attribute \"%s\" disallowed", attrs[i] );
00331                             fprintf( stderr, "%s: line %d: %s\n",
00332                                    fname, lineno, c_reply->msg );
00333                      }
00334                      rc = LDAP_INAPPROPRIATE_MATCHING;
00335                      goto done;
00336               }
00337 
00338               if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
00339                      ad->ad_type->sat_substr
00340                             && ad->ad_type->sat_substr->smr_indexer
00341                             && ad->ad_type->sat_substr->smr_filter ) )
00342               {
00343                      if (c_reply) {
00344                             snprintf(c_reply->msg, sizeof(c_reply->msg),
00345                                    "substr index of attribute \"%s\" disallowed", attrs[i] );
00346                             fprintf( stderr, "%s: line %d: %s\n",
00347                                    fname, lineno, c_reply->msg );
00348                      }
00349                      rc = LDAP_INAPPROPRIATE_MATCHING;
00350                      goto done;
00351               }
00352 
00353               Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
00354                      ad->ad_cname.bv_val, mask, 0 ); 
00355 
00356               a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
00357 
00358 #ifdef LDAP_COMP_MATCH
00359               a->ai_cr = NULL;
00360 #endif
00361               a->ai_cursor = NULL;
00362               a->ai_flist = NULL;
00363               a->ai_clist = NULL;
00364               a->ai_root = NULL;
00365               a->ai_desc = ad;
00366               a->ai_dbi = 0;
00367 
00368               if ( mdb->mi_flags & MDB_IS_OPEN ) {
00369                      a->ai_indexmask = 0;
00370                      a->ai_newmask = mask;
00371               } else {
00372                      a->ai_indexmask = mask;
00373                      a->ai_newmask = 0;
00374               }
00375 
00376 #ifdef LDAP_COMP_MATCH
00377               if ( cr ) {
00378                      a_cr = mdb_attr_mask( mdb, ad );
00379                      if ( a_cr ) {
00380                             /*
00381                              * AttrInfo is already in AVL
00382                              * just add the extracted component reference
00383                              * in the AttrInfo
00384                              */
00385                             rc = insert_component_reference( cr, &a_cr->ai_cr );
00386                             if ( rc != LDAP_SUCCESS) {
00387                                    fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
00388                                    rc = LDAP_PARAM_ERROR;
00389                                    goto done;
00390                             }
00391                             continue;
00392                      } else {
00393                             rc = insert_component_reference( cr, &a->ai_cr );
00394                             if ( rc != LDAP_SUCCESS) {
00395                                    fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
00396                                    rc = LDAP_PARAM_ERROR;
00397                                    goto done;
00398                             }
00399                      }
00400               }
00401 #endif
00402               rc = ainfo_insert( mdb, a );
00403               if( rc ) {
00404                      if ( mdb->mi_flags & MDB_IS_OPEN ) {
00405                             AttrInfo *b = mdb_attr_mask( mdb, ad );
00406                             /* If there is already an index defined for this attribute
00407                              * it must be replaced. Otherwise we end up with multiple 
00408                              * olcIndex values for the same attribute */
00409                             if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
00410                                    /* If we were editing this attr, reset it */
00411                                    b->ai_indexmask &= ~MDB_INDEX_DELETING;
00412                                    /* If this is leftover from a previous add, commit it */
00413                                    if ( b->ai_newmask )
00414                                           b->ai_indexmask = b->ai_newmask;
00415                                    b->ai_newmask = a->ai_newmask;
00416                                    ch_free( a );
00417                                    rc = 0;
00418                                    continue;
00419                             }
00420                      }
00421                      if (c_reply) {
00422                             snprintf(c_reply->msg, sizeof(c_reply->msg),
00423                                    "duplicate index definition for attr \"%s\"",
00424                                    attrs[i] );
00425                             fprintf( stderr, "%s: line %d: %s\n",
00426                                    fname, lineno, c_reply->msg );
00427                      }
00428 
00429                      rc = LDAP_PARAM_ERROR;
00430                      goto done;
00431               }
00432        }
00433 
00434 done:
00435        ldap_charray_free( attrs );
00436        if ( indexes != NULL ) ldap_charray_free( indexes );
00437 
00438        return rc;
00439 }
00440 
00441 static int
00442 mdb_attr_index_unparser( void *v1, void *v2 )
00443 {
00444        AttrInfo *ai = v1;
00445        BerVarray *bva = v2;
00446        struct berval bv;
00447        char *ptr;
00448 
00449        slap_index2bvlen( ai->ai_indexmask, &bv );
00450        if ( bv.bv_len ) {
00451               bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
00452               ptr = ch_malloc( bv.bv_len+1 );
00453               bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
00454               *bv.bv_val++ = ' ';
00455               slap_index2bv( ai->ai_indexmask, &bv );
00456               bv.bv_val = ptr;
00457               ber_bvarray_add( bva, &bv );
00458        }
00459        return 0;
00460 }
00461 
00462 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
00463 static AttrInfo aidef = { &addef };
00464 
00465 void
00466 mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
00467 {
00468        int i;
00469 
00470        if ( mdb->mi_defaultmask ) {
00471               aidef.ai_indexmask = mdb->mi_defaultmask;
00472               mdb_attr_index_unparser( &aidef, bva );
00473        }
00474        for ( i=0; i<mdb->mi_nattrs; i++ )
00475               mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
00476 }
00477 
00478 void
00479 mdb_attr_info_free( AttrInfo *ai )
00480 {
00481 #ifdef LDAP_COMP_MATCH
00482        free( ai->ai_cr );
00483 #endif
00484        free( ai );
00485 }
00486 
00487 void
00488 mdb_attr_index_destroy( struct mdb_info *mdb )
00489 {
00490        int i;
00491 
00492        for ( i=0; i<mdb->mi_nattrs; i++ ) 
00493               mdb_attr_info_free( mdb->mi_attrs[i] );
00494 
00495        free( mdb->mi_attrs );
00496 }
00497 
00498 void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
00499 {
00500        int i;
00501 
00502        i = mdb_attr_slot( mdb, ad, NULL );
00503        if ( i >= 0 ) {
00504               mdb_attr_info_free( mdb->mi_attrs[i] );
00505               mdb->mi_nattrs--;
00506               for (; i<mdb->mi_nattrs; i++)
00507                      mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
00508        }
00509 }
00510 
00511 void mdb_attr_flush( struct mdb_info *mdb )
00512 {
00513        int i;
00514 
00515        for ( i=0; i<mdb->mi_nattrs; i++ ) {
00516               if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
00517                      int j;
00518                      mdb_attr_info_free( mdb->mi_attrs[i] );
00519                      mdb->mi_nattrs--;
00520                      for (j=i; j<mdb->mi_nattrs; j++)
00521                             mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
00522                      i--;
00523               }
00524        }
00525 }
00526 
00527 int mdb_ad_read( struct mdb_info *mdb, MDB_txn *txn )
00528 {
00529        int i, rc;
00530        MDB_cursor *mc;
00531        MDB_val key, data;
00532        struct berval bdata;
00533        const char *text;
00534        AttributeDescription *ad;
00535 
00536        rc = mdb_cursor_open( txn, mdb->mi_ad2id, &mc );
00537        if ( rc ) {
00538               Debug( LDAP_DEBUG_ANY,
00539                      "mdb_ad_read: cursor_open failed %s(%d)\n",
00540                      mdb_strerror(rc), rc, 0);
00541               return rc;
00542        }
00543 
00544        /* our array is 1-based, an index of 0 means no data */
00545        i = mdb->mi_numads+1;
00546        key.mv_size = sizeof(int);
00547        key.mv_data = &i;
00548 
00549        rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
00550 
00551        while ( rc == MDB_SUCCESS ) {
00552               bdata.bv_len = data.mv_size;
00553               bdata.bv_val = data.mv_data;
00554               ad = NULL;
00555               rc = slap_bv2ad( &bdata, &ad, &text );
00556               if ( rc ) {
00557                      rc = slap_bv2undef_ad( &bdata, &mdb->mi_ads[i], &text, 0 );
00558               } else {
00559                      if ( ad->ad_index >= MDB_MAXADS ) {
00560                             Debug( LDAP_DEBUG_ANY,
00561                                    "mdb_adb_read: too many AttributeDescriptions in use\n",
00562                                    0, 0, 0 );
00563                             return LDAP_OTHER;
00564                      }
00565                      mdb->mi_adxs[ad->ad_index] = i;
00566                      mdb->mi_ads[i] = ad;
00567               }
00568               i++;
00569               rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
00570        }
00571        mdb->mi_numads = i-1;
00572 
00573 done:
00574        if ( rc == MDB_NOTFOUND )
00575               rc = 0;
00576 
00577        mdb_cursor_close( mc );
00578 
00579        return rc;
00580 }
00581 
00582 int mdb_ad_get( struct mdb_info *mdb, MDB_txn *txn, AttributeDescription *ad )
00583 {
00584        int i, rc;
00585        MDB_val key, val;
00586 
00587        rc = mdb_ad_read( mdb, txn );
00588        if (rc)
00589               return rc;
00590 
00591        if ( mdb->mi_adxs[ad->ad_index] )
00592               return 0;
00593 
00594        i = mdb->mi_numads+1;
00595        key.mv_size = sizeof(int);
00596        key.mv_data = &i;
00597        val.mv_size = ad->ad_cname.bv_len;
00598        val.mv_data = ad->ad_cname.bv_val;
00599 
00600        rc = mdb_put( txn, mdb->mi_ad2id, &key, &val, 0 );
00601        if ( rc == MDB_SUCCESS ) {
00602               mdb->mi_adxs[ad->ad_index] = i;
00603               mdb->mi_ads[i] = ad;
00604               mdb->mi_numads++;
00605        } else {
00606               Debug( LDAP_DEBUG_ANY,
00607                      "mdb_ad_get: mdb_put failed %s(%d)\n",
00608                      mdb_strerror(rc), rc, 0);
00609        }
00610 
00611        return rc;
00612 }