]> git.sur5r.net Git - openldap/blob - servers/slapd/entry.c
Missed a test in AttributeDescription commit
[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, "str2entry: "
119                                         "entry %ld has multiple dns \"%s\" and \"%s\" "
120                                         "(second ignored)\n",
121                                         (long) e->e_id, e->e_dn, value.bv_val != NULL ? value.bv_val : "" ));
122 #else
123                                 Debug( LDAP_DEBUG_ANY, "str2entry: "
124                                         "entry %ld has multiple dns \"%s\" and \"%s\" "
125                                         "(second ignored)\n",
126                                     (long) e->e_id, e->e_dn,
127                                         value.bv_val != NULL ? value.bv_val : "" );
128 #endif
129                                 if( value.bv_val != NULL ) free( value.bv_val );
130                                 continue;
131                         }
132
133                         e->e_dn = value.bv_val != NULL ? value.bv_val : ch_strdup( "" );
134                         continue;
135                 }
136
137                 ad = NULL;
138                 rc = slap_str2ad( type, &ad, &text );
139
140                 if( rc != LDAP_SUCCESS ) {
141 #ifdef NEW_LOGGING
142                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
143                                    "str2entry:  str2ad(%s):      %s\n", type, text ));
144 #else
145                         Debug( slapMode & SLAP_TOOL_MODE
146                                 ? LDAP_DEBUG_ANY : LDAP_DEBUG_TRACE,
147                                 "<= str2entry: str2ad(%s): %s\n", type, text, 0 );
148 #endif
149                         if( slapMode & SLAP_TOOL_MODE ) {
150                                 entry_free( e );
151                                 free( value.bv_val );
152                                 free( type );
153                                 return NULL;
154                         }
155
156                         rc = slap_str2undef_ad( type, &ad, &text );
157
158                         if( rc != LDAP_SUCCESS ) {
159 #ifdef NEW_LOGGING
160                                 LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
161                                            "str2entry:  str2undef_ad(%s):  %s\n", type, text ));
162 #else
163                                 Debug( LDAP_DEBUG_ANY,
164                                         "<= str2entry: str2undef_ad(%s): %s\n",
165                                                 type, text, 0 );
166 #endif
167                                 entry_free( e );
168                                 free( value.bv_val );
169                                 free( type );
170                                 return NULL;
171                         }
172                 }
173
174                 if( slapMode & SLAP_TOOL_MODE ) {
175                         slap_syntax_validate_func *validate =
176                                 ad->ad_type->sat_syntax->ssyn_validate;
177
178                         if( !validate ) {
179 #ifdef NEW_LOGGING
180                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
181                                            "str2entry: no validator for syntax %s\n", 
182                                            ad->ad_type->sat_syntax->ssyn_oid ));
183 #else
184                                 Debug( LDAP_DEBUG_ANY,
185                                         "str2entry: no validator for syntax %s\n",
186                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
187 #endif
188                                 entry_free( e );
189                                 free( value.bv_val );
190                                 free( type );
191                                 return NULL;
192                         }
193
194                         /*
195                          * validate value per syntax
196                          */
197                         rc = validate( ad->ad_type->sat_syntax, &value );
198
199                         if( rc != 0 ) {
200 #ifdef NEW_LOGGING
201                                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
202                                            "str2entry:  invalid value for syntax %s\n",
203                                            ad->ad_type->sat_syntax->ssyn_oid ));
204 #else
205                                 Debug( LDAP_DEBUG_ANY,
206                                         "str2entry: invalid value for syntax %s\n",
207                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
208 #endif
209                                 entry_free( e );
210                                 free( value.bv_val );
211                                 free( type );
212                                 return NULL;
213                         }
214                 }
215
216                 rc = attr_merge( e, ad, vals );
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",
241                                 (long) e->e_id ));
242 #else
243                 Debug( LDAP_DEBUG_ANY, "str2entry: entry %ld has no dn\n",
244                     (long) e->e_id, 0, 0 );
245 #endif
246                 entry_free( e );
247                 return( NULL );
248         }
249
250         /* generate normalized dn */
251         e->e_ndn = ch_strdup( e->e_dn );
252         (void) dn_normalize( e->e_ndn );
253
254 #ifdef NEW_LOGGING
255         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL2,
256                    "str2entry(%s) -> 0x%lx\n", e->e_dn, (unsigned long)e ));
257 #else
258         Debug(LDAP_DEBUG_TRACE, "<= str2entry(%s) -> 0x%lx\n",
259                 e->e_dn, (unsigned long) e, 0 );
260 #endif
261         return( e );
262 }
263
264
265 #define GRABSIZE        BUFSIZ
266
267 #define MAKE_SPACE( n ) { \
268                 while ( ecur + (n) > ebuf + emaxsize ) { \
269                         ptrdiff_t       offset; \
270                         offset = (int) (ecur - ebuf); \
271                         ebuf = (unsigned char *) ch_realloc( (char *) ebuf, \
272                             emaxsize + GRABSIZE ); \
273                         emaxsize += GRABSIZE; \
274                         ecur = ebuf + offset; \
275                 } \
276         }
277
278 char *
279 entry2str(
280     Entry       *e,
281     int         *len )
282 {
283         Attribute       *a;
284         struct berval   *bv;
285         int             i, tmplen;
286
287         /*
288          * In string format, an entry looks like this:
289          *      dn: <dn>\n
290          *      [<attr>: <value>\n]*
291          */
292
293         ecur = ebuf;
294
295         /* put the dn */
296         if ( e->e_dn != NULL ) {
297                 /* put "dn: <dn>" */
298                 tmplen = strlen( e->e_dn );
299                 MAKE_SPACE( LDIF_SIZE_NEEDED( 2, tmplen ));
300                 ldif_sput( (char **) &ecur, LDIF_PUT_VALUE, "dn", e->e_dn, tmplen );
301         }
302
303         /* put the attributes */
304         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
305                 /* put "<type>:[:] <value>" line for each value */
306                 for ( i = 0; a->a_vals[i] != NULL; i++ ) {
307                         bv = a->a_vals[i];
308                         tmplen = a->a_desc->ad_cname.bv_len;
309                         MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len ));
310                         ldif_sput( (char **) &ecur, LDIF_PUT_VALUE,
311                                 a->a_desc->ad_cname.bv_val,
312                             bv->bv_val, bv->bv_len );
313                 }
314         }
315         MAKE_SPACE( 1 );
316         *ecur = '\0';
317         *len = ecur - ebuf;
318
319         return( (char *) ebuf );
320 }
321
322 void
323 entry_free( Entry *e )
324 {
325         /* free an entry structure */
326         assert( e != NULL );
327
328         /* e_private must be freed by the caller */
329         assert( e->e_private == NULL );
330         e->e_private = NULL;
331
332         /* free DNs */
333         if ( e->e_dn != NULL ) {
334                 free( e->e_dn );
335                 e->e_dn = NULL;
336         }
337         if ( e->e_ndn != NULL ) {
338                 free( e->e_ndn );
339                 e->e_ndn = NULL;
340         }
341
342         /* free attributes */
343         attrs_free( e->e_attrs );
344         e->e_attrs = NULL;
345
346         free( e );
347 }
348
349 /*
350  * These routines are used only by Backend.
351  *
352  * the Entry has three entry points (ways to find things):
353  *
354  *      by entry        e.g., if you already have an entry from the cache
355  *                      and want to delete it. (really by entry ptr)
356  *      by dn           e.g., when looking for the base object of a search
357  *      by id           e.g., for search candidates
358  *
359  * these correspond to three different avl trees that are maintained.
360  */
361
362 int
363 entry_cmp( Entry *e1, Entry *e2 )
364 {
365         return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) );
366 }
367
368 int
369 entry_dn_cmp( Entry *e1, Entry *e2 )
370 {
371         /* compare their normalized UPPERCASED dn's */
372         return( strcmp( e1->e_ndn, e2->e_ndn ) );
373 }
374
375 int
376 entry_id_cmp( Entry *e1, Entry *e2 )
377 {
378         return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) );
379 }
380
381 #ifdef SLAPD_BDB
382
383 /* Flatten an Entry into a buffer. The buffer contents become a direct
384  * copy of the entry, with all pointers converted to offsets from the
385  * beginning of the buffer. We do this by first walking through all
386  * the fields of the Entry, adding up their sizes. Then a single chunk
387  * of memory is malloc'd and the entry is copied. We differentiate between
388  * fixed size fields and variable-length content when tallying up the
389  * entry size, so that we can stick all of the variable-length stuff
390  * into the back half of the buffer.
391  */
392 int entry_encode(Entry *e, struct berval **bv)
393 {
394         int siz = sizeof(Entry);
395         int len, dnlen;
396         int i, j;
397         Entry *f;
398         Attribute *a, *b;
399         struct berval **bvl, *bz;
400         char *ptr, *base, *data;
401
402         *bv = ch_malloc(sizeof(struct berval));
403         /* Compress any white space in the DN */
404         dn_validate(e->e_dn);
405 #ifdef NEW_LOGGING
406         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
407                 "entry_encode: id: 0x%08lx  \"%s\"\n",
408                 (long) e->e_id, e->e_dn ));
409 #else
410         Debug( LDAP_DEBUG_TRACE, "=> entry_encode(0x%08lx): %s\n",
411                 (long) e->e_id, e->e_dn, 0 );
412 #endif
413         dnlen = strlen(e->e_dn);
414         /* The dn and ndn are always the same length */
415         len = dnlen + dnlen + 2;        /* two trailing NUL bytes */
416         for (a=e->e_attrs; a; a=a->a_next) {
417                 /* For AttributeDesc, we only store the attr name */
418                 siz += sizeof(Attribute);
419                 len += a->a_desc->ad_cname.bv_len+1;
420                 for (i=0; a->a_vals[i]; i++) {
421                         siz += sizeof(struct berval *);
422                         siz += sizeof(struct berval);
423                         len += a->a_vals[i]->bv_len + 1;
424                 }
425                 siz += sizeof(struct berval *); /* NULL pointer at end */
426         }
427         (*bv)->bv_len = siz + len;
428         (*bv)->bv_val = ch_malloc(siz+len);
429         base = (*bv)->bv_val;
430         ptr = base + siz;
431         f = (Entry *)base;
432         data = (char *)(f+1);
433         f->e_id = e->e_id;
434         f->e_dn = (char *)(ptr-base);
435         memcpy(ptr, e->e_dn, dnlen);
436         ptr += dnlen;
437         *ptr++ = '\0';
438         f->e_ndn = (char *)(ptr-base);
439         memcpy(ptr, e->e_ndn, dnlen);
440         ptr += dnlen;
441         *ptr++ = '\0';
442         f->e_attrs = e->e_attrs ? (Attribute *)sizeof(Entry) : NULL;
443         f->e_private = NULL;
444         for (a=e->e_attrs; a; a=a->a_next) {
445                 b = (Attribute *)data;
446                 data = (char *)(b+1);
447                 b->a_desc = (AttributeDescription *)(ptr-base);
448                 memcpy(ptr, a->a_desc->ad_cname.bv_val,
449                         a->a_desc->ad_cname.bv_len);
450                 ptr += a->a_desc->ad_cname.bv_len;
451                 *ptr++ = '\0';
452                 if (a->a_vals) {
453                     bvl = (struct berval **)data;
454                     b->a_vals = (struct berval **)(data-base);
455                     for (i=0; a->a_vals[i]; i++);
456                     data = (char *)(bvl+i+1);
457                     bz = (struct berval *)data;
458                     for (j=0; j<i; j++) {
459                             bz->bv_len = a->a_vals[j]->bv_len;
460                             if (a->a_vals[j]->bv_val) {
461                                 bz->bv_val = (char *)(ptr-base);
462                                 memcpy(ptr, a->a_vals[j]->bv_val, bz->bv_len);
463                             } else {
464                                 bz->bv_val = NULL;
465                             }
466                             ptr += bz->bv_len;
467                             *ptr++ = '\0';
468                             bvl[j] = (struct berval *)(data-base);
469                             bz++;
470                             data = (char *)bz;
471                     }
472                     bvl[j] = NULL;
473                 } else {
474                     b->a_vals = NULL;
475                 }
476
477                 if (a->a_next)
478                     b->a_next = (Attribute *)(data-base);
479                 else
480                     b->a_next = NULL;
481         }
482         return 0;
483 }
484
485 /* Retrieve an Entry that was stored using entry_encode above.
486  * All we have to do is add the buffer address to all of the
487  * stored offsets. We also must lookup the stored attribute names
488  * to get AttributeDescriptions. To detect if the attributes of
489  * an Entry are later modified, we also store the address of the
490  * end of this block in e_private.
491  *
492  * Note: everything is stored in a single contiguous block, so
493  * you can not free individual attributes or names from this
494  * structure. Attempting to do so will likely corrupt memory.
495  */
496 int entry_decode(struct berval *bv, Entry **e)
497 {
498         int i;
499         long base;
500         Attribute *a;
501         Entry *x = (Entry *)bv->bv_val;
502         char *type;
503         const char *text;
504         AttributeDescription *ad;
505
506         base = (long)bv->bv_val;
507         x->e_dn += base;
508         x->e_ndn += base;
509 #ifdef NEW_LOGGING
510         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL2,
511                    "entry_decode: \"%s\"\n", x->e_dn ));
512 #else
513         Debug( LDAP_DEBUG_TRACE,
514             "entry_decode: \"%s\"\n",
515             x->e_dn, 0, 0 );
516 #endif
517         x->e_private = bv->bv_val + bv->bv_len;
518         if (x->e_attrs)
519                 x->e_attrs = (Attribute *)((long)x->e_attrs+base);
520         for (a=x->e_attrs; a; a=a->a_next) {
521                 if (a->a_next)
522                         a->a_next = (Attribute *)((long)a->a_next+base);
523                 ad = NULL;
524                 type = (char *)a->a_desc+base;
525                 i = slap_str2ad( type, &ad, &text );
526
527                 if( i != LDAP_SUCCESS ) {
528 #ifdef NEW_LOGGING
529                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
530                                    "entry_decode: str2ad(%s): %s\n", type, text ));
531 #else
532                         Debug( LDAP_DEBUG_TRACE,
533                                 "<= entry_decode: str2ad(%s): %s\n", type, text, 0 );
534 #endif
535                         i = slap_str2undef_ad( type, &ad, &text );
536
537                         if( i != LDAP_SUCCESS ) {
538 #ifdef NEW_LOGGING
539                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
540                                            "entry_decode:  str2undef_ad(%s): %s\n", type, text));
541 #else
542                                 Debug( LDAP_DEBUG_ANY,
543                                         "<= entry_decode: str2undef_ad(%s): %s\n",
544                                                 type, text, 0 );
545 #endif
546                                 return i;
547                         }
548                 }
549                 a->a_desc = ad;
550                 if (a->a_vals) {
551                         a->a_vals = (struct berval **)((long)a->a_vals+base);
552                         for (i=0; a->a_vals[i]; i++) {
553                                 a->a_vals[i] = (struct berval *)
554                                         ((long)a->a_vals[i]+base);
555                                 if (a->a_vals[i]->bv_val)
556                                     a->a_vals[i]->bv_val += base;
557                         }
558                 }
559         }
560 #ifdef NEW_LOGGING
561         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
562                    "entry_decode:  %s\n", x->e_dn ));
563 #else
564         Debug(LDAP_DEBUG_TRACE, "<= entry_decode(%s)\n",
565                 x->e_dn, 0, 0 );
566 #endif
567         *e = x;
568         return 0;
569 }
570 #endif