1/* $NetBSD$ */ 2 3/* attr.c - backend routines for dealing with attributes */ 4/* OpenLDAP: pkg/ldap/servers/slapd/back-bdb/attr.c,v 1.36.2.10 2010/04/13 20:23:23 kurt Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2010 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19#include "portable.h" 20 21#include <stdio.h> 22 23#include <ac/socket.h> 24#include <ac/string.h> 25 26#include "slap.h" 27#include "back-bdb.h" 28#include "config.h" 29#include "lutil.h" 30 31/* Find the ad, return -1 if not found, 32 * set point for insertion if ins is non-NULL 33 */ 34int 35bdb_attr_slot( struct bdb_info *bdb, AttributeDescription *ad, int *ins ) 36{ 37 unsigned base = 0, cursor = 0; 38 unsigned n = bdb->bi_nattrs; 39 int val = 0; 40 41 while ( 0 < n ) { 42 unsigned pivot = n >> 1; 43 cursor = base + pivot; 44 45 val = SLAP_PTRCMP( ad, bdb->bi_attrs[cursor]->ai_desc ); 46 if ( val < 0 ) { 47 n = pivot; 48 } else if ( val > 0 ) { 49 base = cursor + 1; 50 n -= pivot + 1; 51 } else { 52 return cursor; 53 } 54 } 55 if ( ins ) { 56 if ( val > 0 ) 57 ++cursor; 58 *ins = cursor; 59 } 60 return -1; 61} 62 63static int 64ainfo_insert( struct bdb_info *bdb, AttrInfo *a ) 65{ 66 int x; 67 int i = bdb_attr_slot( bdb, a->ai_desc, &x ); 68 69 /* Is it a dup? */ 70 if ( i >= 0 ) 71 return -1; 72 73 bdb->bi_attrs = ch_realloc( bdb->bi_attrs, ( bdb->bi_nattrs+1 ) * 74 sizeof( AttrInfo * )); 75 if ( x < bdb->bi_nattrs ) 76 AC_MEMCPY( &bdb->bi_attrs[x+1], &bdb->bi_attrs[x], 77 ( bdb->bi_nattrs - x ) * sizeof( AttrInfo *)); 78 bdb->bi_attrs[x] = a; 79 bdb->bi_nattrs++; 80 return 0; 81} 82 83AttrInfo * 84bdb_attr_mask( 85 struct bdb_info *bdb, 86 AttributeDescription *desc ) 87{ 88 int i = bdb_attr_slot( bdb, desc, NULL ); 89 return i < 0 ? NULL : bdb->bi_attrs[i]; 90} 91 92int 93bdb_attr_index_config( 94 struct bdb_info *bdb, 95 const char *fname, 96 int lineno, 97 int argc, 98 char **argv, 99 struct config_reply_s *c_reply) 100{ 101 int rc = 0; 102 int i; 103 slap_mask_t mask; 104 char **attrs; 105 char **indexes = NULL; 106 107 attrs = ldap_str2charray( argv[0], "," ); 108 109 if( attrs == NULL ) { 110 fprintf( stderr, "%s: line %d: " 111 "no attributes specified: %s\n", 112 fname, lineno, argv[0] ); 113 return LDAP_PARAM_ERROR; 114 } 115 116 if ( argc > 1 ) { 117 indexes = ldap_str2charray( argv[1], "," ); 118 119 if( indexes == NULL ) { 120 fprintf( stderr, "%s: line %d: " 121 "no indexes specified: %s\n", 122 fname, lineno, argv[1] ); 123 rc = LDAP_PARAM_ERROR; 124 goto done; 125 } 126 } 127 128 if( indexes == NULL ) { 129 mask = bdb->bi_defaultmask; 130 131 } else { 132 mask = 0; 133 134 for ( i = 0; indexes[i] != NULL; i++ ) { 135 slap_mask_t index; 136 rc = slap_str2index( indexes[i], &index ); 137 138 if( rc != LDAP_SUCCESS ) { 139 if ( c_reply ) 140 { 141 snprintf(c_reply->msg, sizeof(c_reply->msg), 142 "index type \"%s\" undefined", indexes[i] ); 143 144 fprintf( stderr, "%s: line %d: %s\n", 145 fname, lineno, c_reply->msg ); 146 } 147 rc = LDAP_PARAM_ERROR; 148 goto done; 149 } 150 151 mask |= index; 152 } 153 } 154 155 if( !mask ) { 156 if ( c_reply ) 157 { 158 snprintf(c_reply->msg, sizeof(c_reply->msg), 159 "no indexes selected" ); 160 fprintf( stderr, "%s: line %d: %s\n", 161 fname, lineno, c_reply->msg ); 162 } 163 rc = LDAP_PARAM_ERROR; 164 goto done; 165 } 166 167 for ( i = 0; attrs[i] != NULL; i++ ) { 168 AttrInfo *a; 169 AttributeDescription *ad; 170 const char *text; 171#ifdef LDAP_COMP_MATCH 172 ComponentReference* cr = NULL; 173 AttrInfo *a_cr = NULL; 174#endif 175 176 if( strcasecmp( attrs[i], "default" ) == 0 ) { 177 bdb->bi_defaultmask |= mask; 178 continue; 179 } 180 181#ifdef LDAP_COMP_MATCH 182 if ( is_component_reference( attrs[i] ) ) { 183 rc = extract_component_reference( attrs[i], &cr ); 184 if ( rc != LDAP_SUCCESS ) { 185 if ( c_reply ) 186 { 187 snprintf(c_reply->msg, sizeof(c_reply->msg), 188 "index component reference\"%s\" undefined", 189 attrs[i] ); 190 fprintf( stderr, "%s: line %d: %s\n", 191 fname, lineno, c_reply->msg ); 192 } 193 goto done; 194 } 195 cr->cr_indexmask = mask; 196 /* 197 * After extracting a component reference 198 * only the name of a attribute will be remaining 199 */ 200 } else { 201 cr = NULL; 202 } 203#endif 204 ad = NULL; 205 rc = slap_str2ad( attrs[i], &ad, &text ); 206 207 if( rc != LDAP_SUCCESS ) { 208 if ( c_reply ) 209 { 210 snprintf(c_reply->msg, sizeof(c_reply->msg), 211 "index attribute \"%s\" undefined", 212 attrs[i] ); 213 214 fprintf( stderr, "%s: line %d: %s\n", 215 fname, lineno, c_reply->msg ); 216 } 217 goto done; 218 } 219 220 if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) { 221 if (c_reply) { 222 snprintf(c_reply->msg, sizeof(c_reply->msg), 223 "index of attribute \"%s\" disallowed", attrs[i] ); 224 fprintf( stderr, "%s: line %d: %s\n", 225 fname, lineno, c_reply->msg ); 226 } 227 rc = LDAP_UNWILLING_TO_PERFORM; 228 goto done; 229 } 230 231 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !( 232 ad->ad_type->sat_approx 233 && ad->ad_type->sat_approx->smr_indexer 234 && ad->ad_type->sat_approx->smr_filter ) ) 235 { 236 if (c_reply) { 237 snprintf(c_reply->msg, sizeof(c_reply->msg), 238 "approx index of attribute \"%s\" disallowed", attrs[i] ); 239 fprintf( stderr, "%s: line %d: %s\n", 240 fname, lineno, c_reply->msg ); 241 } 242 rc = LDAP_INAPPROPRIATE_MATCHING; 243 goto done; 244 } 245 246 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !( 247 ad->ad_type->sat_equality 248 && ad->ad_type->sat_equality->smr_indexer 249 && ad->ad_type->sat_equality->smr_filter ) ) 250 { 251 if (c_reply) { 252 snprintf(c_reply->msg, sizeof(c_reply->msg), 253 "equality index of attribute \"%s\" disallowed", attrs[i] ); 254 fprintf( stderr, "%s: line %d: %s\n", 255 fname, lineno, c_reply->msg ); 256 } 257 rc = LDAP_INAPPROPRIATE_MATCHING; 258 goto done; 259 } 260 261 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !( 262 ad->ad_type->sat_substr 263 && ad->ad_type->sat_substr->smr_indexer 264 && ad->ad_type->sat_substr->smr_filter ) ) 265 { 266 if (c_reply) { 267 snprintf(c_reply->msg, sizeof(c_reply->msg), 268 "substr index of attribute \"%s\" disallowed", attrs[i] ); 269 fprintf( stderr, "%s: line %d: %s\n", 270 fname, lineno, c_reply->msg ); 271 } 272 rc = LDAP_INAPPROPRIATE_MATCHING; 273 goto done; 274 } 275 276 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n", 277 ad->ad_cname.bv_val, mask, 0 ); 278 279 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) ); 280 281#ifdef LDAP_COMP_MATCH 282 a->ai_cr = NULL; 283#endif 284 a->ai_desc = ad; 285 286 if ( bdb->bi_flags & BDB_IS_OPEN ) { 287 a->ai_indexmask = 0; 288 a->ai_newmask = mask; 289 } else { 290 a->ai_indexmask = mask; 291 a->ai_newmask = 0; 292 } 293 294#ifdef LDAP_COMP_MATCH 295 if ( cr ) { 296 a_cr = bdb_attr_mask( bdb, ad ); 297 if ( a_cr ) { 298 /* 299 * AttrInfo is already in AVL 300 * just add the extracted component reference 301 * in the AttrInfo 302 */ 303 rc = insert_component_reference( cr, &a_cr->ai_cr ); 304 if ( rc != LDAP_SUCCESS) { 305 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]); 306 rc = LDAP_PARAM_ERROR; 307 goto done; 308 } 309 continue; 310 } else { 311 rc = insert_component_reference( cr, &a->ai_cr ); 312 if ( rc != LDAP_SUCCESS) { 313 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]); 314 rc = LDAP_PARAM_ERROR; 315 goto done; 316 } 317 } 318 } 319#endif 320 rc = ainfo_insert( bdb, a ); 321 if( rc ) { 322 if ( bdb->bi_flags & BDB_IS_OPEN ) { 323 AttrInfo *b = bdb_attr_mask( bdb, ad ); 324 /* If there is already an index defined for this attribute 325 * it must be replaced. Otherwise we end up with multiple 326 * olcIndex values for the same attribute */ 327 if ( b->ai_indexmask & BDB_INDEX_DELETING ) { 328 /* If we were editing this attr, reset it */ 329 b->ai_indexmask &= ~BDB_INDEX_DELETING; 330 /* If this is leftover from a previous add, commit it */ 331 if ( b->ai_newmask ) 332 b->ai_indexmask = b->ai_newmask; 333 b->ai_newmask = a->ai_newmask; 334 ch_free( a ); 335 rc = 0; 336 continue; 337 } 338 } 339 if (c_reply) { 340 snprintf(c_reply->msg, sizeof(c_reply->msg), 341 "duplicate index definition for attr \"%s\"", 342 attrs[i] ); 343 fprintf( stderr, "%s: line %d: %s\n", 344 fname, lineno, c_reply->msg ); 345 } 346 347 rc = LDAP_PARAM_ERROR; 348 goto done; 349 } 350 } 351 352done: 353 ldap_charray_free( attrs ); 354 if ( indexes != NULL ) ldap_charray_free( indexes ); 355 356 return rc; 357} 358 359static int 360bdb_attr_index_unparser( void *v1, void *v2 ) 361{ 362 AttrInfo *ai = v1; 363 BerVarray *bva = v2; 364 struct berval bv; 365 char *ptr; 366 367 slap_index2bvlen( ai->ai_indexmask, &bv ); 368 if ( bv.bv_len ) { 369 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1; 370 ptr = ch_malloc( bv.bv_len+1 ); 371 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val ); 372 *bv.bv_val++ = ' '; 373 slap_index2bv( ai->ai_indexmask, &bv ); 374 bv.bv_val = ptr; 375 ber_bvarray_add( bva, &bv ); 376 } 377 return 0; 378} 379 380static AttributeDescription addef = { NULL, NULL, BER_BVC("default") }; 381static AttrInfo aidef = { &addef }; 382 383void 384bdb_attr_index_unparse( struct bdb_info *bdb, BerVarray *bva ) 385{ 386 int i; 387 388 if ( bdb->bi_defaultmask ) { 389 aidef.ai_indexmask = bdb->bi_defaultmask; 390 bdb_attr_index_unparser( &aidef, bva ); 391 } 392 for ( i=0; i<bdb->bi_nattrs; i++ ) 393 bdb_attr_index_unparser( bdb->bi_attrs[i], bva ); 394} 395 396void 397bdb_attr_info_free( AttrInfo *ai ) 398{ 399#ifdef LDAP_COMP_MATCH 400 free( ai->ai_cr ); 401#endif 402 free( ai ); 403} 404 405void 406bdb_attr_index_destroy( struct bdb_info *bdb ) 407{ 408 int i; 409 410 for ( i=0; i<bdb->bi_nattrs; i++ ) 411 bdb_attr_info_free( bdb->bi_attrs[i] ); 412 413 free( bdb->bi_attrs ); 414} 415 416void bdb_attr_index_free( struct bdb_info *bdb, AttributeDescription *ad ) 417{ 418 int i; 419 420 i = bdb_attr_slot( bdb, ad, NULL ); 421 if ( i >= 0 ) { 422 bdb_attr_info_free( bdb->bi_attrs[i] ); 423 bdb->bi_nattrs--; 424 for (; i<bdb->bi_nattrs; i++) 425 bdb->bi_attrs[i] = bdb->bi_attrs[i+1]; 426 } 427} 428 429void bdb_attr_flush( struct bdb_info *bdb ) 430{ 431 int i; 432 433 for ( i=0; i<bdb->bi_nattrs; i++ ) { 434 if ( bdb->bi_attrs[i]->ai_indexmask & BDB_INDEX_DELETING ) { 435 int j; 436 bdb_attr_info_free( bdb->bi_attrs[i] ); 437 bdb->bi_nattrs--; 438 for (j=i; j<bdb->bi_nattrs; j++) 439 bdb->bi_attrs[j] = bdb->bi_attrs[j+1]; 440 i--; 441 } 442 } 443} 444