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