]> git.sur5r.net Git - openldap/blob - servers/slapd/entry.c
SLAP_NVALUES mostly populated now
[openldap] / servers / slapd / entry.c
1 /* entry.c - routines for dealing with entries */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 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 /*
25  * Empty root entry
26  */
27 const Entry slap_entry_root = {
28         NOID, { 0, "" }, { 0, "" }, NULL, 0, { 0, "" }, NULL
29 };
30
31 int entry_destroy(void)
32 {
33         if ( ebuf ) free( ebuf );
34         ebuf = NULL;
35         ecur = NULL;
36         emaxsize = 0;
37         return 0;
38 }
39
40
41 Entry *
42 str2entry( char *s )
43 {
44         int rc;
45         Entry           *e;
46         char            *type;
47         struct berval   vals[2];
48 #ifdef SLAP_NVALUES
49         struct berval   nvals[2], *nvalsp;
50 #endif
51         AttributeDescription *ad;
52         const char *text;
53         char    *next;
54
55         /*
56          * LDIF is used as the string format.
57          * An entry looks like this:
58          *
59          *      dn: <dn>\n
60          *      [<attr>:[:] <value>\n]
61          *      [<tab><continuedvalue>\n]*
62          *      ...
63          *
64          * If a double colon is used after a type, it means the
65          * following value is encoded as a base 64 string.  This
66          * happens if the value contains a non-printing character
67          * or newline.
68          */
69
70 #ifdef NEW_LOGGING
71         LDAP_LOG( OPERATION, DETAIL1, "str2entry: \"%s\"\n", s ? s : "NULL", 0, 0 );
72 #else
73         Debug( LDAP_DEBUG_TRACE, "=> str2entry\n",
74                 s ? s : "NULL", 0, 0 );
75 #endif
76
77         /* initialize reader/writer lock */
78         e = (Entry *) ch_calloc( 1, sizeof(Entry) );
79
80         if( e == NULL ) {
81 #ifdef NEW_LOGGING
82                 LDAP_LOG( OPERATION, ERR, "str2entry: entry allocation failed.\n", 0, 0, 0 );
83 #else
84                 Debug( LDAP_DEBUG_ANY,
85                     "<= str2entry NULL (entry allocation failed)\n",
86                     0, 0, 0 );
87 #endif
88                 return( NULL );
89         }
90
91         /* initialize entry */
92         e->e_id = NOID;
93
94         /* dn + attributes */
95         vals[1].bv_len = 0;
96         vals[1].bv_val = NULL;
97
98         next = s;
99         while ( (s = ldif_getline( &next )) != NULL ) {
100                 if ( *s == '\n' || *s == '\0' ) {
101                         break;
102                 }
103
104                 if ( ldif_parse_line( s, &type, &vals[0].bv_val, &vals[0].bv_len ) != 0 ) {
105 #ifdef NEW_LOGGING
106                         LDAP_LOG( OPERATION, DETAIL1, "str2entry:  NULL (parse_line)\n",0, 0, 0 );
107 #else
108                         Debug( LDAP_DEBUG_TRACE,
109                             "<= str2entry NULL (parse_line)\n", 0, 0, 0 );
110 #endif
111                         continue;
112                 }
113
114                 if ( strcasecmp( type, "dn" ) == 0 ) {
115                         free( type );
116
117                         if ( e->e_dn != NULL ) {
118 #ifdef NEW_LOGGING
119                                 LDAP_LOG( OPERATION, DETAIL1, "str2entry: "
120                                         "entry %ld has multiple DNs \"%s\" and \"%s\"\n",
121                                         (long) e->e_id, e->e_dn, vals[0].bv_val );
122 #else
123                                 Debug( LDAP_DEBUG_ANY, "str2entry: "
124                                         "entry %ld has multiple DNs \"%s\" and \"%s\"\n",
125                                     (long) e->e_id, e->e_dn, vals[0].bv_val );
126 #endif
127                                 free( vals[0].bv_val );
128                                 entry_free( e );
129                                 return NULL;
130                         }
131
132                         rc = dnPrettyNormal( NULL, &vals[0], &e->e_name, &e->e_nname );
133                         if( rc != LDAP_SUCCESS ) {
134 #ifdef NEW_LOGGING
135                                 LDAP_LOG( OPERATION, DETAIL1, 
136                                         "str2entry: entry %ld has invalid DN \"%s\"\n",
137                                         (long) e->e_id, vals[0].bv_val, 0 );
138 #else
139                                 Debug( LDAP_DEBUG_ANY, "str2entry: "
140                                         "entry %ld has invalid DN \"%s\"\n",
141                                         (long) e->e_id, vals[0].bv_val, 0 );
142 #endif
143                                 entry_free( e );
144                                 free( vals[0].bv_val );
145                                 return NULL;
146                         }
147                         free( vals[0].bv_val );
148                         continue;
149                 }
150
151                 ad = NULL;
152                 rc = slap_str2ad( type, &ad, &text );
153
154                 if( rc != LDAP_SUCCESS ) {
155 #ifdef NEW_LOGGING
156                         LDAP_LOG( OPERATION, DETAIL1, 
157                                 "str2entry:  str2ad(%s): %s\n", type, text, 0 );
158 #else
159                         Debug( slapMode & SLAP_TOOL_MODE
160                                 ? LDAP_DEBUG_ANY : LDAP_DEBUG_TRACE,
161                                 "<= str2entry: str2ad(%s): %s\n", type, text, 0 );
162 #endif
163                         if( slapMode & SLAP_TOOL_MODE ) {
164                                 entry_free( e );
165                                 free( vals[0].bv_val );
166                                 free( type );
167                                 return NULL;
168                         }
169
170                         rc = slap_str2undef_ad( type, &ad, &text );
171                         if( rc != LDAP_SUCCESS ) {
172 #ifdef NEW_LOGGING
173                                 LDAP_LOG( OPERATION, DETAIL1, 
174                                         "str2entry: str2undef_ad(%s): %s\n", type, text, 0 );
175 #else
176                                 Debug( LDAP_DEBUG_ANY,
177                                         "<= str2entry: str2undef_ad(%s): %s\n",
178                                                 type, text, 0 );
179 #endif
180                                 entry_free( e );
181                                 free( vals[0].bv_val );
182                                 free( type );
183                                 return NULL;
184                         }
185                 }
186
187                 if( slapMode & SLAP_TOOL_MODE ) {
188                         struct berval pval;
189                         slap_syntax_validate_func *validate =
190                                 ad->ad_type->sat_syntax->ssyn_validate;
191                         slap_syntax_transform_func *pretty =
192                                 ad->ad_type->sat_syntax->ssyn_pretty;
193
194                         if( pretty ) {
195                                 rc = pretty( ad->ad_type->sat_syntax,
196                                         &vals[0], &pval );
197
198                         } else if( validate ) {
199                                 /*
200                                  * validate value per syntax
201                                  */
202                                 rc = validate( ad->ad_type->sat_syntax, &vals[0] );
203
204                         } else {
205 #ifdef NEW_LOGGING
206                                 LDAP_LOG( OPERATION, INFO, 
207                                         "str2entry: no validator for syntax %s\n", 
208                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
209 #else
210                                 Debug( LDAP_DEBUG_ANY,
211                                         "str2entry: no validator for syntax %s\n",
212                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
213 #endif
214                                 entry_free( e );
215                                 free( vals[0].bv_val );
216                                 free( type );
217                                 return NULL;
218                         }
219
220                         if( rc != 0 ) {
221 #ifdef NEW_LOGGING
222                                 LDAP_LOG( OPERATION, ERR, 
223                                         "str2entry:  invalid value for syntax %s\n",
224                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
225 #else
226                                 Debug( LDAP_DEBUG_ANY,
227                                         "str2entry: invalid value for syntax %s\n",
228                                         ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
229 #endif
230                                 entry_free( e );
231                                 free( vals[0].bv_val );
232                                 free( type );
233                                 return NULL;
234                         }
235
236                         if( pretty ) {
237                                 free( vals[0].bv_val );
238                                 vals[0] = pval;
239                         }
240                 }
241
242 #ifdef SLAP_NVALUES
243                 nvalsp = NULL;
244                 nvals[0].bv_val = NULL;
245
246                 if( ad->ad_type->sat_equality &&
247                         ad->ad_type->sat_equality->smr_match &&
248                         ad->ad_type->sat_syntax->ssyn_normalize )
249                 {
250                         rc = ad->ad_type->sat_syntax->ssyn_normalize(
251                                 ad->ad_type->sat_syntax,
252                                 &vals[0], &nvals[0] );
253
254                         if( rc ) {
255 #ifdef NEW_LOGGING
256                                 LDAP_LOG( OPERATION, DETAIL1,
257                                         "str2entry:  NULL (ssyn_normalize %d)\n" , rc, 0, 0 );
258 #else
259                                 Debug( LDAP_DEBUG_ANY,
260                                         "<= str2entry NULL (ssyn_normalize %d)\n", rc, 0, 0 );
261 #endif
262
263                                 entry_free( e );
264                                 free( vals[0].bv_val );
265                                 free( type );
266                                 return NULL;
267                         }
268
269                         nvals[1].bv_len = 0;
270                         nvals[1].bv_val = NULL;
271
272                         nvalsp = &nvals[0];
273                 }
274 #endif
275
276 #ifdef SLAP_NVALUES
277                 rc = attr_merge( e, ad, vals, nvalsp );
278 #else
279                 rc = attr_merge( e, ad, vals );
280 #endif
281                 if( rc != 0 ) {
282 #ifdef NEW_LOGGING
283                         LDAP_LOG( OPERATION, DETAIL1,
284                                 "str2entry:  NULL (attr_merge)\n" , 0, 0, 0 );
285 #else
286                         Debug( LDAP_DEBUG_ANY,
287                             "<= str2entry NULL (attr_merge)\n", 0, 0, 0 );
288 #endif
289                         entry_free( e );
290                         free( vals[0].bv_val );
291                         free( type );
292                         return( NULL );
293                 }
294
295                 free( type );
296                 free( vals[0].bv_val );
297 #ifdef SLAP_NVALUES
298                 free( nvals[0].bv_val );
299 #endif
300         }
301
302         /* check to make sure there was a dn: line */
303         if ( e->e_dn == NULL ) {
304 #ifdef NEW_LOGGING
305                 LDAP_LOG( OPERATION, INFO, 
306                         "str2entry:  entry %ld has no dn.\n", (long) e->e_id, 0, 0 );
307 #else
308                 Debug( LDAP_DEBUG_ANY, "str2entry: entry %ld has no dn\n",
309                     (long) e->e_id, 0, 0 );
310 #endif
311                 entry_free( e );
312                 return NULL;
313         }
314
315 #ifdef NEW_LOGGING
316         LDAP_LOG( OPERATION, DETAIL2,
317                 "str2entry(%s) -> 0x%lx\n", e->e_dn, (unsigned long)e, 0 );
318 #else
319         Debug(LDAP_DEBUG_TRACE, "<= str2entry(%s) -> 0x%lx\n",
320                 e->e_dn, (unsigned long) e, 0 );
321 #endif
322         return( e );
323 }
324
325
326 #define GRABSIZE        BUFSIZ
327
328 #define MAKE_SPACE( n ) { \
329                 while ( ecur + (n) > ebuf + emaxsize ) { \
330                         ptrdiff_t       offset; \
331                         offset = (int) (ecur - ebuf); \
332                         ebuf = (unsigned char *) ch_realloc( (char *) ebuf, \
333                             emaxsize + GRABSIZE ); \
334                         emaxsize += GRABSIZE; \
335                         ecur = ebuf + offset; \
336                 } \
337         }
338
339 char *
340 entry2str(
341     Entry       *e,
342     int         *len )
343 {
344         Attribute       *a;
345         struct berval   *bv;
346         int             i;
347         ber_len_t tmplen;
348
349         assert( e != NULL );
350
351         /*
352          * In string format, an entry looks like this:
353          *      dn: <dn>\n
354          *      [<attr>: <value>\n]*
355          */
356
357         ecur = ebuf;
358
359         /* put the dn */
360         if ( e->e_dn != NULL ) {
361                 /* put "dn: <dn>" */
362                 tmplen = e->e_name.bv_len;
363                 MAKE_SPACE( LDIF_SIZE_NEEDED( 2, tmplen ));
364                 ldif_sput( (char **) &ecur, LDIF_PUT_VALUE, "dn", e->e_dn, tmplen );
365         }
366
367         /* put the attributes */
368         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
369                 /* put "<type>:[:] <value>" line for each value */
370                 for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
371                         bv = &a->a_vals[i];
372                         tmplen = a->a_desc->ad_cname.bv_len;
373                         MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len ));
374                         ldif_sput( (char **) &ecur, LDIF_PUT_VALUE,
375                                 a->a_desc->ad_cname.bv_val,
376                             bv->bv_val, bv->bv_len );
377                 }
378         }
379         MAKE_SPACE( 1 );
380         *ecur = '\0';
381         *len = ecur - ebuf;
382
383         return( (char *) ebuf );
384 }
385
386 void
387 entry_free( Entry *e )
388 {
389         /* free an entry structure */
390         assert( e != NULL );
391
392         /* e_private must be freed by the caller */
393         assert( e->e_private == NULL );
394         e->e_private = NULL;
395
396         /* free DNs */
397         if ( e->e_dn != NULL ) {
398                 free( e->e_dn );
399                 e->e_dn = NULL;
400         }
401         if ( e->e_ndn != NULL ) {
402                 free( e->e_ndn );
403                 e->e_ndn = NULL;
404         }
405
406         if ( e->e_bv.bv_val != NULL ) {
407                 free( e->e_bv.bv_val );
408                 e->e_bv.bv_val = NULL;
409         }
410
411         /* free attributes */
412         attrs_free( e->e_attrs );
413         e->e_attrs = NULL;
414
415         free( e );
416 }
417
418 /*
419  * These routines are used only by Backend.
420  *
421  * the Entry has three entry points (ways to find things):
422  *
423  *      by entry        e.g., if you already have an entry from the cache
424  *                      and want to delete it. (really by entry ptr)
425  *      by dn           e.g., when looking for the base object of a search
426  *      by id           e.g., for search candidates
427  *
428  * these correspond to three different avl trees that are maintained.
429  */
430
431 int
432 entry_cmp( Entry *e1, Entry *e2 )
433 {
434         return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) );
435 }
436
437 int
438 entry_dn_cmp( const void *v_e1, const void *v_e2 )
439 {
440         /* compare their normalized UPPERCASED dn's */
441         const Entry *e1 = v_e1, *e2 = v_e2;
442         int rc = e1->e_nname.bv_len - e2->e_nname.bv_len;
443         if (rc) return rc;
444         return( strcmp( e1->e_ndn, e2->e_ndn ) );
445 }
446
447 int
448 entry_id_cmp( const void *v_e1, const void *v_e2 )
449 {
450         const Entry *e1 = v_e1, *e2 = v_e2;
451         return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) );
452 }
453
454 #ifdef SLAPD_BDB
455
456 /* This is like a ber_len */
457 static ber_len_t
458 entry_lenlen(ber_len_t len)
459 {
460         if (len <= 0x7f)
461                 return 1;
462         if (len <= 0xff)
463                 return 2;
464         if (len <= 0xffff)
465                 return 3;
466         if (len <= 0xffffff)
467                 return 4;
468         return 5;
469 }
470
471 static void
472 entry_putlen(unsigned char **buf, ber_len_t len)
473 {
474         ber_len_t lenlen = entry_lenlen(len);
475
476         if (lenlen == 1) {
477                 **buf = (unsigned char) len;
478         } else {
479                 int i;
480                 **buf = 0x80 | ((unsigned char) lenlen - 1);
481                 for (i=lenlen-1; i>0; i--) {
482                         (*buf)[i] = (unsigned char) len;
483                         len >>= 8;
484                 }
485         }
486         *buf += lenlen;
487 }
488
489 static ber_len_t
490 entry_getlen(unsigned char **buf)
491 {
492         ber_len_t len;
493         int i;
494
495         len = *(*buf)++;
496         if (len <= 0x7f)
497                 return len;
498         i = len & 0x7f;
499         len = 0;
500         for (;i > 0; i--) {
501                 len <<= 8;
502                 len |= *(*buf)++;
503         }
504         return len;
505 }
506
507 /* Flatten an Entry into a buffer. The buffer is filled with just the
508  * strings/bervals of all the entry components. Each field is preceded
509  * by its length, encoded the way ber_put_len works. Every field is NUL
510  * terminated.  The entire buffer size is precomputed so that a single
511  * malloc can be performed. The entry size is also recorded,
512  * to aid in entry_decode.
513  */
514 int entry_encode(Entry *e, struct berval *bv)
515 {
516         ber_len_t siz = sizeof(Entry);
517         ber_len_t len, dnlen, ndnlen;
518         int i;
519         Attribute *a;
520         unsigned char *ptr;
521
522 #ifdef NEW_LOGGING
523         LDAP_LOG( OPERATION, DETAIL1, "entry_encode: id: 0x%08lx  \"%s\"\n",
524                 (long) e->e_id, e->e_dn, 0 );
525 #else
526         Debug( LDAP_DEBUG_TRACE, "=> entry_encode(0x%08lx): %s\n",
527                 (long) e->e_id, e->e_dn, 0 );
528 #endif
529         dnlen = e->e_name.bv_len;
530         ndnlen = e->e_nname.bv_len;
531         len = dnlen + ndnlen + 2;       /* two trailing NUL bytes */
532         len += entry_lenlen(dnlen);
533         len += entry_lenlen(ndnlen);
534         for (a=e->e_attrs; a; a=a->a_next) {
535                 /* For AttributeDesc, we only store the attr name */
536                 siz += sizeof(Attribute);
537                 len += a->a_desc->ad_cname.bv_len+1;
538                 len += entry_lenlen(a->a_desc->ad_cname.bv_len);
539                 for (i=0; a->a_vals[i].bv_val; i++) {
540                         siz += sizeof(struct berval);
541                         len += a->a_vals[i].bv_len + 1;
542                         len += entry_lenlen(a->a_vals[i].bv_len);
543                 }
544                 len += entry_lenlen(i);
545                 siz += sizeof(struct berval);   /* empty berval at end */
546         }
547         len += 1;       /* NUL byte at end */
548         len += entry_lenlen(siz);
549         bv->bv_len = len;
550         bv->bv_val = ch_malloc(len);
551         ptr = (unsigned char *)bv->bv_val;
552         entry_putlen(&ptr, siz);
553         entry_putlen(&ptr, dnlen);
554         AC_MEMCPY(ptr, e->e_dn, dnlen);
555         ptr += dnlen;
556         *ptr++ = '\0';
557         entry_putlen(&ptr, ndnlen);
558         AC_MEMCPY(ptr, e->e_ndn, ndnlen);
559         ptr += ndnlen;
560         *ptr++ = '\0';
561
562         for (a=e->e_attrs; a; a=a->a_next) {
563                 entry_putlen(&ptr, a->a_desc->ad_cname.bv_len);
564                 AC_MEMCPY(ptr, a->a_desc->ad_cname.bv_val,
565                         a->a_desc->ad_cname.bv_len);
566                 ptr += a->a_desc->ad_cname.bv_len;
567                 *ptr++ = '\0';
568                 if (a->a_vals) {
569                     for (i=0; a->a_vals[i].bv_val; i++);
570                     entry_putlen(&ptr, i);
571                     for (i=0; a->a_vals[i].bv_val; i++) {
572                         entry_putlen(&ptr, a->a_vals[i].bv_len);
573                         memcpy(ptr, a->a_vals[i].bv_val,
574                                 a->a_vals[i].bv_len);
575                         ptr += a->a_vals[i].bv_len;
576                         *ptr++ = '\0';
577                     }
578                 }
579         }
580         *ptr = '\0';
581         return 0;
582 }
583
584 /* Retrieve an Entry that was stored using entry_encode above.
585  * We malloc a single block with the size stored above for the Entry
586  * and all if its Attributes. We also must lookup the stored
587  * attribute names to get AttributeDescriptions. To detect if the
588  * attributes of an Entry are later modified, we note that e->e_attr
589  * is always a constant offset from (e).
590  *
591  * Note: everything is stored in a single contiguous block, so
592  * you can not free individual attributes or names from this
593  * structure. Attempting to do so will likely corrupt memory.
594  */
595 int entry_decode(struct berval *bv, Entry **e)
596 {
597         int i, j, count;
598         int rc;
599         Attribute *a;
600         Entry *x;
601         const char *text;
602         AttributeDescription *ad;
603         unsigned char *ptr = (unsigned char *)bv->bv_val;
604         BerVarray bptr;
605
606         i = entry_getlen(&ptr);
607         x = ch_calloc(1, i);
608         i = entry_getlen(&ptr);
609         x->e_name.bv_val = ptr;
610         x->e_name.bv_len = i;
611         ptr += i+1;
612         i = entry_getlen(&ptr);
613         x->e_nname.bv_val = ptr;
614         x->e_nname.bv_len = i;
615         ptr += i+1;
616 #ifdef NEW_LOGGING
617         LDAP_LOG( OPERATION, DETAIL2, "entry_decode: \"%s\"\n", x->e_dn, 0, 0 );
618 #else
619         Debug( LDAP_DEBUG_TRACE,
620             "entry_decode: \"%s\"\n",
621             x->e_dn, 0, 0 );
622 #endif
623         x->e_bv = *bv;
624
625         /* A valid entry must have at least one attr, so this
626          * pointer can never be NULL
627          */
628         x->e_attrs = (Attribute *)(x+1);
629         bptr = (BerVarray)x->e_attrs;
630         a = NULL;
631
632         while ((i = entry_getlen(&ptr))) {
633                 struct berval bv;
634                 bv.bv_len = i;
635                 bv.bv_val = ptr;
636                 if (a) {
637                         a->a_next = (Attribute *)bptr;
638                 }
639                 a = (Attribute *)bptr;
640                 ad = NULL;
641                 rc = slap_bv2ad( &bv, &ad, &text );
642
643                 if( rc != LDAP_SUCCESS ) {
644 #ifdef NEW_LOGGING
645                         LDAP_LOG( OPERATION, INFO, 
646                                 "entry_decode: str2ad(%s): %s\n", ptr, text, 0 );
647 #else
648                         Debug( LDAP_DEBUG_TRACE,
649                                 "<= entry_decode: str2ad(%s): %s\n", ptr, text, 0 );
650 #endif
651                         rc = slap_bv2undef_ad( &bv, &ad, &text );
652
653                         if( rc != LDAP_SUCCESS ) {
654 #ifdef NEW_LOGGING
655                                 LDAP_LOG( OPERATION, INFO, 
656                                         "entry_decode:  str2undef_ad(%s): %s\n", ptr, text, 0 );
657 #else
658                                 Debug( LDAP_DEBUG_ANY,
659                                         "<= entry_decode: str2undef_ad(%s): %s\n",
660                                                 ptr, text, 0 );
661 #endif
662                                 return rc;
663                         }
664                 }
665                 ptr += i + 1;
666                 a->a_desc = ad;
667                 bptr = (BerVarray)(a+1);
668                 a->a_vals = bptr;
669                 a->a_flags = 0;
670                 count = j = entry_getlen(&ptr);
671
672                 while (j) {
673                         i = entry_getlen(&ptr);
674                         bptr->bv_len = i;
675                         bptr->bv_val = (char *)ptr;
676                         ptr += i+1;
677                         bptr++;
678                         j--;
679                 }
680                 bptr->bv_val = NULL;
681                 bptr->bv_len = 0;
682                 bptr++;
683
684 #ifdef SLAP_NVALUES
685                 if( count && ad->ad_type->sat_equality &&
686                         ad->ad_type->sat_equality->smr_match &&
687                         ad->ad_type->sat_syntax->ssyn_normalize )
688                 {
689                         a->a_nvals = ch_malloc((count+1)*sizeof(struct berval));
690
691                         for(j=0; j<count; j++) {
692                                 rc = ad->ad_type->sat_syntax->ssyn_normalize(
693                                         ad->ad_type->sat_syntax,
694                                         &a->a_vals[j], &a->a_nvals[j] );
695
696                                 if( rc ) {
697 #ifdef NEW_LOGGING
698                                         LDAP_LOG( OPERATION, DETAIL1,
699                                                 "entry_decode: NULL (ssyn_normalize %d)\n",
700                                                 rc, 0, 0 );
701 #else
702                                         Debug( LDAP_DEBUG_ANY,
703                                                 "<= entry_decode NULL (ssyn_normalize %d)\n",
704                                                 rc, 0, 0 );
705 #endif
706
707                                         return rc;
708                                 }
709                         }
710                 }
711 #endif
712
713         }
714
715         if (a) a->a_next = NULL;
716 #ifdef NEW_LOGGING
717         LDAP_LOG( OPERATION, DETAIL1, "entry_decode:  %s\n", x->e_dn, 0, 0 );
718 #else
719         Debug(LDAP_DEBUG_TRACE, "<= entry_decode(%s)\n",
720                 x->e_dn, 0, 0 );
721 #endif
722         *e = x;
723         return 0;
724 }
725 #endif