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