attr.c revision 1.1.1.1.10.1 1 /* $NetBSD: attr.c,v 1.1.1.1.10.1 2017/03/20 06:56:17 pgoyette Exp $ */
2
3 /* attr.c - backend routines for dealing with attributes */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2000-2016 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 <sys/cdefs.h>
20 __RCSID("$NetBSD: attr.c,v 1.1.1.1.10.1 2017/03/20 06:56:17 pgoyette Exp $");
21
22 #include "portable.h"
23
24 #include <stdio.h>
25
26 #include <ac/socket.h>
27 #include <ac/string.h>
28
29 #include "slap.h"
30 #include "back-mdb.h"
31 #include "config.h"
32 #include "lutil.h"
33
34 /* Find the ad, return -1 if not found,
35 * set point for insertion if ins is non-NULL
36 */
37 int
38 mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
39 {
40 unsigned base = 0, cursor = 0;
41 unsigned n = mdb->mi_nattrs;
42 int val = 0;
43
44 while ( 0 < n ) {
45 unsigned pivot = n >> 1;
46 cursor = base + pivot;
47
48 val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
49 if ( val < 0 ) {
50 n = pivot;
51 } else if ( val > 0 ) {
52 base = cursor + 1;
53 n -= pivot + 1;
54 } else {
55 return cursor;
56 }
57 }
58 if ( ins ) {
59 if ( val > 0 )
60 ++cursor;
61 *ins = cursor;
62 }
63 return -1;
64 }
65
66 static int
67 ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
68 {
69 int x;
70 int i = mdb_attr_slot( mdb, a->ai_desc, &x );
71
72 /* Is it a dup? */
73 if ( i >= 0 )
74 return -1;
75
76 mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) *
77 sizeof( AttrInfo * ));
78 if ( x < mdb->mi_nattrs )
79 AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
80 ( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
81 mdb->mi_attrs[x] = a;
82 mdb->mi_nattrs++;
83 return 0;
84 }
85
86 AttrInfo *
87 mdb_attr_mask(
88 struct mdb_info *mdb,
89 AttributeDescription *desc )
90 {
91 int i = mdb_attr_slot( mdb, desc, NULL );
92 return i < 0 ? NULL : mdb->mi_attrs[i];
93 }
94
95 /* Open all un-opened index DB handles */
96 int
97 mdb_attr_dbs_open(
98 BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
99 {
100 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
101 MDB_txn *txn;
102 MDB_dbi *dbis = NULL;
103 int i, flags;
104 int rc;
105
106 txn = tx0;
107 if ( txn == NULL ) {
108 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
109 if ( rc ) {
110 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
111 "txn_begin failed: %s (%d).",
112 be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
113 Debug( LDAP_DEBUG_ANY,
114 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
115 cr->msg, 0, 0 );
116 return rc;
117 }
118 dbis = ch_calloc( 1, mdb->mi_nattrs * sizeof(MDB_dbi) );
119 } else {
120 rc = 0;
121 }
122
123 flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
124 if ( !(slapMode & SLAP_TOOL_READONLY) )
125 flags |= MDB_CREATE;
126
127 for ( i=0; i<mdb->mi_nattrs; i++ ) {
128 if ( mdb->mi_attrs[i]->ai_dbi ) /* already open */
129 continue;
130 rc = mdb_dbi_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
131 flags, &mdb->mi_attrs[i]->ai_dbi );
132 if ( rc ) {
133 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
134 "mdb_dbi_open(%s) failed: %s (%d).",
135 be->be_suffix[0].bv_val,
136 mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
137 mdb_strerror(rc), rc );
138 Debug( LDAP_DEBUG_ANY,
139 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
140 cr->msg, 0, 0 );
141 break;
142 }
143 /* Remember newly opened DBI handles */
144 if ( dbis )
145 dbis[i] = mdb->mi_attrs[i]->ai_dbi;
146 }
147
148 /* Only commit if this is our txn */
149 if ( tx0 == NULL ) {
150 if ( !rc ) {
151 rc = mdb_txn_commit( txn );
152 if ( rc ) {
153 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
154 "txn_commit failed: %s (%d).",
155 be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
156 Debug( LDAP_DEBUG_ANY,
157 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
158 cr->msg, 0, 0 );
159 }
160 } else {
161 mdb_txn_abort( txn );
162 }
163 /* Something failed, forget anything we just opened */
164 if ( rc ) {
165 for ( i=0; i<mdb->mi_nattrs; i++ ) {
166 if ( dbis[i] ) {
167 mdb->mi_attrs[i]->ai_dbi = 0;
168 mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
169 }
170 }
171 mdb_attr_flush( mdb );
172 }
173 ch_free( dbis );
174 }
175
176 return rc;
177 }
178
179 void
180 mdb_attr_dbs_close(
181 struct mdb_info *mdb
182 )
183 {
184 int i;
185 for ( i=0; i<mdb->mi_nattrs; i++ )
186 if ( mdb->mi_attrs[i]->ai_dbi ) {
187 mdb_dbi_close( mdb->mi_dbenv, mdb->mi_attrs[i]->ai_dbi );
188 mdb->mi_attrs[i]->ai_dbi = 0;
189 }
190 }
191
192 int
193 mdb_attr_index_config(
194 struct mdb_info *mdb,
195 const char *fname,
196 int lineno,
197 int argc,
198 char **argv,
199 struct config_reply_s *c_reply)
200 {
201 int rc = 0;
202 int i;
203 slap_mask_t mask;
204 char **attrs;
205 char **indexes = NULL;
206
207 attrs = ldap_str2charray( argv[0], "," );
208
209 if( attrs == NULL ) {
210 fprintf( stderr, "%s: line %d: "
211 "no attributes specified: %s\n",
212 fname, lineno, argv[0] );
213 return LDAP_PARAM_ERROR;
214 }
215
216 if ( argc > 1 ) {
217 indexes = ldap_str2charray( argv[1], "," );
218
219 if( indexes == NULL ) {
220 fprintf( stderr, "%s: line %d: "
221 "no indexes specified: %s\n",
222 fname, lineno, argv[1] );
223 rc = LDAP_PARAM_ERROR;
224 goto done;
225 }
226 }
227
228 if( indexes == NULL ) {
229 mask = mdb->mi_defaultmask;
230
231 } else {
232 mask = 0;
233
234 for ( i = 0; indexes[i] != NULL; i++ ) {
235 slap_mask_t index;
236 rc = slap_str2index( indexes[i], &index );
237
238 if( rc != LDAP_SUCCESS ) {
239 if ( c_reply )
240 {
241 snprintf(c_reply->msg, sizeof(c_reply->msg),
242 "index type \"%s\" undefined", indexes[i] );
243
244 fprintf( stderr, "%s: line %d: %s\n",
245 fname, lineno, c_reply->msg );
246 }
247 rc = LDAP_PARAM_ERROR;
248 goto done;
249 }
250
251 mask |= index;
252 }
253 }
254
255 if( !mask ) {
256 if ( c_reply )
257 {
258 snprintf(c_reply->msg, sizeof(c_reply->msg),
259 "no indexes selected" );
260 fprintf( stderr, "%s: line %d: %s\n",
261 fname, lineno, c_reply->msg );
262 }
263 rc = LDAP_PARAM_ERROR;
264 goto done;
265 }
266
267 for ( i = 0; attrs[i] != NULL; i++ ) {
268 AttrInfo *a;
269 AttributeDescription *ad;
270 const char *text;
271 #ifdef LDAP_COMP_MATCH
272 ComponentReference* cr = NULL;
273 AttrInfo *a_cr = NULL;
274 #endif
275
276 if( strcasecmp( attrs[i], "default" ) == 0 ) {
277 mdb->mi_defaultmask |= mask;
278 continue;
279 }
280
281 #ifdef LDAP_COMP_MATCH
282 if ( is_component_reference( attrs[i] ) ) {
283 rc = extract_component_reference( attrs[i], &cr );
284 if ( rc != LDAP_SUCCESS ) {
285 if ( c_reply )
286 {
287 snprintf(c_reply->msg, sizeof(c_reply->msg),
288 "index component reference\"%s\" undefined",
289 attrs[i] );
290 fprintf( stderr, "%s: line %d: %s\n",
291 fname, lineno, c_reply->msg );
292 }
293 goto done;
294 }
295 cr->cr_indexmask = mask;
296 /*
297 * After extracting a component reference
298 * only the name of a attribute will be remaining
299 */
300 } else {
301 cr = NULL;
302 }
303 #endif
304 ad = NULL;
305 rc = slap_str2ad( attrs[i], &ad, &text );
306
307 if( rc != LDAP_SUCCESS ) {
308 if ( c_reply )
309 {
310 snprintf(c_reply->msg, sizeof(c_reply->msg),
311 "index attribute \"%s\" undefined",
312 attrs[i] );
313
314 fprintf( stderr, "%s: line %d: %s\n",
315 fname, lineno, c_reply->msg );
316 }
317 goto done;
318 }
319
320 if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
321 if (c_reply) {
322 snprintf(c_reply->msg, sizeof(c_reply->msg),
323 "index of attribute \"%s\" disallowed", attrs[i] );
324 fprintf( stderr, "%s: line %d: %s\n",
325 fname, lineno, c_reply->msg );
326 }
327 rc = LDAP_UNWILLING_TO_PERFORM;
328 goto done;
329 }
330
331 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
332 ad->ad_type->sat_approx
333 && ad->ad_type->sat_approx->smr_indexer
334 && ad->ad_type->sat_approx->smr_filter ) )
335 {
336 if (c_reply) {
337 snprintf(c_reply->msg, sizeof(c_reply->msg),
338 "approx index of attribute \"%s\" disallowed", attrs[i] );
339 fprintf( stderr, "%s: line %d: %s\n",
340 fname, lineno, c_reply->msg );
341 }
342 rc = LDAP_INAPPROPRIATE_MATCHING;
343 goto done;
344 }
345
346 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
347 ad->ad_type->sat_equality
348 && ad->ad_type->sat_equality->smr_indexer
349 && ad->ad_type->sat_equality->smr_filter ) )
350 {
351 if (c_reply) {
352 snprintf(c_reply->msg, sizeof(c_reply->msg),
353 "equality index of attribute \"%s\" disallowed", attrs[i] );
354 fprintf( stderr, "%s: line %d: %s\n",
355 fname, lineno, c_reply->msg );
356 }
357 rc = LDAP_INAPPROPRIATE_MATCHING;
358 goto done;
359 }
360
361 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
362 ad->ad_type->sat_substr
363 && ad->ad_type->sat_substr->smr_indexer
364 && ad->ad_type->sat_substr->smr_filter ) )
365 {
366 if (c_reply) {
367 snprintf(c_reply->msg, sizeof(c_reply->msg),
368 "substr index of attribute \"%s\" disallowed", attrs[i] );
369 fprintf( stderr, "%s: line %d: %s\n",
370 fname, lineno, c_reply->msg );
371 }
372 rc = LDAP_INAPPROPRIATE_MATCHING;
373 goto done;
374 }
375
376 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
377 ad->ad_cname.bv_val, mask, 0 );
378
379 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
380
381 #ifdef LDAP_COMP_MATCH
382 a->ai_cr = NULL;
383 #endif
384 a->ai_cursor = NULL;
385 a->ai_flist = NULL;
386 a->ai_clist = NULL;
387 a->ai_root = NULL;
388 a->ai_desc = ad;
389 a->ai_dbi = 0;
390
391 if ( mdb->mi_flags & MDB_IS_OPEN ) {
392 a->ai_indexmask = 0;
393 a->ai_newmask = mask;
394 } else {
395 a->ai_indexmask = mask;
396 a->ai_newmask = 0;
397 }
398
399 #ifdef LDAP_COMP_MATCH
400 if ( cr ) {
401 a_cr = mdb_attr_mask( mdb, ad );
402 if ( a_cr ) {
403 /*
404 * AttrInfo is already in AVL
405 * just add the extracted component reference
406 * in the AttrInfo
407 */
408 rc = insert_component_reference( cr, &a_cr->ai_cr );
409 if ( rc != LDAP_SUCCESS) {
410 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
411 rc = LDAP_PARAM_ERROR;
412 goto done;
413 }
414 continue;
415 } else {
416 rc = insert_component_reference( cr, &a->ai_cr );
417 if ( rc != LDAP_SUCCESS) {
418 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
419 rc = LDAP_PARAM_ERROR;
420 goto done;
421 }
422 }
423 }
424 #endif
425 rc = ainfo_insert( mdb, a );
426 if( rc ) {
427 if ( mdb->mi_flags & MDB_IS_OPEN ) {
428 AttrInfo *b = mdb_attr_mask( mdb, ad );
429 /* If there is already an index defined for this attribute
430 * it must be replaced. Otherwise we end up with multiple
431 * olcIndex values for the same attribute */
432 if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
433 /* If we were editing this attr, reset it */
434 b->ai_indexmask &= ~MDB_INDEX_DELETING;
435 /* If this is leftover from a previous add, commit it */
436 if ( b->ai_newmask )
437 b->ai_indexmask = b->ai_newmask;
438 b->ai_newmask = a->ai_newmask;
439 ch_free( a );
440 rc = 0;
441 continue;
442 }
443 }
444 if (c_reply) {
445 snprintf(c_reply->msg, sizeof(c_reply->msg),
446 "duplicate index definition for attr \"%s\"",
447 attrs[i] );
448 fprintf( stderr, "%s: line %d: %s\n",
449 fname, lineno, c_reply->msg );
450 }
451
452 rc = LDAP_PARAM_ERROR;
453 goto done;
454 }
455 }
456
457 done:
458 ldap_charray_free( attrs );
459 if ( indexes != NULL ) ldap_charray_free( indexes );
460
461 return rc;
462 }
463
464 static int
465 mdb_attr_index_unparser( void *v1, void *v2 )
466 {
467 AttrInfo *ai = v1;
468 BerVarray *bva = v2;
469 struct berval bv;
470 char *ptr;
471
472 slap_index2bvlen( ai->ai_indexmask, &bv );
473 if ( bv.bv_len ) {
474 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
475 ptr = ch_malloc( bv.bv_len+1 );
476 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
477 *bv.bv_val++ = ' ';
478 slap_index2bv( ai->ai_indexmask, &bv );
479 bv.bv_val = ptr;
480 ber_bvarray_add( bva, &bv );
481 }
482 return 0;
483 }
484
485 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
486 static AttrInfo aidef = { &addef };
487
488 void
489 mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
490 {
491 int i;
492
493 if ( mdb->mi_defaultmask ) {
494 aidef.ai_indexmask = mdb->mi_defaultmask;
495 mdb_attr_index_unparser( &aidef, bva );
496 }
497 for ( i=0; i<mdb->mi_nattrs; i++ )
498 mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
499 }
500
501 void
502 mdb_attr_info_free( AttrInfo *ai )
503 {
504 #ifdef LDAP_COMP_MATCH
505 free( ai->ai_cr );
506 #endif
507 free( ai );
508 }
509
510 void
511 mdb_attr_index_destroy( struct mdb_info *mdb )
512 {
513 int i;
514
515 for ( i=0; i<mdb->mi_nattrs; i++ )
516 mdb_attr_info_free( mdb->mi_attrs[i] );
517
518 free( mdb->mi_attrs );
519 }
520
521 void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
522 {
523 int i;
524
525 i = mdb_attr_slot( mdb, ad, NULL );
526 if ( i >= 0 ) {
527 mdb_attr_info_free( mdb->mi_attrs[i] );
528 mdb->mi_nattrs--;
529 for (; i<mdb->mi_nattrs; i++)
530 mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
531 }
532 }
533
534 void mdb_attr_flush( struct mdb_info *mdb )
535 {
536 int i;
537
538 for ( i=0; i<mdb->mi_nattrs; i++ ) {
539 if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
540 int j;
541 mdb_attr_info_free( mdb->mi_attrs[i] );
542 mdb->mi_nattrs--;
543 for (j=i; j<mdb->mi_nattrs; j++)
544 mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
545 i--;
546 }
547 }
548 }
549
550 int mdb_ad_read( struct mdb_info *mdb, MDB_txn *txn )
551 {
552 int i, rc;
553 MDB_cursor *mc;
554 MDB_val key, data;
555 struct berval bdata;
556 const char *text;
557 AttributeDescription *ad;
558
559 rc = mdb_cursor_open( txn, mdb->mi_ad2id, &mc );
560 if ( rc ) {
561 Debug( LDAP_DEBUG_ANY,
562 "mdb_ad_read: cursor_open failed %s(%d)\n",
563 mdb_strerror(rc), rc, 0);
564 return rc;
565 }
566
567 /* our array is 1-based, an index of 0 means no data */
568 i = mdb->mi_numads+1;
569 key.mv_size = sizeof(int);
570 key.mv_data = &i;
571
572 rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
573
574 while ( rc == MDB_SUCCESS ) {
575 bdata.bv_len = data.mv_size;
576 bdata.bv_val = data.mv_data;
577 ad = NULL;
578 rc = slap_bv2ad( &bdata, &ad, &text );
579 if ( rc ) {
580 rc = slap_bv2undef_ad( &bdata, &mdb->mi_ads[i], &text, 0 );
581 } else {
582 if ( ad->ad_index >= MDB_MAXADS ) {
583 Debug( LDAP_DEBUG_ANY,
584 "mdb_adb_read: too many AttributeDescriptions in use\n",
585 0, 0, 0 );
586 return LDAP_OTHER;
587 }
588 mdb->mi_adxs[ad->ad_index] = i;
589 mdb->mi_ads[i] = ad;
590 }
591 i++;
592 rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
593 }
594 mdb->mi_numads = i-1;
595
596 done:
597 if ( rc == MDB_NOTFOUND )
598 rc = 0;
599
600 mdb_cursor_close( mc );
601
602 return rc;
603 }
604
605 int mdb_ad_get( struct mdb_info *mdb, MDB_txn *txn, AttributeDescription *ad )
606 {
607 int i, rc;
608 MDB_val key, val;
609
610 rc = mdb_ad_read( mdb, txn );
611 if (rc)
612 return rc;
613
614 if ( mdb->mi_adxs[ad->ad_index] )
615 return 0;
616
617 i = mdb->mi_numads+1;
618 key.mv_size = sizeof(int);
619 key.mv_data = &i;
620 val.mv_size = ad->ad_cname.bv_len;
621 val.mv_data = ad->ad_cname.bv_val;
622
623 rc = mdb_put( txn, mdb->mi_ad2id, &key, &val, 0 );
624 if ( rc == MDB_SUCCESS ) {
625 mdb->mi_adxs[ad->ad_index] = i;
626 mdb->mi_ads[i] = ad;
627 mdb->mi_numads = i;
628 } else {
629 Debug( LDAP_DEBUG_ANY,
630 "mdb_ad_get: mdb_put failed %s(%d)\n",
631 mdb_strerror(rc), rc, 0);
632 }
633
634 return rc;
635 }
636