1 /* $NetBSD: attr.c,v 1.2 2021/08/14 16:15:02 christos Exp $ */ 2 3 /* OpenLDAP WiredTiger backend */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2002-2021 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 /* ACKNOWLEDGEMENTS: 19 * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp> 20 * based on back-bdb for inclusion in OpenLDAP Software. 21 * WiredTiger is a product of MongoDB Inc. 22 */ 23 24 #include "back-wt.h" 25 #include "slap-config.h" 26 27 /* Find the ad, return -1 if not found, 28 * set point for insertion if ins is non-NULL 29 */ 30 int 31 wt_attr_slot( struct wt_info *wi, AttributeDescription *ad, int *ins ) 32 { 33 unsigned base = 0, cursor = 0; 34 unsigned n = wi->wi_nattrs; 35 int val = 0; 36 37 while ( 0 < n ) { 38 unsigned pivot = n >> 1; 39 cursor = base + pivot; 40 41 val = SLAP_PTRCMP( ad, wi->wi_attrs[cursor]->ai_desc ); 42 if ( val < 0 ) { 43 n = pivot; 44 } else if ( val > 0 ) { 45 base = cursor + 1; 46 n -= pivot + 1; 47 } else { 48 return cursor; 49 } 50 } 51 if ( ins ) { 52 if ( val > 0 ) 53 ++cursor; 54 *ins = cursor; 55 } 56 return -1; 57 } 58 59 static int 60 ainfo_insert( struct wt_info *wi, AttrInfo *a ) 61 { 62 int x; 63 int i = wt_attr_slot( wi, a->ai_desc, &x ); 64 65 /* Is it a dup? */ 66 if ( i >= 0 ) 67 return -1; 68 69 wi->wi_attrs = ch_realloc( wi->wi_attrs, ( wi->wi_nattrs+1 ) * 70 sizeof( AttrInfo * )); 71 if ( x < wi->wi_nattrs ) 72 AC_MEMCPY( &wi->wi_attrs[x+1], &wi->wi_attrs[x], 73 ( wi->wi_nattrs - x ) * sizeof( AttrInfo *)); 74 wi->wi_attrs[x] = a; 75 wi->wi_nattrs++; 76 return 0; 77 } 78 79 AttrInfo * 80 wt_attr_mask( 81 struct wt_info *wi, 82 AttributeDescription *desc ) 83 { 84 int i = wt_attr_slot( wi, desc, NULL ); 85 return i < 0 ? NULL : wi->wi_attrs[i]; 86 } 87 88 int 89 wt_attr_index_config( 90 struct wt_info *wi, 91 const char *fname, 92 int lineno, 93 int argc, 94 char **argv, 95 struct config_reply_s *c_reply) 96 { 97 int rc = 0; 98 int i; 99 slap_mask_t mask; 100 char **attrs; 101 char **indexes = NULL; 102 103 attrs = ldap_str2charray( argv[0], "," ); 104 105 if( attrs == NULL ) { 106 fprintf( stderr, "%s: line %d: " 107 "no attributes specified: %s\n", 108 fname, lineno, argv[0] ); 109 return LDAP_PARAM_ERROR; 110 } 111 112 if ( argc > 1 ) { 113 indexes = ldap_str2charray( argv[1], "," ); 114 115 if( indexes == NULL ) { 116 fprintf( stderr, "%s: line %d: " 117 "no indexes specified: %s\n", 118 fname, lineno, argv[1] ); 119 rc = LDAP_PARAM_ERROR; 120 goto done; 121 } 122 } 123 124 if( indexes == NULL ) { 125 mask = wi->wi_defaultmask; 126 127 } else { 128 mask = 0; 129 130 for ( i = 0; indexes[i] != NULL; i++ ) { 131 slap_mask_t index; 132 133 rc = slap_str2index( indexes[i], &index ); 134 135 if( rc != LDAP_SUCCESS ) { 136 if ( c_reply ) 137 { 138 snprintf(c_reply->msg, sizeof(c_reply->msg), 139 "index type \"%s\" undefined", indexes[i] ); 140 141 fprintf( stderr, "%s: line %d: %s\n", 142 fname, lineno, c_reply->msg ); 143 } 144 rc = LDAP_PARAM_ERROR; 145 goto done; 146 } 147 148 mask |= index; 149 } 150 } 151 152 if( !mask ) { 153 if ( c_reply ) 154 { 155 snprintf(c_reply->msg, sizeof(c_reply->msg), 156 "no indexes selected" ); 157 fprintf( stderr, "%s: line %d: %s\n", 158 fname, lineno, c_reply->msg ); 159 } 160 rc = LDAP_PARAM_ERROR; 161 goto done; 162 } 163 164 for ( i = 0; attrs[i] != NULL; i++ ) { 165 AttrInfo *a; 166 AttributeDescription *ad; 167 const char *text; 168 #ifdef LDAP_COMP_MATCH 169 ComponentReference* cr = NULL; 170 AttrInfo *a_cr = NULL; 171 #endif 172 173 if( strcasecmp( attrs[i], "default" ) == 0 ) { 174 wi->wi_defaultmask |= mask; 175 continue; 176 } 177 178 #ifdef LDAP_COMP_MATCH 179 if ( is_component_reference( attrs[i] ) ) { 180 rc = extract_component_reference( attrs[i], &cr ); 181 if ( rc != LDAP_SUCCESS ) { 182 if ( c_reply ) 183 { 184 snprintf(c_reply->msg, sizeof(c_reply->msg), 185 "index component reference\"%s\" undefined", 186 attrs[i] ); 187 fprintf( stderr, "%s: line %d: %s\n", 188 fname, lineno, c_reply->msg ); 189 } 190 goto done; 191 } 192 cr->cr_indexmask = mask; 193 /* 194 * After extracting a component reference 195 * only the name of a attribute will be remaining 196 */ 197 } else { 198 cr = NULL; 199 } 200 #endif 201 ad = NULL; 202 rc = slap_str2ad( attrs[i], &ad, &text ); 203 204 if( rc != LDAP_SUCCESS ) { 205 if ( c_reply ) 206 { 207 snprintf(c_reply->msg, sizeof(c_reply->msg), 208 "index attribute \"%s\" undefined", 209 attrs[i] ); 210 211 fprintf( stderr, "%s: line %d: %s\n", 212 fname, lineno, c_reply->msg ); 213 } 214 fail: 215 #ifdef LDAP_COMP_MATCH 216 ch_free( cr ); 217 #endif 218 goto done; 219 } 220 221 if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) { 222 if (c_reply) { 223 snprintf(c_reply->msg, sizeof(c_reply->msg), 224 "index of attribute \"%s\" disallowed", attrs[i] ); 225 fprintf( stderr, "%s: line %d: %s\n", 226 fname, lineno, c_reply->msg ); 227 } 228 rc = LDAP_UNWILLING_TO_PERFORM; 229 goto fail; 230 } 231 232 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !( 233 ad->ad_type->sat_approx 234 && ad->ad_type->sat_approx->smr_indexer 235 && ad->ad_type->sat_approx->smr_filter ) ) 236 { 237 if (c_reply) { 238 snprintf(c_reply->msg, sizeof(c_reply->msg), 239 "approx index of attribute \"%s\" disallowed", attrs[i] ); 240 fprintf( stderr, "%s: line %d: %s\n", 241 fname, lineno, c_reply->msg ); 242 } 243 rc = LDAP_INAPPROPRIATE_MATCHING; 244 goto fail; 245 } 246 247 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !( 248 ad->ad_type->sat_equality 249 && ad->ad_type->sat_equality->smr_indexer 250 && ad->ad_type->sat_equality->smr_filter ) ) 251 { 252 if (c_reply) { 253 snprintf(c_reply->msg, sizeof(c_reply->msg), 254 "equality index of attribute \"%s\" disallowed", attrs[i] ); 255 fprintf( stderr, "%s: line %d: %s\n", 256 fname, lineno, c_reply->msg ); 257 } 258 rc = LDAP_INAPPROPRIATE_MATCHING; 259 goto fail; 260 } 261 262 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !( 263 ad->ad_type->sat_substr 264 && ad->ad_type->sat_substr->smr_indexer 265 && ad->ad_type->sat_substr->smr_filter ) ) 266 { 267 if (c_reply) { 268 snprintf(c_reply->msg, sizeof(c_reply->msg), 269 "substr index of attribute \"%s\" disallowed", attrs[i] ); 270 fprintf( stderr, "%s: line %d: %s\n", 271 fname, lineno, c_reply->msg ); 272 } 273 rc = LDAP_INAPPROPRIATE_MATCHING; 274 goto fail; 275 } 276 277 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n", 278 ad->ad_cname.bv_val, mask ); 279 280 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) ); 281 282 #ifdef LDAP_COMP_MATCH 283 a->ai_cr = NULL; 284 #endif 285 a->ai_desc = ad; 286 287 if ( wi->wi_flags & WT_IS_OPEN ) { 288 a->ai_indexmask = 0; 289 a->ai_newmask = mask; 290 } else { 291 a->ai_indexmask = mask; 292 a->ai_newmask = 0; 293 } 294 295 #ifdef LDAP_COMP_MATCH 296 if ( cr ) { 297 a_cr = wt_attr_mask( wi, ad ); 298 if ( a_cr ) { 299 /* 300 * AttrInfo is already in AVL 301 * just add the extracted component reference 302 * in the AttrInfo 303 */ 304 ch_free( a ); 305 rc = insert_component_reference( cr, &a_cr->ai_cr ); 306 if ( rc != LDAP_SUCCESS) { 307 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]); 308 rc = LDAP_PARAM_ERROR; 309 goto fail; 310 } 311 continue; 312 } else { 313 rc = insert_component_reference( cr, &a->ai_cr ); 314 if ( rc != LDAP_SUCCESS) { 315 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]); 316 rc = LDAP_PARAM_ERROR; 317 ch_free( a ); 318 goto fail; 319 } 320 } 321 } 322 #endif 323 rc = ainfo_insert( wi, a ); 324 if( rc ) { 325 if ( wi->wi_flags & WT_IS_OPEN ) { 326 AttrInfo *b = wt_attr_mask( wi, ad ); 327 /* If there is already an index defined for this attribute 328 * it must be replaced. Otherwise we end up with multiple 329 * olcIndex values for the same attribute */ 330 if ( b->ai_indexmask & WT_INDEX_DELETING ) { 331 /* If we were editing this attr, reset it */ 332 b->ai_indexmask &= ~WT_INDEX_DELETING; 333 /* If this is leftover from a previous add, commit it */ 334 if ( b->ai_newmask ) 335 b->ai_indexmask = b->ai_newmask; 336 b->ai_newmask = a->ai_newmask; 337 ch_free( a ); 338 rc = 0; 339 continue; 340 } 341 } 342 if (c_reply) { 343 snprintf(c_reply->msg, sizeof(c_reply->msg), 344 "duplicate index definition for attr \"%s\"", 345 attrs[i] ); 346 fprintf( stderr, "%s: line %d: %s\n", 347 fname, lineno, c_reply->msg ); 348 } 349 350 rc = LDAP_PARAM_ERROR; 351 goto done; 352 } 353 } 354 355 done: 356 ldap_charray_free( attrs ); 357 if ( indexes != NULL ) ldap_charray_free( indexes ); 358 359 return rc; 360 } 361 362 void 363 wt_attr_info_free( AttrInfo *ai ) 364 { 365 #ifdef LDAP_COMP_MATCH 366 free( ai->ai_cr ); 367 #endif 368 free( ai ); 369 } 370 371 void 372 wt_attr_index_destroy( struct wt_info *wi ) 373 { 374 int i; 375 376 for ( i=0; i<wi->wi_nattrs; i++ ) 377 wt_attr_info_free( wi->wi_attrs[i] ); 378 379 free( wi->wi_attrs ); 380 } 381 382 383 384 /* 385 * Local variables: 386 * indent-tabs-mode: t 387 * tab-width: 4 388 * c-basic-offset: 4 389 * End: 390 */ 391