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