]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/attr.c
Happy new year (belated)
[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-2014 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                         goto done;
216                 }
217
218                 if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
219                         if (c_reply) {
220                                 snprintf(c_reply->msg, sizeof(c_reply->msg),
221                                         "index of attribute \"%s\" disallowed", attrs[i] );
222                                 fprintf( stderr, "%s: line %d: %s\n",
223                                         fname, lineno, c_reply->msg );
224                         }
225                         rc = LDAP_UNWILLING_TO_PERFORM;
226                         goto done;
227                 }
228
229                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
230                         ad->ad_type->sat_approx
231                                 && ad->ad_type->sat_approx->smr_indexer
232                                 && ad->ad_type->sat_approx->smr_filter ) )
233                 {
234                         if (c_reply) {
235                                 snprintf(c_reply->msg, sizeof(c_reply->msg),
236                                         "approx index of attribute \"%s\" disallowed", attrs[i] );
237                                 fprintf( stderr, "%s: line %d: %s\n",
238                                         fname, lineno, c_reply->msg );
239                         }
240                         rc = LDAP_INAPPROPRIATE_MATCHING;
241                         goto done;
242                 }
243
244                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
245                         ad->ad_type->sat_equality
246                                 && ad->ad_type->sat_equality->smr_indexer
247                                 && ad->ad_type->sat_equality->smr_filter ) )
248                 {
249                         if (c_reply) {
250                                 snprintf(c_reply->msg, sizeof(c_reply->msg),
251                                         "equality index of attribute \"%s\" disallowed", attrs[i] );
252                                 fprintf( stderr, "%s: line %d: %s\n",
253                                         fname, lineno, c_reply->msg );
254                         }
255                         rc = LDAP_INAPPROPRIATE_MATCHING;
256                         goto done;
257                 }
258
259                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
260                         ad->ad_type->sat_substr
261                                 && ad->ad_type->sat_substr->smr_indexer
262                                 && ad->ad_type->sat_substr->smr_filter ) )
263                 {
264                         if (c_reply) {
265                                 snprintf(c_reply->msg, sizeof(c_reply->msg),
266                                         "substr index of attribute \"%s\" disallowed", attrs[i] );
267                                 fprintf( stderr, "%s: line %d: %s\n",
268                                         fname, lineno, c_reply->msg );
269                         }
270                         rc = LDAP_INAPPROPRIATE_MATCHING;
271                         goto done;
272                 }
273
274                 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
275                         ad->ad_cname.bv_val, mask, 0 ); 
276
277                 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
278
279 #ifdef LDAP_COMP_MATCH
280                 a->ai_cr = NULL;
281 #endif
282                 a->ai_desc = ad;
283
284                 if ( bdb->bi_flags & BDB_IS_OPEN ) {
285                         a->ai_indexmask = 0;
286                         a->ai_newmask = mask;
287                 } else {
288                         a->ai_indexmask = mask;
289                         a->ai_newmask = 0;
290                 }
291
292 #ifdef LDAP_COMP_MATCH
293                 if ( cr ) {
294                         a_cr = bdb_attr_mask( bdb, ad );
295                         if ( a_cr ) {
296                                 /*
297                                  * AttrInfo is already in AVL
298                                  * just add the extracted component reference
299                                  * in the AttrInfo
300                                  */
301                                 rc = insert_component_reference( cr, &a_cr->ai_cr );
302                                 if ( rc != LDAP_SUCCESS) {
303                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
304                                         rc = LDAP_PARAM_ERROR;
305                                         goto done;
306                                 }
307                                 continue;
308                         } else {
309                                 rc = insert_component_reference( cr, &a->ai_cr );
310                                 if ( rc != LDAP_SUCCESS) {
311                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
312                                         rc = LDAP_PARAM_ERROR;
313                                         goto done;
314                                 }
315                         }
316                 }
317 #endif
318                 rc = ainfo_insert( bdb, a );
319                 if( rc ) {
320                         if ( bdb->bi_flags & BDB_IS_OPEN ) {
321                                 AttrInfo *b = bdb_attr_mask( bdb, ad );
322                                 /* If there is already an index defined for this attribute
323                                  * it must be replaced. Otherwise we end up with multiple 
324                                  * olcIndex values for the same attribute */
325                                 if ( b->ai_indexmask & BDB_INDEX_DELETING ) {
326                                         /* If we were editing this attr, reset it */
327                                         b->ai_indexmask &= ~BDB_INDEX_DELETING;
328                                         /* If this is leftover from a previous add, commit it */
329                                         if ( b->ai_newmask )
330                                                 b->ai_indexmask = b->ai_newmask;
331                                         b->ai_newmask = a->ai_newmask;
332                                         ch_free( a );
333                                         rc = 0;
334                                         continue;
335                                 }
336                         }
337                         if (c_reply) {
338                                 snprintf(c_reply->msg, sizeof(c_reply->msg),
339                                         "duplicate index definition for attr \"%s\"",
340                                         attrs[i] );
341                                 fprintf( stderr, "%s: line %d: %s\n",
342                                         fname, lineno, c_reply->msg );
343                         }
344
345                         rc = LDAP_PARAM_ERROR;
346                         goto done;
347                 }
348         }
349
350 done:
351         ldap_charray_free( attrs );
352         if ( indexes != NULL ) ldap_charray_free( indexes );
353
354         return rc;
355 }
356
357 static int
358 bdb_attr_index_unparser( void *v1, void *v2 )
359 {
360         AttrInfo *ai = v1;
361         BerVarray *bva = v2;
362         struct berval bv;
363         char *ptr;
364
365         slap_index2bvlen( ai->ai_indexmask, &bv );
366         if ( bv.bv_len ) {
367                 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
368                 ptr = ch_malloc( bv.bv_len+1 );
369                 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
370                 *bv.bv_val++ = ' ';
371                 slap_index2bv( ai->ai_indexmask, &bv );
372                 bv.bv_val = ptr;
373                 ber_bvarray_add( bva, &bv );
374         }
375         return 0;
376 }
377
378 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
379 static AttrInfo aidef = { &addef };
380
381 void
382 bdb_attr_index_unparse( struct bdb_info *bdb, BerVarray *bva )
383 {
384         int i;
385
386         if ( bdb->bi_defaultmask ) {
387                 aidef.ai_indexmask = bdb->bi_defaultmask;
388                 bdb_attr_index_unparser( &aidef, bva );
389         }
390         for ( i=0; i<bdb->bi_nattrs; i++ )
391                 bdb_attr_index_unparser( bdb->bi_attrs[i], bva );
392 }
393
394 void
395 bdb_attr_info_free( AttrInfo *ai )
396 {
397 #ifdef LDAP_COMP_MATCH
398         free( ai->ai_cr );
399 #endif
400         free( ai );
401 }
402
403 void
404 bdb_attr_index_destroy( struct bdb_info *bdb )
405 {
406         int i;
407
408         for ( i=0; i<bdb->bi_nattrs; i++ ) 
409                 bdb_attr_info_free( bdb->bi_attrs[i] );
410
411         free( bdb->bi_attrs );
412 }
413
414 void bdb_attr_index_free( struct bdb_info *bdb, AttributeDescription *ad )
415 {
416         int i;
417
418         i = bdb_attr_slot( bdb, ad, NULL );
419         if ( i >= 0 ) {
420                 bdb_attr_info_free( bdb->bi_attrs[i] );
421                 bdb->bi_nattrs--;
422                 for (; i<bdb->bi_nattrs; i++)
423                         bdb->bi_attrs[i] = bdb->bi_attrs[i+1];
424         }
425 }
426
427 void bdb_attr_flush( struct bdb_info *bdb )
428 {
429         int i;
430
431         for ( i=0; i<bdb->bi_nattrs; i++ ) {
432                 if ( bdb->bi_attrs[i]->ai_indexmask & BDB_INDEX_DELETING ) {
433                         int j;
434                         bdb_attr_info_free( bdb->bi_attrs[i] );
435                         bdb->bi_nattrs--;
436                         for (j=i; j<bdb->bi_nattrs; j++)
437                                 bdb->bi_attrs[j] = bdb->bi_attrs[j+1];
438                         i--;
439                 }
440         }
441 }