]> git.sur5r.net Git - openldap/blob - servers/slapd/entry.c
Add a sample ACL
[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 #define SLAPD_SLEEPY 1
381 #ifdef SLAPD_SLEEPY
382
383 /* a DER encoded entry looks like:
384  *
385  * entry :== SEQUENCE {
386  *              dn              DistinguishedName,
387  *              ndn             NormalizedDistinguishedName,
388  *              attrs   SEQUENCE OF SEQUENCE {
389  *                      type    AttributeType,
390  *                      values  SET OF AttributeValue
391  *              }
392  * }
393  *
394  * Encoding/Decoding of DER should be much faster than LDIF
395  */
396
397 int entry_decode( struct berval *bv, Entry **entry )
398 {
399         int rc;
400         BerElement      *ber;
401         Entry           *e;
402         ber_tag_t       tag;
403         ber_len_t       len;
404         char *last;
405
406         ber = ber_init( bv );
407         if( ber == NULL ) {
408 #ifdef NEW_LOGGING
409                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
410                            "entry_decode: ber_init failed\n" ));
411 #else
412                 Debug( LDAP_DEBUG_ANY,
413                     "<= entry_decode: ber_init failed\n",
414                     0, 0, 0 );
415 #endif
416                 return LDAP_LOCAL_ERROR;
417         }
418
419         /* initialize reader/writer lock */
420         e = (Entry *) ch_malloc( sizeof(Entry) );
421
422         if( e == NULL ) {
423 #ifdef NEW_LOGGING
424                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
425                            "entry_decode: entry allocation failed.\n" ));
426 #else
427                 Debug( LDAP_DEBUG_ANY,
428                     "<= entry_decode: entry allocation failed\n",
429                     0, 0, 0 );
430 #endif
431                 return LDAP_LOCAL_ERROR;
432         }
433
434         /* initialize entry */
435         e->e_id = NOID;
436         e->e_dn = NULL;
437         e->e_ndn = NULL;
438         e->e_attrs = NULL;
439         e->e_private = NULL;
440
441         tag = ber_scanf( ber, "{aa" /*"}"*/, &e->e_dn, &e->e_ndn );
442         if( tag == LBER_ERROR ) {
443                 free( e );
444                 return LDAP_PROTOCOL_ERROR;
445         }
446
447 #ifdef NEW_LOGGING
448         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL2,
449                    "entry_decode: \"%s\"\n", e->e_dn ));
450 #else
451         Debug( LDAP_DEBUG_TRACE,
452             "entry_decode: \"%s\"\n",
453             e->e_dn, 0, 0 );
454 #endif
455         /* get the attrs */
456         for ( tag = ber_first_element( ber, &len, &last );
457                 tag != LBER_DEFAULT;
458             tag = ber_next_element( ber, &len, last ) )
459         {
460                 struct berval *type;
461                 struct berval **vals;
462                 AttributeDescription *ad;
463                 const char *text;
464
465                 tag = ber_scanf( ber, "{O{V}}", &type, &vals );
466
467                 if ( tag == LBER_ERROR ) {
468 #ifdef NEW_LOGGING
469                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
470                                    "entry_decode: decoding error (%s)\n", e->e_dn ));
471 #else
472                         Debug( LDAP_DEBUG_ANY, "entry_decode: decoding error\n", 0, 0, 0 );
473 #endif
474                         entry_free( e );
475                         return LDAP_PROTOCOL_ERROR;
476                 }
477
478                 if ( vals == NULL ) {
479 #ifdef NEW_LOGGING
480                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
481                                    "entry_decode: no values for type %s\n", type ));
482 #else
483                         Debug( LDAP_DEBUG_ANY, "entry_decode: no values for type %s\n",
484                                 type, 0, 0 );
485 #endif
486                         ber_bvfree( type );
487                         entry_free( e );
488                         return LDAP_PROTOCOL_ERROR;
489                 }
490
491                 ad = NULL;
492                 rc = slap_bv2ad( type, &ad, &text );
493
494                 if( rc != LDAP_SUCCESS ) {
495 #ifdef NEW_LOGGING
496                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
497                                    "entry_decode: str2ad(%s): %s\n", type, text ));
498 #else
499                         Debug( LDAP_DEBUG_TRACE,
500                                 "<= entry_decode: str2ad(%s): %s\n", type, text, 0 );
501 #endif
502                         rc = slap_bv2undef_ad( type, &ad, &text );
503
504                         if( rc != LDAP_SUCCESS ) {
505 #ifdef NEW_LOGGING
506                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
507                                            "entry_decode:  str2undef_ad(%s): %s\n", type, text));
508 #else
509                                 Debug( LDAP_DEBUG_ANY,
510                                         "<= entry_decode: str2undef_ad(%s): %s\n",
511                                                 type, text, 0 );
512 #endif
513                                 ber_bvfree( type );
514                                 ber_bvecfree( vals );
515                                 entry_free( e );
516                                 return rc;
517                         }
518                 }
519
520                 rc = attr_merge( e, ad, vals );
521                 ad_free( ad, 1 );
522
523                 if( rc != 0 ) {
524 #ifdef NEW_LOGGING
525                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
526                                    "entry_decode:  attr_merge failed\n"));
527 #else
528                         Debug( LDAP_DEBUG_ANY,
529                             "<= entry_decode: attr_merge failed\n", 0, 0, 0 );
530 #endif
531                         ber_bvfree( type );
532                         ber_bvecfree( vals );
533                         entry_free( e );
534                         return LDAP_LOCAL_ERROR;
535                 }
536
537                 free( type );
538                 ber_bvecfree( vals );
539         }
540
541         rc = ber_scanf( ber, /*"{"*/  "}" );
542         if( rc < 0 ) {
543                 entry_free( e );
544                 return LDAP_PROTOCOL_ERROR;
545         }
546
547 #ifdef NEW_LOGGING
548         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
549                    "entry_decode:  %s\n", e->e_dn ));
550 #else
551         Debug(LDAP_DEBUG_TRACE, "<= entry_decode(%s)\n",
552                 e->e_dn, 0, 0 );
553 #endif
554
555         *entry = e;
556         return LDAP_SUCCESS;
557 }
558
559 int entry_encode(
560         Entry *e,
561         struct berval **bv )
562 {
563         int rc = -1;
564         Attribute *a;
565         BerElement *ber;
566         
567 #ifdef NEW_LOGGING
568         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
569                    "entry_encode: id: 0x%08lx  \"%s\"\n",
570                    e->e_id, e->e_dn ));
571 #else
572         Debug( LDAP_DEBUG_TRACE, "=> entry_encode(0x%08lx): %s\n",
573                 e->e_id, e->e_dn, 0 );
574 #endif
575         ber = ber_alloc_t( LBER_USE_DER );
576         if( ber == NULL ) {
577                 goto done;
578         }
579
580         rc = ber_printf( ber, "{ss{" /*"}}"*/, e->e_dn, e->e_ndn );
581         if( rc < 0 ) {
582                 goto done;
583         }
584
585         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
586                 rc = ber_printf( ber, "{O{V}}",
587                         a->a_desc->ad_cname,
588                         a->a_vals );
589                 if( rc < 0 ) {
590                         goto done;
591                 }
592         }
593
594         rc = ber_printf( ber, /*"{{"*/ "}}" );
595         if( rc < 0 ) {
596                 goto done;
597         }
598
599         rc = ber_flatten( ber, bv );
600
601 done:
602         ber_free( ber, 1 );
603         if( rc ) {
604 #ifdef NEW_LOGGING
605                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
606                            "entry_encode: id=0x%08lx  failed (%d)\n", e->e_id, rc ));
607 #else
608                 Debug( LDAP_DEBUG_ANY, "=> entry_encode(0x%08lx): failed (%d)\n",
609                         e->e_id, rc, 0 );
610 #endif
611         }
612         return rc;
613 }
614 #endif