]> git.sur5r.net Git - openldap/blob - servers/slapd/entry.c
Add some initial BDB_INDEX code... needs much work.
[openldap] / servers / slapd / entry.c
1 /* entry.c - routines for dealing with entries */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/ctype.h>
13 #include <ac/errno.h>
14 #include <ac/socket.h>
15 #include <ac/string.h>
16
17 #include "slap.h"
18 #include "ldif.h"
19
20 static unsigned char    *ebuf;  /* buf returned by entry2str             */
21 static unsigned char    *ecur;  /* pointer to end of currently used ebuf */
22 static int              emaxsize;/* max size of ebuf                     */
23
24 int entry_destroy(void)
25 {
26         free( ebuf );
27         ebuf = NULL;
28         ecur = NULL;
29         emaxsize = 0;
30         return 0;
31 }
32
33
34 Entry *
35 str2entry( char *s )
36 {
37         int rc;
38         Entry           *e;
39         Attribute       **a = NULL;
40         char            *type;
41         struct berval value;
42         struct berval   *vals[2];
43         AttributeDescription *ad;
44         const char *text;
45         char    *next;
46
47         /*
48          * LDIF is used as the string format.
49          * An entry looks like this:
50          *
51          *      dn: <dn>\n
52          *      [<attr>:[:] <value>\n]
53          *      [<tab><continuedvalue>\n]*
54          *      ...
55          *
56          * If a double colon is used after a type, it means the
57          * following value is encoded as a base 64 string.  This
58          * happens if the value contains a non-printing character
59          * or newline.
60          */
61
62 #ifdef NEW_LOGGING
63         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
64                    "str2entry: \"%s\"\n", s ? s : "NULL" ));
65 #else
66         Debug( LDAP_DEBUG_TRACE, "=> str2entry\n",
67                 s ? s : "NULL", 0, 0 );
68 #endif
69
70         /* initialize reader/writer lock */
71         e = (Entry *) ch_malloc( sizeof(Entry) );
72
73         if( e == NULL ) {
74 #ifdef NEW_LOGGING
75                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
76                            "str2entry: entry allocation failed.\n" ));
77 #else
78                 Debug( LDAP_DEBUG_ANY,
79                     "<= str2entry NULL (entry allocation failed)\n",
80                     0, 0, 0 );
81 #endif
82                 return( NULL );
83         }
84
85         /* initialize entry */
86         e->e_id = NOID;
87         e->e_dn = NULL;
88         e->e_ndn = NULL;
89         e->e_attrs = NULL;
90         e->e_private = NULL;
91
92         /* dn + attributes */
93         vals[0] = &value;
94         vals[1] = NULL;
95
96         next = s;
97         while ( (s = ldif_getline( &next )) != NULL ) {
98                 if ( *s == '\n' || *s == '\0' ) {
99                         break;
100                 }
101
102                 if ( ldif_parse_line( s, &type, &value.bv_val, &value.bv_len ) != 0 ) {
103 #ifdef NEW_LOGGING
104                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
105                                    "str2entry:  NULL (parse_line)\n" ));
106 #else
107                         Debug( LDAP_DEBUG_TRACE,
108                             "<= str2entry NULL (parse_line)\n", 0, 0, 0 );
109 #endif
110                         continue;
111                 }
112
113                 if ( strcasecmp( type, "dn" ) == 0 ) {
114                         free( type );
115
116                         if ( e->e_dn != NULL ) {
117 #ifdef NEW_LOGGING
118                                 LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
119                                            "str2entry: entry %ld has multiple dns \"%s\" and \"%s\" (second ignored)\n",
120                                            e->e_id, e->e_dn, value.bv_val != NULL ? value.bv_val : "" ));
121 #else
122                                 Debug( LDAP_DEBUG_ANY,
123  "str2entry: entry %ld has multiple dns \"%s\" and \"%s\" (second ignored)\n",
124                                     e->e_id, e->e_dn,
125                                         value.bv_val != NULL ? value.bv_val : "" );
126 #endif
127                                 if( value.bv_val != NULL ) free( value.bv_val );
128                                 continue;
129                         }
130
131                         e->e_dn = value.bv_val != NULL ? value.bv_val : ch_strdup( "" );
132                         continue;
133                 }
134
135                 ad = NULL;
136                 rc = slap_str2ad( type, &ad, &text );
137
138                 if( rc != LDAP_SUCCESS ) {
139 #ifdef NEW_LOGGING
140                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
141                                    "str2entry:  str2ad(%s):      %s\n", type, text ));
142 #else
143                         Debug( slapMode & SLAP_TOOL_MODE
144                                 ? LDAP_DEBUG_ANY : LDAP_DEBUG_TRACE,
145                                 "<= str2entry: str2ad(%s): %s\n", type, text, 0 );
146 #endif
147                         if( slapMode & SLAP_TOOL_MODE ) {
148                                 entry_free( e );
149                                 free( value.bv_val );
150                                 free( type );
151                                 return NULL;
152                         }
153
154                         rc = slap_str2undef_ad( type, &ad, &text );
155
156                         if( rc != LDAP_SUCCESS ) {
157 #ifdef NEW_LOGGING
158                                 LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
159                                            "str2entry:  str2undef_ad(%s):  %s\n", type, text ));
160 #else
161                                 Debug( LDAP_DEBUG_ANY,
162                                         "<= str2entry: str2undef_ad(%s): %s\n",
163                                                 type, text, 0 );
164 #endif
165                                 entry_free( e );
166                                 free( value.bv_val );
167                                 free( type );
168                                 return NULL;
169                         }
170                 }
171
172                 if( slapMode & SLAP_TOOL_MODE ) {
173                         slap_syntax_validate_func *validate =
174                                 ad->ad_type->sat_syntax->ssyn_validate;
175
176                         if( !validate ) {
177 #ifdef NEW_LOGGING
178                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
179                                            "str2entry: no validator for syntax %s\n", 
180                                            ad->ad_type->sat_syntax->ssyn_oid ));
181 #else
182                                 Debug( LDAP_DEBUG_ANY,
183                                         "str2entry: no validator for syntax %s\n",
184                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
185 #endif
186                                 entry_free( e );
187                                 free( value.bv_val );
188                                 free( type );
189                                 return NULL;
190                         }
191
192                         /*
193                          * validate value per syntax
194                          */
195                         rc = validate( ad->ad_type->sat_syntax, &value );
196
197                         if( rc != 0 ) {
198 #ifdef NEW_LOGGING
199                                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
200                                            "str2entry:  invalid value for syntax %s\n",
201                                            ad->ad_type->sat_syntax->ssyn_oid ));
202 #else
203                                 Debug( LDAP_DEBUG_ANY,
204                                         "str2entry: invalid value for syntax %s\n",
205                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
206 #endif
207                                 entry_free( e );
208                                 free( value.bv_val );
209                                 free( type );
210                                 return NULL;
211                         }
212                 }
213
214                 rc = attr_merge( e, ad, vals );
215
216                 ad_free( ad, 1 );
217
218                 if( rc != 0 ) {
219 #ifdef NEW_LOGGING
220                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
221                                    "str2entry:  NULL (attr_merge)\n" ));
222 #else
223                         Debug( LDAP_DEBUG_ANY,
224                             "<= str2entry NULL (attr_merge)\n", 0, 0, 0 );
225 #endif
226                         entry_free( e );
227                         free( value.bv_val );
228                         free( type );
229                         return( NULL );
230                 }
231
232                 free( type );
233                 free( value.bv_val );
234         }
235
236         /* check to make sure there was a dn: line */
237         if ( e->e_dn == NULL ) {
238 #ifdef NEW_LOGGING
239                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
240                            "str2entry:  entry %ld has no dn.\n", e->e_id ));
241 #else
242                 Debug( LDAP_DEBUG_ANY, "str2entry: entry %ld has no dn\n",
243                     e->e_id, 0, 0 );
244 #endif
245                 entry_free( e );
246                 return( NULL );
247         }
248
249         /* generate normalized dn */
250         e->e_ndn = ch_strdup( e->e_dn );
251         (void) dn_normalize( e->e_ndn );
252
253 #ifdef NEW_LOGGING
254         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL2,
255                    "str2entry(%s) -> 0x%lx\n", e->e_dn, (unsigned long)e ));
256 #else
257         Debug(LDAP_DEBUG_TRACE, "<= str2entry(%s) -> 0x%lx\n",
258                 e->e_dn, (unsigned long) e, 0 );
259 #endif
260         return( e );
261 }
262
263
264 #define GRABSIZE        BUFSIZ
265
266 #define MAKE_SPACE( n ) { \
267                 while ( ecur + (n) > ebuf + emaxsize ) { \
268                         ptrdiff_t       offset; \
269                         offset = (int) (ecur - ebuf); \
270                         ebuf = (unsigned char *) ch_realloc( (char *) ebuf, \
271                             emaxsize + GRABSIZE ); \
272                         emaxsize += GRABSIZE; \
273                         ecur = ebuf + offset; \
274                 } \
275         }
276
277 char *
278 entry2str(
279     Entry       *e,
280     int         *len )
281 {
282         Attribute       *a;
283         struct berval   *bv;
284         int             i, tmplen;
285
286         /*
287          * In string format, an entry looks like this:
288          *      dn: <dn>\n
289          *      [<attr>: <value>\n]*
290          */
291
292         ecur = ebuf;
293
294         /* put the dn */
295         if ( e->e_dn != NULL ) {
296                 /* put "dn: <dn>" */
297                 tmplen = strlen( e->e_dn );
298                 MAKE_SPACE( LDIF_SIZE_NEEDED( 2, tmplen ));
299                 ldif_sput( (char **) &ecur, LDIF_PUT_VALUE, "dn", e->e_dn, tmplen );
300         }
301
302         /* put the attributes */
303         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
304                 /* put "<type>:[:] <value>" line for each value */
305                 for ( i = 0; a->a_vals[i] != NULL; i++ ) {
306                         bv = a->a_vals[i];
307                         tmplen = a->a_desc->ad_cname->bv_len;
308                         MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len ));
309                         ldif_sput( (char **) &ecur, LDIF_PUT_VALUE,
310                                 a->a_desc->ad_cname->bv_val,
311                             bv->bv_val, bv->bv_len );
312                 }
313         }
314         MAKE_SPACE( 1 );
315         *ecur = '\0';
316         *len = ecur - ebuf;
317
318         return( (char *) ebuf );
319 }
320
321 void
322 entry_free( Entry *e )
323 {
324         /* free an entry structure */
325         assert( e != NULL );
326
327         /* e_private must be freed by the caller */
328         assert( e->e_private == NULL );
329         e->e_private = NULL;
330
331         /* free DNs */
332         if ( e->e_dn != NULL ) {
333                 free( e->e_dn );
334                 e->e_dn = NULL;
335         }
336         if ( e->e_ndn != NULL ) {
337                 free( e->e_ndn );
338                 e->e_ndn = NULL;
339         }
340
341         /* free attributes */
342         attrs_free( e->e_attrs );
343         e->e_attrs = NULL;
344
345         free( e );
346 }
347
348 /*
349  * These routines are used only by Backend.
350  *
351  * the Entry has three entry points (ways to find things):
352  *
353  *      by entry        e.g., if you already have an entry from the cache
354  *                      and want to delete it. (really by entry ptr)
355  *      by dn           e.g., when looking for the base object of a search
356  *      by id           e.g., for search candidates
357  *
358  * these correspond to three different avl trees that are maintained.
359  */
360
361 int
362 entry_cmp( Entry *e1, Entry *e2 )
363 {
364         return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) );
365 }
366
367 int
368 entry_dn_cmp( Entry *e1, Entry *e2 )
369 {
370         /* compare their normalized UPPERCASED dn's */
371         return( strcmp( e1->e_ndn, e2->e_ndn ) );
372 }
373
374 int
375 entry_id_cmp( Entry *e1, Entry *e2 )
376 {
377         return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) );
378 }
379
380 #ifdef SLAPD_BDB
381
382 /* a LBER encoded entry looks like:
383  *
384  *       entry :== SEQUENCE {
385  *                      dn              DistinguishedName,
386  *                      ndn             NormalizedDistinguishedName,
387  *                      attrs   SEQUENCE OF SEQUENCE {
388  *                              type    AttributeType,
389  *                              values  SET OF AttributeValue
390  *                      }
391  *       }
392  *
393  * Encoding/Decoding of LBER should be much faster than LDIF
394  */
395
396 int entry_decode( struct berval *bv, Entry **entry )
397 {
398         int rc;
399         BerElement      *ber;
400         Entry           *e;
401         ber_tag_t       tag;
402         ber_len_t       len;
403         char *last;
404
405         assert( bv != NULL );
406         assert( entry != NULL );
407
408         ber = ber_init( bv );
409         if( ber == NULL ) {
410                 assert( 0 );    /* XXYYZ: Temporary assert */
411
412 #ifdef NEW_LOGGING
413                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
414                            "entry_decode: ber_init failed\n" ));
415 #else
416                 Debug( LDAP_DEBUG_ANY,
417                     "<= entry_decode: ber_init failed\n",
418                     0, 0, 0 );
419 #endif
420                 return LDAP_LOCAL_ERROR;
421         }
422
423         /* initialize reader/writer lock */
424         e = (Entry *) ch_malloc( sizeof(Entry) );
425
426         if( e == NULL ) {
427 #ifdef NEW_LOGGING
428                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
429                            "entry_decode: entry allocation failed.\n" ));
430 #else
431                 Debug( LDAP_DEBUG_ANY,
432                     "<= entry_decode: entry allocation failed\n",
433                     0, 0, 0 );
434 #endif
435                 return LDAP_LOCAL_ERROR;
436         }
437
438         /* initialize entry */
439         e->e_id = NOID;
440         e->e_dn = NULL;
441         e->e_ndn = NULL;
442         e->e_attrs = NULL;
443         e->e_private = NULL;
444
445         tag = ber_scanf( ber, "{aa" /*"}"*/, &e->e_dn, &e->e_ndn );
446         if( tag == LBER_ERROR ) {
447                 free( e );
448                 return LDAP_PROTOCOL_ERROR;
449         }
450
451 #ifdef NEW_LOGGING
452         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL2,
453                    "entry_decode: \"%s\"\n", e->e_dn ));
454 #else
455         Debug( LDAP_DEBUG_TRACE,
456             "entry_decode: \"%s\"\n",
457             e->e_dn, 0, 0 );
458 #endif
459         /* get the attrs */
460         for ( tag = ber_first_element( ber, &len, &last );
461                 tag != LBER_DEFAULT;
462             tag = ber_next_element( ber, &len, last ) )
463         {
464                 struct berval *type;
465                 struct berval **vals;
466                 AttributeDescription *ad;
467                 const char *text;
468
469                 tag = ber_scanf( ber, "{O{V}}", &type, &vals );
470
471                 if ( tag == LBER_ERROR ) {
472 #ifdef NEW_LOGGING
473                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
474                                    "entry_decode: decoding error (%s)\n", e->e_dn ));
475 #else
476                         Debug( LDAP_DEBUG_ANY, "entry_decode: decoding error\n", 0, 0, 0 );
477 #endif
478                         entry_free( e );
479                         return LDAP_PROTOCOL_ERROR;
480                 }
481
482                 if ( vals == NULL ) {
483 #ifdef NEW_LOGGING
484                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
485                                    "entry_decode: no values for type %s\n", type ));
486 #else
487                         Debug( LDAP_DEBUG_ANY, "entry_decode: no values for type %s\n",
488                                 type, 0, 0 );
489 #endif
490                         ber_bvfree( type );
491                         entry_free( e );
492                         return LDAP_PROTOCOL_ERROR;
493                 }
494
495                 ad = NULL;
496                 rc = slap_bv2ad( type, &ad, &text );
497
498                 if( rc != LDAP_SUCCESS ) {
499 #ifdef NEW_LOGGING
500                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
501                                    "entry_decode: str2ad(%s): %s\n", type, text ));
502 #else
503                         Debug( LDAP_DEBUG_TRACE,
504                                 "<= entry_decode: str2ad(%s): %s\n", type, text, 0 );
505 #endif
506                         rc = slap_bv2undef_ad( type, &ad, &text );
507
508                         if( rc != LDAP_SUCCESS ) {
509 #ifdef NEW_LOGGING
510                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
511                                            "entry_decode:  str2undef_ad(%s): %s\n", type, text));
512 #else
513                                 Debug( LDAP_DEBUG_ANY,
514                                         "<= entry_decode: str2undef_ad(%s): %s\n",
515                                                 type, text, 0 );
516 #endif
517                                 ber_bvfree( type );
518                                 ber_bvecfree( vals );
519                                 entry_free( e );
520                                 return rc;
521                         }
522                 }
523
524                 rc = attr_merge( e, ad, vals );
525                 ad_free( ad, 1 );
526
527                 if( rc != 0 ) {
528 #ifdef NEW_LOGGING
529                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
530                                    "entry_decode:  attr_merge failed\n"));
531 #else
532                         Debug( LDAP_DEBUG_ANY,
533                             "<= entry_decode: attr_merge failed\n", 0, 0, 0 );
534 #endif
535                         ber_bvfree( type );
536                         ber_bvecfree( vals );
537                         entry_free( e );
538                         return LDAP_LOCAL_ERROR;
539                 }
540
541                 free( type );
542                 ber_bvecfree( vals );
543         }
544
545         rc = ber_scanf( ber, /*"{"*/  "}" );
546         if( rc < 0 ) {
547                 entry_free( e );
548                 return LDAP_PROTOCOL_ERROR;
549         }
550
551 #ifdef NEW_LOGGING
552         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
553                    "entry_decode:  %s\n", e->e_dn ));
554 #else
555         Debug(LDAP_DEBUG_TRACE, "<= entry_decode(%s)\n",
556                 e->e_dn, 0, 0 );
557 #endif
558
559         *entry = e;
560         return LDAP_SUCCESS;
561 }
562
563 int entry_encode(
564         Entry *e,
565         struct berval **bv )
566 {
567         int rc = -1;
568         Attribute *a;
569         BerElement *ber;
570         
571 #ifdef NEW_LOGGING
572         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
573                    "entry_encode: id: 0x%08lx  \"%s\"\n",
574                    e->e_id, e->e_dn ));
575 #else
576         Debug( LDAP_DEBUG_TRACE, "=> entry_encode(0x%08lx): %s\n",
577                 e->e_id, e->e_dn, 0 );
578 #endif
579         ber = ber_alloc_t( LBER_USE_DER );
580         if( ber == NULL ) {
581                 goto done;
582         }
583
584         rc = ber_printf( ber, "{ss{" /*"}}"*/, e->e_dn, e->e_ndn );
585         if( rc < 0 ) {
586                 goto done;
587         }
588
589         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
590                 rc = ber_printf( ber, "{O{V}}",
591                         a->a_desc->ad_cname,
592                         a->a_vals );
593                 if( rc < 0 ) {
594                         goto done;
595                 }
596         }
597
598         rc = ber_printf( ber, /*"{{"*/ "}}" );
599         if( rc < 0 ) {
600                 goto done;
601         }
602
603         rc = ber_flatten( ber, bv );
604
605 done:
606         ber_free( ber, 1 );
607         if( rc ) {
608 #ifdef NEW_LOGGING
609                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
610                            "entry_encode: id=0x%08lx  failed (%d)\n", e->e_id, rc ));
611 #else
612                 Debug( LDAP_DEBUG_ANY, "=> entry_encode(0x%08lx): failed (%d)\n",
613                         e->e_id, rc, 0 );
614 #endif
615         }
616         return rc;
617 }
618 #endif