]> git.sur5r.net Git - openldap/blob - servers/slapd/entry.c
Do something with the error text.
[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, ndnlen;
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 #ifdef NEW_LOGGING
404         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
405                 "entry_encode: id: 0x%08lx  \"%s\"\n",
406                 (long) e->e_id, e->e_dn ));
407 #else
408         Debug( LDAP_DEBUG_TRACE, "=> entry_encode(0x%08lx): %s\n",
409                 (long) e->e_id, e->e_dn, 0 );
410 #endif
411         dnlen = strlen(e->e_dn);
412         ndnlen = strlen(e->e_ndn);
413         len = dnlen + ndnlen + 2;       /* two trailing NUL bytes */
414         for (a=e->e_attrs; a; a=a->a_next) {
415                 /* For AttributeDesc, we only store the attr name */
416                 siz += sizeof(Attribute);
417                 len += a->a_desc->ad_cname.bv_len+1;
418                 for (i=0; a->a_vals[i]; i++) {
419                         siz += sizeof(struct berval *);
420                         siz += sizeof(struct berval);
421                         len += a->a_vals[i]->bv_len + 1;
422                 }
423                 siz += sizeof(struct berval *); /* NULL pointer at end */
424         }
425         (*bv)->bv_len = siz + len;
426         (*bv)->bv_val = ch_malloc(siz+len);
427         base = (*bv)->bv_val;
428         ptr = base + siz;
429         f = (Entry *)base;
430         data = (char *)(f+1);
431         f->e_id = e->e_id;
432         f->e_dn = (char *)(ptr-base);
433         memcpy(ptr, e->e_dn, dnlen);
434         ptr += dnlen;
435         *ptr++ = '\0';
436         f->e_ndn = (char *)(ptr-base);
437         memcpy(ptr, e->e_ndn, ndnlen);
438         ptr += ndnlen;
439         *ptr++ = '\0';
440         f->e_attrs = e->e_attrs ? (Attribute *)sizeof(Entry) : NULL;
441         f->e_private = NULL;
442         for (a=e->e_attrs; a; a=a->a_next) {
443                 b = (Attribute *)data;
444                 data = (char *)(b+1);
445                 b->a_desc = (AttributeDescription *)(ptr-base);
446                 memcpy(ptr, a->a_desc->ad_cname.bv_val,
447                         a->a_desc->ad_cname.bv_len);
448                 ptr += a->a_desc->ad_cname.bv_len;
449                 *ptr++ = '\0';
450                 if (a->a_vals) {
451                     bvl = (struct berval **)data;
452                     b->a_vals = (struct berval **)(data-base);
453                     for (i=0; a->a_vals[i]; i++);
454                     data = (char *)(bvl+i+1);
455                     bz = (struct berval *)data;
456                     for (j=0; j<i; j++) {
457                             bz->bv_len = a->a_vals[j]->bv_len;
458                             if (a->a_vals[j]->bv_val) {
459                                 bz->bv_val = (char *)(ptr-base);
460                                 memcpy(ptr, a->a_vals[j]->bv_val, bz->bv_len);
461                             } else {
462                                 bz->bv_val = NULL;
463                             }
464                             ptr += bz->bv_len;
465                             *ptr++ = '\0';
466                             bvl[j] = (struct berval *)(data-base);
467                             bz++;
468                             data = (char *)bz;
469                     }
470                     bvl[j] = NULL;
471                 } else {
472                     b->a_vals = NULL;
473                 }
474
475                 if (a->a_next)
476                     b->a_next = (Attribute *)(data-base);
477                 else
478                     b->a_next = NULL;
479         }
480         return 0;
481 }
482
483 /* Retrieve an Entry that was stored using entry_encode above.
484  * All we have to do is add the buffer address to all of the
485  * stored offsets. We also must lookup the stored attribute names
486  * to get AttributeDescriptions. To detect if the attributes of
487  * an Entry are later modified, we also store the address of the
488  * end of this block in e_private.
489  *
490  * Note: everything is stored in a single contiguous block, so
491  * you can not free individual attributes or names from this
492  * structure. Attempting to do so will likely corrupt memory.
493  */
494 int entry_decode(struct berval *bv, Entry **e)
495 {
496         int i;
497         long base;
498         Attribute *a;
499         Entry *x = (Entry *)bv->bv_val;
500         char *type;
501         const char *text;
502         AttributeDescription *ad;
503
504         base = (long)bv->bv_val;
505         x->e_dn += base;
506         x->e_ndn += base;
507 #ifdef NEW_LOGGING
508         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL2,
509                    "entry_decode: \"%s\"\n", x->e_dn ));
510 #else
511         Debug( LDAP_DEBUG_TRACE,
512             "entry_decode: \"%s\"\n",
513             x->e_dn, 0, 0 );
514 #endif
515         x->e_private = bv->bv_val + bv->bv_len;
516         if (x->e_attrs)
517                 x->e_attrs = (Attribute *)((long)x->e_attrs+base);
518         for (a=x->e_attrs; a; a=a->a_next) {
519                 if (a->a_next)
520                         a->a_next = (Attribute *)((long)a->a_next+base);
521                 ad = NULL;
522                 type = (char *)a->a_desc+base;
523                 i = slap_str2ad( type, &ad, &text );
524
525                 if( i != LDAP_SUCCESS ) {
526 #ifdef NEW_LOGGING
527                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
528                                    "entry_decode: str2ad(%s): %s\n", type, text ));
529 #else
530                         Debug( LDAP_DEBUG_TRACE,
531                                 "<= entry_decode: str2ad(%s): %s\n", type, text, 0 );
532 #endif
533                         i = slap_str2undef_ad( type, &ad, &text );
534
535                         if( i != LDAP_SUCCESS ) {
536 #ifdef NEW_LOGGING
537                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
538                                            "entry_decode:  str2undef_ad(%s): %s\n", type, text));
539 #else
540                                 Debug( LDAP_DEBUG_ANY,
541                                         "<= entry_decode: str2undef_ad(%s): %s\n",
542                                                 type, text, 0 );
543 #endif
544                                 return i;
545                         }
546                 }
547                 a->a_desc = ad;
548                 if (a->a_vals) {
549                         a->a_vals = (struct berval **)((long)a->a_vals+base);
550                         for (i=0; a->a_vals[i]; i++) {
551                                 a->a_vals[i] = (struct berval *)
552                                         ((long)a->a_vals[i]+base);
553                                 if (a->a_vals[i]->bv_val)
554                                     a->a_vals[i]->bv_val += base;
555                         }
556                 }
557         }
558 #ifdef NEW_LOGGING
559         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
560                    "entry_decode:  %s\n", x->e_dn ));
561 #else
562         Debug(LDAP_DEBUG_TRACE, "<= entry_decode(%s)\n",
563                 x->e_dn, 0, 0 );
564 #endif
565         *e = x;
566         return 0;
567 }
568 #endif