]> git.sur5r.net Git - openldap/blob - libraries/libldap/getdn.c
af9d2154a62fd8f522981db77542d173a8f0cb85
[openldap] / libraries / libldap / getdn.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1994 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  getdn.c
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/stdlib.h>
18 #include <ac/socket.h>
19 #include <ac/string.h>
20 #include <ac/time.h>
21
22 #include "ldap-int.h"
23 #include "ldap_schema.h"
24
25 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
26  * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
27 #define DC_IN_UFN
28 #define PRETTY_ESCAPE
29
30 /* parsing/printing routines */
31 static int str2strval( const char *str, ber_len_t stoplen, struct berval *val, 
32                 const char **next, unsigned flags, unsigned *retFlags );
33 static int DCE2strval( const char *str, struct berval *val, 
34                 const char **next, unsigned flags );
35 static int IA52strval( const char *str, struct berval *val, 
36                 const char **next, unsigned flags );
37 static int quotedIA52strval( const char *str, struct berval *val, 
38                 const char **next, unsigned flags );
39 static int hexstr2binval( const char *str, struct berval *val, 
40                 const char **next, unsigned flags );
41 static int hexstr2bin( const char *str, char *c );
42 static int byte2hexpair( const char *val, char *pair );
43 static int binval2hexstr( struct berval *val, char *str );
44 static int strval2strlen( struct berval *val, unsigned flags, 
45                 ber_len_t *len );
46 static int strval2str( struct berval *val, char *str, unsigned flags, 
47                 ber_len_t *len );
48 static int strval2IA5strlen( struct berval *val, unsigned flags,
49                 ber_len_t *len );
50 static int strval2IA5str( struct berval *val, char *str, unsigned flags, 
51                 ber_len_t *len );
52 static int strval2DCEstrlen( struct berval *val, unsigned flags,
53                 ber_len_t *len );
54 static int strval2DCEstr( struct berval *val, char *str, unsigned flags, 
55                 ber_len_t *len );
56 static int strval2ADstrlen( struct berval *val, unsigned flags,
57                 ber_len_t *len );
58 static int strval2ADstr( struct berval *val, char *str, unsigned flags, 
59                 ber_len_t *len );
60 static int dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN );
61
62 /* AVA helpers */
63 static LDAPAVA * ldapava_new(
64         const struct berval *attr, const struct berval *val, unsigned flags );
65
66 /* Higher level helpers */
67 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
68                 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
69 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
70                 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
71 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len  );
72 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
73 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
74 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
75 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
76 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
77
78 /*
79  * RFC 1823 ldap_get_dn
80  */
81 char *
82 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
83 {
84         char            *dn;
85         BerElement      tmp;
86
87         Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
88
89         if ( entry == NULL ) {
90                 ld->ld_errno = LDAP_PARAM_ERROR;
91                 return( NULL );
92         }
93
94         tmp = *entry->lm_ber;   /* struct copy */
95         if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
96                 ld->ld_errno = LDAP_DECODING_ERROR;
97                 return( NULL );
98         }
99
100         return( dn );
101 }
102
103 /*
104  * RFC 1823 ldap_dn2ufn
105  */
106 char *
107 ldap_dn2ufn( LDAP_CONST char *dn )
108 {
109         char    *out = NULL;
110
111         Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
112
113         ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
114                 &out, LDAP_DN_FORMAT_UFN );
115         
116         return( out );
117 }
118
119 /*
120  * RFC 1823 ldap_explode_dn
121  */
122 char **
123 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
124 {
125         LDAPDN  *tmpDN;
126         char    **values = NULL;
127         int     iRDN;
128         unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
129         
130         Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
131
132         if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) 
133                         != LDAP_SUCCESS ) {
134                 return NULL;
135         }
136
137         if( tmpDN == NULL ) {
138                 values = LDAP_MALLOC( sizeof( char * ) );
139                 if( values == NULL ) return NULL;
140
141                 values[0] = NULL;
142                 return values;
143         }
144
145         for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ );
146
147         values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
148         if ( values == NULL ) {
149                 ldap_dnfree( tmpDN );
150                 return NULL;
151         }
152
153         for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ ) {
154                 ldap_rdn2str( tmpDN[ 0 ][ iRDN ], &values[ iRDN ], flag );
155         }
156         ldap_dnfree( tmpDN );
157         values[ iRDN ] = NULL;
158
159         return values;
160 }
161
162 char **
163 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
164 {
165         LDAPRDN         *tmpRDN;
166         char            **values = NULL;
167         const char      *p;
168         int             iAVA;
169         
170         Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
171
172         /*
173          * we only parse the first rdn
174          * FIXME: we prefer efficiency over checking if the _ENTIRE_
175          * dn can be parsed
176          */
177         if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP ) 
178                         != LDAP_SUCCESS ) {
179                 return( NULL );
180         }
181
182         for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) ;
183         values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
184         if ( values == NULL ) {
185                 ldap_rdnfree( tmpRDN );
186                 return( NULL );
187         }
188
189         for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) {
190                 ber_len_t       l = 0, vl, al = 0;
191                 char            *str;
192                 LDAPAVA         *ava = tmpRDN[ 0 ][ iAVA ];
193                 
194                 if ( ava->la_flags == LDAP_AVA_BINARY ) {
195                         vl = 1 + 2 * ava->la_value.bv_len;
196
197                 } else {
198                         if ( strval2strlen( &ava->la_value, 
199                                                 ava->la_flags, &vl ) ) {
200                                 goto error_return;
201                         }
202                 }
203                 
204                 if ( !notypes ) {
205                         al = ava->la_attr.bv_len;
206                         l = vl + ava->la_attr.bv_len + 1;
207
208                         str = LDAP_MALLOC( l + 1 );
209                         AC_MEMCPY( str, ava->la_attr.bv_val, 
210                                         ava->la_attr.bv_len );
211                         str[ al++ ] = '=';
212
213                 } else {
214                         l = vl;
215                         str = LDAP_MALLOC( l + 1 );
216                 }
217                 
218                 if ( ava->la_flags == LDAP_AVA_BINARY ) {
219                         str[ al++ ] = '#';
220                         if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
221                                 goto error_return;
222                         }
223
224                 } else {
225                         if ( strval2str( &ava->la_value, &str[ al ], 
226                                         ava->la_flags, &vl ) ) {
227                                 goto error_return;
228                         }
229                 }
230
231                 str[ l ] = '\0';
232                 values[ iAVA ] = str;
233         }
234         values[ iAVA ] = NULL;
235
236         ldap_rdnfree( tmpRDN );
237
238         return( values );
239
240 error_return:;
241         LBER_VFREE( values );
242         ldap_rdnfree( tmpRDN );
243         return( NULL );
244 }
245
246 char *
247 ldap_dn2dcedn( LDAP_CONST char *dn )
248 {
249         char    *out = NULL;
250
251         Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
252
253         ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
254                                    &out, LDAP_DN_FORMAT_DCE );
255
256         return( out );
257 }
258
259 char *
260 ldap_dcedn2dn( LDAP_CONST char *dce )
261 {
262         char    *out = NULL;
263
264         Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
265
266         ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
267
268         return( out );
269 }
270
271 char *
272 ldap_dn2ad_canonical( LDAP_CONST char *dn )
273 {
274         char    *out = NULL;
275
276         Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
277
278         ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
279                        &out, LDAP_DN_FORMAT_AD_CANONICAL );
280
281         return( out );
282 }
283
284 /*
285  * function that changes the string representation of dnin
286  * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
287  * 
288  * fin can be one of:
289  *      LDAP_DN_FORMAT_LDAP             (rfc 2253 and ldapbis liberal, 
290  *                                      plus some rfc 1779)
291  *      LDAP_DN_FORMAT_LDAPV3           (rfc 2253 and ldapbis)
292  *      LDAP_DN_FORMAT_LDAPV2           (rfc 1779)
293  *      LDAP_DN_FORMAT_DCE              (?)
294  *
295  * fout can be any of the above except
296  *      LDAP_DN_FORMAT_LDAP
297  * plus:
298  *      LDAP_DN_FORMAT_UFN              (rfc 1781, partial and with extensions)
299  *      LDAP_DN_FORMAT_AD_CANONICAL     (?)
300  */
301 int
302 ldap_dn_normalize( LDAP_CONST char *dnin,
303         unsigned fin, char **dnout, unsigned fout )
304 {
305         int     rc;
306         LDAPDN  *tmpDN = NULL;
307
308         Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
309
310         assert( dnout );
311
312         *dnout = NULL;
313
314         if ( dnin == NULL ) {
315                 return( LDAP_SUCCESS );
316         }
317
318         rc = ldap_str2dn( dnin , &tmpDN, fin );
319         if ( rc != LDAP_SUCCESS ) {
320                 return( rc );
321         }
322
323         rc = ldap_dn2str( tmpDN, dnout, fout );
324
325         ldap_dnfree( tmpDN );
326
327         return( rc );
328 }
329
330 /* States */
331 #define B4AVA                   0x0000
332
333 /* #define      B4ATTRTYPE              0x0001 */
334 #define B4OIDATTRTYPE           0x0002
335 #define B4STRINGATTRTYPE        0x0003
336
337 #define B4AVAEQUALS             0x0100
338 #define B4AVASEP                0x0200
339 #define B4RDNSEP                0x0300
340 #define GOTAVA                  0x0400
341
342 #define B4ATTRVALUE             0x0010
343 #define B4STRINGVALUE           0x0020
344 #define B4IA5VALUEQUOTED        0x0030
345 #define B4IA5VALUE              0x0040
346 #define B4BINARYVALUE           0x0050
347
348 /*
349  * Helpers (mostly from slap.h)
350  * c is assumed to Unicode in an ASCII compatible format (UTF-8)
351  * Macros assume "C" Locale (ASCII)
352  */
353 #define LDAP_DN_ASCII_SPACE(c) \
354         ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
355 #define LDAP_DN_ASCII_LOWER(c)          LDAP_LOWER(c)
356 #define LDAP_DN_ASCII_UPPER(c)          LDAP_UPPER(c)
357 #define LDAP_DN_ASCII_ALPHA(c)          LDAP_ALPHA(c)
358
359 #define LDAP_DN_ASCII_DIGIT(c)          LDAP_DIGIT(c)
360 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) LDAP_HEXLOWER(c)
361 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) LDAP_HEXUPPER(c)
362 #define LDAP_DN_ASCII_HEXDIGIT(c)       LDAP_HEX(c)
363 #define LDAP_DN_ASCII_ALNUM(c)          LDAP_ALNUM(c)
364 #define LDAP_DN_ASCII_PRINTABLE(c)      ( (c) >= ' ' && (c) <= '~' )
365
366 /* attribute type */
367 #define LDAP_DN_OID_LEADCHAR(c)         LDAP_DIGIT(c)
368 #define LDAP_DN_DESC_LEADCHAR(c)        LDAP_ALPHA(c)
369 #define LDAP_DN_DESC_CHAR(c)            LDAP_LDH(c)
370 #define LDAP_DN_LANG_SEP(c)             ( (c) == ';' )
371 #define LDAP_DN_ATTRDESC_CHAR(c) \
372         ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
373
374 /* special symbols */
375 #define LDAP_DN_AVA_EQUALS(c)           ( (c) == '=' )
376 #define LDAP_DN_AVA_SEP(c)              ( (c) == '+' )
377 #define LDAP_DN_RDN_SEP(c)              ( (c) == ',' )
378 #define LDAP_DN_RDN_SEP_V2(c)           ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
379 #define LDAP_DN_OCTOTHORPE(c)           ( (c) == '#' )
380 #define LDAP_DN_QUOTES(c)               ( (c) == '\"' )
381 #define LDAP_DN_ESCAPE(c)               ( (c) == '\\' )
382 #define LDAP_DN_VALUE_END(c) \
383         ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
384 #define LDAP_DN_NE(c) \
385         ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
386           || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
387 #define LDAP_DN_MAYESCAPE(c) \
388         ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \
389           || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) )
390 #define LDAP_DN_NEEDESCAPE(c) \
391         ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
392 #define LDAP_DN_NEEDESCAPE_LEAD(c)      LDAP_DN_MAYESCAPE(c)
393 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
394         ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
395 #define LDAP_DN_WILLESCAPE_CHAR(c) \
396         ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
397 #define LDAP_DN_IS_PRETTY(f)            ( (f) & LDAP_DN_PRETTY )
398 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
399         ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
400
401 /* LDAPv2 */
402 #define LDAP_DN_VALUE_END_V2(c) \
403         ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
404 /* RFC 1779 */
405 #define LDAP_DN_V2_SPECIAL(c) \
406           ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
407             || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
408             || LDAP_DN_OCTOTHORPE(c) )
409 #define LDAP_DN_V2_PAIR(c) \
410           ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
411
412 /*
413  * DCE (mostly from Luke Howard and IBM implementation for AIX)
414  *
415  * From: "Application Development Guide - Directory Services" (FIXME: add link?)
416  * Here escapes and valid chars for GDS are considered; as soon as more
417  * specific info is found, the macros will be updated.
418  *
419  * Chars:       'a'-'z', 'A'-'Z', '0'-'9', 
420  *              '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
421  *
422  * Metachars:   '/', ',', '=', '\'.
423  *
424  * the '\' is used to escape other metachars.
425  *
426  * Assertion:           '='
427  * RDN separator:       '/'
428  * AVA separator:       ','
429  * 
430  * Attribute types must start with alphabetic chars and can contain 
431  * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
432  */
433 #define LDAP_DN_RDN_SEP_DCE(c)          ( (c) == '/' )
434 #define LDAP_DN_AVA_SEP_DCE(c)          ( (c) == ',' )
435 #define LDAP_DN_ESCAPE_DCE(c)           ( LDAP_DN_ESCAPE(c) )
436 #define LDAP_DN_VALUE_END_DCE(c) \
437         ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
438 #define LDAP_DN_NEEDESCAPE_DCE(c) \
439         ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
440
441 /* AD Canonical */
442 #define LDAP_DN_RDN_SEP_AD(c)           ( (c) == '/' )
443 #define LDAP_DN_ESCAPE_AD(c)            ( LDAP_DN_ESCAPE(c) )
444 #define LDAP_DN_AVA_SEP_AD(c)           ( (c) == ',' )  /* assume same as DCE */
445 #define LDAP_DN_VALUE_END_AD(c) \
446         ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
447 #define LDAP_DN_NEEDESCAPE_AD(c) \
448         ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
449
450 /* generics */
451 #define LDAP_DN_HEXPAIR(s) \
452         ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
453 /* better look at the AttributeDescription? */
454
455 /* FIXME: no composite rdn or non-"dc" types, right?
456  * (what about "dc" in OID form?) */
457 /* FIXME: we do not allow binary values in domain, right? */
458 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
459 /* NOTE: don't use strcasecmp() as it is locale specific! */
460 #define LDAP_DC_ATTR    "dc"
461 #define LDAP_DC_ATTRU   "DC"
462 #define LDAP_DN_IS_RDN_DC( r ) \
463         ( (r) && (r)[0][0] && !(r)[0][1] \
464           && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
465           && ((r)[0][0]->la_attr.bv_len == 2) \
466           && (((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
467                 || ((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
468           && (((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
469                 || ((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
470
471 /* Composite rules */
472 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
473         ( LDAP_DN_LDAPV2(f) \
474           || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
475 #define LDAP_DN_ALLOW_SPACES(f) \
476         ( LDAP_DN_LDAPV2(f) \
477           || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
478 #define LDAP_DN_LDAP(f) \
479         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
480 #define LDAP_DN_LDAPV3(f) \
481         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
482 #define LDAP_DN_LDAPV2(f) \
483         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
484 #define LDAP_DN_DCE(f) \
485         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
486 #define LDAP_DN_UFN(f) \
487         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
488 #define LDAP_DN_ADC(f) \
489         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
490 #define LDAP_DN_FORMAT(f)               ( (f) & LDAP_DN_FORMAT_MASK )
491
492 /*
493  * LDAPAVA helpers (will become part of the API for operations 
494  * on structural representations of DNs).
495  */
496 LDAPAVA *
497 ldapava_new( const struct berval *attr, const struct berval *val, 
498                 unsigned flags )
499 {
500         LDAPAVA *ava;
501
502         assert( attr );
503         assert( val );
504
505         ava = LDAP_MALLOC( sizeof( LDAPAVA ) + attr->bv_len + 1 );
506         
507         /* should we test it? */
508         if ( ava == NULL ) {
509                 return( NULL );
510         }
511
512         ava->la_attr.bv_len = attr->bv_len;
513         ava->la_attr.bv_val = (char *)(ava+1);
514         AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len );
515         ava->la_attr.bv_val[attr->bv_len] = '\0';
516
517         ava->la_value = *val;
518         ava->la_flags = flags;
519
520         ava->la_private = NULL;
521
522         return( ava );
523 }
524
525 void
526 ldap_avafree( LDAPAVA *ava )
527 {
528         assert( ava );
529
530 #if 0
531         /* ava's private must be freed by caller
532          * (at present let's skip this check because la_private
533          * basically holds static data) */
534         assert( ava->la_private == NULL );
535 #endif
536
537 #if 0
538         /* la_attr is now contiguous with ava, not freed separately */
539         LDAP_FREE( ava->la_attr.bv_val );
540 #endif
541         LDAP_FREE( ava->la_value.bv_val );
542
543         LDAP_FREE( ava );
544 }
545
546 void
547 ldap_rdnfree( LDAPRDN *rdn )
548 {
549         int iAVA;
550         
551         if ( rdn == NULL ) {
552                 return;
553         }
554
555         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
556                 ldap_avafree( rdn[ 0 ][ iAVA ] );
557         }
558
559         LDAP_FREE( rdn );
560 }
561
562 void
563 ldap_dnfree( LDAPDN *dn )
564 {
565         int iRDN;
566         
567         if ( dn == NULL ) {
568                 return;
569         }
570
571         for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
572                 ldap_rdnfree( dn[ 0 ][ iRDN ] );
573         }
574
575         LDAP_FREE( dn );
576 }
577
578 /*
579  * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
580  * into a structural representation of the DN, by separating attribute
581  * types and values encoded in the more appropriate form, which is
582  * string or OID for attribute types and binary form of the BER encoded
583  * value or Unicode string. Formats different from LDAPv3 are parsed
584  * according to their own rules and turned into the more appropriate
585  * form according to LDAPv3.
586  *
587  * NOTE: I realize the code is getting spaghettish; it is rather
588  * experimental and will hopefully turn into something more simple
589  * and readable as soon as it works as expected.
590  */
591
592 /*
593  * Default sizes of AVA and RDN static working arrays; if required
594  * the are dynamically resized.  The values can be tuned in case
595  * of special requirements (e.g. very deep DN trees or high number 
596  * of AVAs per RDN).
597  */
598 #define TMP_AVA_SLOTS   8
599 #define TMP_RDN_SLOTS   32
600
601 int
602 ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
603 {
604         struct berval   bv = { 0, (char *)str };
605
606         assert( str );
607
608         bv.bv_len = strlen( str );
609         
610         return ldap_bv2dn( &bv, dn, flags );
611 }
612
613 int
614 ldap_bv2dn( struct berval *bv, LDAPDN **dn, unsigned flags )
615 {
616         const char      *p;
617         int             rc = LDAP_DECODING_ERROR;
618         int             nrdns = 0;
619
620         LDAPDN          *newDN = NULL;
621         LDAPRDN         *newRDN = NULL, *tmpDN_[TMP_RDN_SLOTS], **tmpDN = tmpDN_;
622         int             num_slots = TMP_RDN_SLOTS;
623         char            *str = bv->bv_val;
624         char            *end = str + bv->bv_len;
625         
626         assert( bv );
627         assert( bv->bv_val );
628         assert( dn );
629
630         Debug( LDAP_DEBUG_TRACE, "=> ldap_bv2dn(%s,%u)\n%s", str, flags, "" );
631
632         *dn = NULL;
633
634         switch ( LDAP_DN_FORMAT( flags ) ) {
635         case LDAP_DN_FORMAT_LDAP:
636         case LDAP_DN_FORMAT_LDAPV3:
637         case LDAP_DN_FORMAT_LDAPV2:
638         case LDAP_DN_FORMAT_DCE:
639                 break;
640
641         /* unsupported in str2dn */
642         case LDAP_DN_FORMAT_UFN:
643         case LDAP_DN_FORMAT_AD_CANONICAL:
644                 return LDAP_PARAM_ERROR;
645
646         case LDAP_DN_FORMAT_LBER:
647         default:
648                 return LDAP_PARAM_ERROR;
649         }
650
651         if ( str[ 0 ] == '\0' ) {
652                 return LDAP_SUCCESS;
653         }
654
655         p = str;
656         if ( LDAP_DN_DCE( flags ) ) {
657                 
658                 /* 
659                  * (from Luke Howard: thnx) A RDN separator is required
660                  * at the beginning of an (absolute) DN.
661                  */
662                 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
663                         goto parsing_error;
664                 }
665                 p++;
666
667         /*
668          * actually we do not want to accept by default the DCE form,
669          * we do not want to auto-detect it
670          */
671 #if 0
672         } else if ( LDAP_DN_LDAP( flags ) ) {
673                 /*
674                  * if dn starts with '/' let's make it a DCE dn
675                  */
676                 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
677                         flags |= LDAP_DN_FORMAT_DCE;
678                         p++;
679                 }
680 #endif
681         }
682
683         for ( ; p < end; p++ ) {
684                 int             err;
685                 struct berval   tmpbv = { bv->bv_len - ( p - str ), (char *)p };
686                 
687                 err = ldap_bv2rdn( &tmpbv, &newRDN, (char **) &p, flags );
688                 if ( err != LDAP_SUCCESS ) {
689                         goto parsing_error;
690                 }
691
692                 /* 
693                  * We expect a rdn separator
694                  */
695                 if ( p < end && p[ 0 ] ) {
696                         switch ( LDAP_DN_FORMAT( flags ) ) {
697                         case LDAP_DN_FORMAT_LDAPV3:
698                                 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
699                                         rc = LDAP_DECODING_ERROR;
700                                         goto parsing_error;
701                                 }
702                                 break;
703         
704                         case LDAP_DN_FORMAT_LDAP:
705                         case LDAP_DN_FORMAT_LDAPV2:
706                                 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
707                                         rc = LDAP_DECODING_ERROR;
708                                         goto parsing_error;
709                                 }
710                                 break;
711         
712                         case LDAP_DN_FORMAT_DCE:
713                                 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
714                                         rc = LDAP_DECODING_ERROR;
715                                         goto parsing_error;
716                                 }
717                                 break;
718                         }
719                 }
720
721
722                 tmpDN[nrdns++] = newRDN;
723                 newRDN = NULL;
724
725                 /*
726                  * make the static RDN array dynamically rescalable
727                  */
728                 if ( nrdns == num_slots ) {
729                         LDAPRDN **tmp;
730
731                         if ( tmpDN == tmpDN_ ) {
732                                 tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPRDN * ) );
733                                 if ( tmp == NULL ) {
734                                         rc = LDAP_NO_MEMORY;
735                                         goto parsing_error;
736                                 }
737                                 AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) );
738
739                         } else {
740                                 tmp = LDAP_REALLOC( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ) );
741                                 if ( tmp == NULL ) {
742                                         rc = LDAP_NO_MEMORY;
743                                         goto parsing_error;
744                                 }
745                         }
746
747                         tmpDN = tmp;
748                         num_slots *= 2;
749                 }
750                                 
751                 if ( p >= end || p[ 0 ] == '\0' ) {
752                         /* 
753                          * the DN is over, phew
754                          */
755                         newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) +
756                                 sizeof(LDAPRDN *) * (nrdns+1));
757                         if ( newDN == NULL ) {
758                                 rc = LDAP_NO_MEMORY;
759                                 goto parsing_error;
760                         } else {
761                                 int i;
762
763                                 newDN[0] = (LDAPRDN **)(newDN+1);
764
765                                 if ( LDAP_DN_DCE( flags ) ) {
766                                         /* add in reversed order */
767                                         for ( i=0; i<nrdns; i++ )
768                                                 newDN[0][i] = tmpDN[nrdns-1-i];
769                                 } else {
770                                         for ( i=0; i<nrdns; i++ )
771                                                 newDN[0][i] = tmpDN[i];
772                                 }
773                                 newDN[0][nrdns] = NULL;
774                                 rc = LDAP_SUCCESS;
775                         }
776                         goto return_result;
777                 }
778         }
779         
780 parsing_error:;
781         if ( newRDN ) {
782                 ldap_rdnfree( newRDN );
783         }
784
785         for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
786                 ldap_rdnfree( tmpDN[nrdns] );
787         }
788
789 return_result:;
790
791         if ( tmpDN != tmpDN_ ) {
792                 LDAP_FREE( tmpDN );
793         }
794
795         Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s,%u)=%d\n", str, flags, rc );
796         *dn = newDN;
797         
798         return( rc );
799 }
800
801 /*
802  * ldap_str2rdn
803  *
804  * Parses a relative DN according to flags up to a rdn separator 
805  * or to the end of str.
806  * Returns the rdn and a pointer to the string continuation, which
807  * corresponds to the rdn separator or to '\0' in case the string is over.
808  */
809 int
810 ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
811         char **n_in, unsigned flags )
812 {
813         struct berval   bv = { 0, (char *)str };
814
815         assert( str );
816         assert( str[ 0 ] != '\0' );     /* FIXME: is this required? */
817
818         bv.bv_len = strlen( str );
819
820         return ldap_bv2rdn( &bv, rdn, n_in, flags );
821 }
822
823 int
824 ldap_bv2rdn( struct berval *bv, LDAPRDN **rdn,
825         char **n_in, unsigned flags )
826 {
827         const char      **n = (const char **) n_in;
828         const char      *p;
829         int             navas = 0;
830         int             state = B4AVA;
831         int             rc = LDAP_DECODING_ERROR;
832         int             attrTypeEncoding = LDAP_AVA_STRING, 
833                         attrValueEncoding = LDAP_AVA_STRING;
834
835         struct berval   attrType = { 0, NULL };
836         struct berval   attrValue = { 0, NULL };
837
838         LDAPRDN         *newRDN = NULL;
839         LDAPAVA         *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
840         int             num_slots = TMP_AVA_SLOTS;
841
842         char            *str;
843         ber_len_t       stoplen;
844         
845         assert( bv );
846         assert( bv->bv_len );
847         assert( bv->bv_val );
848         assert( rdn || flags & LDAP_DN_SKIP );
849         assert( n );
850
851         str = bv->bv_val;
852         stoplen = bv->bv_len;
853
854         if ( rdn ) {
855                 *rdn = NULL;
856         }
857         *n = NULL;
858
859         switch ( LDAP_DN_FORMAT( flags ) ) {
860         case LDAP_DN_FORMAT_LDAP:
861         case LDAP_DN_FORMAT_LDAPV3:
862         case LDAP_DN_FORMAT_LDAPV2:
863         case LDAP_DN_FORMAT_DCE:
864                 break;
865
866         /* unsupported in str2dn */
867         case LDAP_DN_FORMAT_UFN:
868         case LDAP_DN_FORMAT_AD_CANONICAL:
869                 return LDAP_PARAM_ERROR;
870
871         case LDAP_DN_FORMAT_LBER:
872         default:
873                 return LDAP_PARAM_ERROR;
874         }
875
876         if ( str[ 0 ] == '\0' ) {
877                 return LDAP_SUCCESS;
878         }
879
880         p = str;
881         for ( ; p[ 0 ] || state == GOTAVA; ) {
882                 
883                 /*
884                  * The parser in principle advances one token a time,
885                  * or toggles state if preferable.
886                  */
887                 switch (state) {
888
889                 /*
890                  * an AttributeType can be encoded as:
891                  * - its string representation; in detail, implementations
892                  *   MUST recognize AttributeType string type names listed 
893                  *   in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
894                  *   MAY recognize other names.
895                  * - its numeric OID (a dotted decimal string); in detail
896                  *   RFC 2253 asserts that ``Implementations MUST allow 
897                  *   an oid in the attribute type to be prefixed by one 
898                  *   of the character strings "oid." or "OID."''.  As soon
899                  *   as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253 
900                  *   I'm not sure whether this is required or not any 
901                  *   longer; to be liberal, we still implement it.
902                  */
903                 case B4AVA:
904                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
905                                 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
906                                         /* error */
907                                         goto parsing_error;
908                                 }
909                                 p++;
910                         }
911
912                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
913                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
914                                         /* error */
915                                         goto parsing_error;
916                                 }
917
918                                 /* whitespace is allowed (and trimmed) */
919                                 p++;
920                                 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
921                                         p++;
922                                 }
923
924                                 if ( !p[ 0 ] ) {
925                                         /* error: we expected an AVA */
926                                         goto parsing_error;
927                                 }
928                         }
929
930                         /* oid */
931                         if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
932                                 state = B4OIDATTRTYPE;
933                                 break;
934                         }
935                         
936                         /* else must be alpha */
937                         if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
938                                 goto parsing_error;
939                         }
940                         
941                         /* LDAPv2 "oid." prefix */
942                         if ( LDAP_DN_LDAPV2( flags ) ) {
943                                 /*
944                                  * to be overly pedantic, we only accept
945                                  * "OID." or "oid."
946                                  */
947                                 if ( flags & LDAP_DN_PEDANTIC ) {
948                                         if ( !strncmp( p, "OID.", 4 )
949                                                 || !strncmp( p, "oid.", 4 ) ) {
950                                                 p += 4;
951                                                 state = B4OIDATTRTYPE;
952                                                 break;
953                                         }
954                                 } else {
955                                        if ( !strncasecmp( p, "oid.", 4 ) ) {
956                                                p += 4;
957                                                state = B4OIDATTRTYPE;
958                                                break;
959                                        }
960                                 }
961                         }
962
963                         state = B4STRINGATTRTYPE;
964                         break;
965                 
966                 case B4OIDATTRTYPE: {
967                         int             err = LDAP_SUCCESS;
968                         
969                         attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
970                                 LDAP_SCHEMA_SKIP);
971
972                         if ( err != LDAP_SUCCESS ) {
973                                 goto parsing_error;
974                         }
975                         attrType.bv_len = p - attrType.bv_val;
976
977                         attrTypeEncoding = LDAP_AVA_BINARY;
978
979                         state = B4AVAEQUALS;
980                         break;
981                 }
982
983                 case B4STRINGATTRTYPE: {
984                         const char      *startPos, *endPos = NULL;
985                         ber_len_t       len;
986                         
987                         /* 
988                          * the starting char has been found to be
989                          * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
990                          * FIXME: DCE attr types seem to have a more
991                          * restrictive syntax (no '-' ...) 
992                          */
993                         for ( startPos = p++; p[ 0 ]; p++ ) {
994                                 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
995                                         continue;
996                                 }
997
998                                 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
999                                         
1000                                         /*
1001                                          * RFC 2253 does not explicitly
1002                                          * allow lang extensions to attribute 
1003                                          * types in DNs ... 
1004                                          */
1005                                         if ( flags & LDAP_DN_PEDANTIC ) {
1006                                                 goto parsing_error;
1007                                         }
1008
1009                                         /*
1010                                          * we trim ';' and following lang 
1011                                          * and so from attribute types
1012                                          */
1013                                         endPos = p;
1014                                         for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1015                                                         || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1016                                                 /* no op */ ;
1017                                         }
1018                                         break;
1019                                 }
1020                                 break;
1021                         }
1022
1023                         len = ( endPos ? endPos : p ) - startPos;
1024                         if ( len == 0 ) {
1025                                 goto parsing_error;
1026                         }
1027                         
1028                         attrTypeEncoding = LDAP_AVA_STRING;
1029
1030                         /*
1031                          * here we need to decide whether to use it as is 
1032                          * or turn it in OID form; as a consequence, we
1033                          * need to decide whether to binary encode the value
1034                          */
1035                         
1036                         state = B4AVAEQUALS;
1037
1038                         if ( flags & LDAP_DN_SKIP ) {
1039                                 break;
1040                         }
1041
1042                         attrType.bv_val = (char *)startPos;
1043                         attrType.bv_len = len;
1044
1045                         break;
1046                 }
1047                                 
1048                 case B4AVAEQUALS:
1049                         /* spaces may not be allowed */
1050                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1051                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1052                                         goto parsing_error;
1053                                 }
1054                         
1055                                 /* trim spaces */
1056                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1057                                         /* no op */
1058                                 }
1059                         }
1060
1061                         /* need equal sign */
1062                         if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1063                                 goto parsing_error;
1064                         }
1065                         p++;
1066
1067                         /* spaces may not be allowed */
1068                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1069                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1070                                         goto parsing_error;
1071                                 }
1072
1073                                 /* trim spaces */
1074                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1075                                         /* no op */
1076                                 }
1077                         }
1078
1079                         /*
1080                          * octothorpe means a BER encoded value will follow
1081                          * FIXME: I don't think DCE will allow it
1082                          */
1083                         if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1084                                 p++;
1085                                 attrValueEncoding = LDAP_AVA_BINARY;
1086                                 state = B4BINARYVALUE;
1087                                 break;
1088                         }
1089
1090                         /* STRING value expected */
1091
1092                         /* 
1093                          * if we're pedantic, an attribute type in OID form
1094                          * SHOULD imply a BER encoded attribute value; we
1095                          * should at least issue a warning
1096                          */
1097                         if ( ( flags & LDAP_DN_PEDANTIC )
1098                                 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1099                                 /* OID attrType SHOULD use binary encoding */
1100                                 goto parsing_error;
1101                         }
1102
1103                         attrValueEncoding = LDAP_AVA_STRING;
1104
1105                         /* 
1106                          * LDAPv2 allows the attribute value to be quoted;
1107                          * also, IA5 values are expected, in principle
1108                          */
1109                         if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1110                                 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1111                                         p++;
1112                                         state = B4IA5VALUEQUOTED;
1113                                         break;
1114                                 }
1115
1116                                 if ( LDAP_DN_LDAPV2( flags ) ) {
1117                                         state = B4IA5VALUE;
1118                                         break;
1119                                 }
1120                         }
1121
1122                         /*
1123                          * here STRING means RFC 2253 string
1124                          * FIXME: what about DCE strings? 
1125                          */
1126                         if ( !p[ 0 ] ) {
1127                                 /* empty value */
1128                                 state = GOTAVA;
1129                         } else {
1130                                 state = B4STRINGVALUE;
1131                         }
1132                         break;
1133
1134                 case B4BINARYVALUE:
1135                         if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1136                                 goto parsing_error;
1137                         }
1138
1139                         state = GOTAVA;
1140                         break;
1141
1142                 case B4STRINGVALUE:
1143                         switch ( LDAP_DN_FORMAT( flags ) ) {
1144                         case LDAP_DN_FORMAT_LDAP:
1145                         case LDAP_DN_FORMAT_LDAPV3:
1146                                 if ( str2strval( p, stoplen - ( p - str ),
1147                                                         &attrValue, &p, flags, 
1148                                                         &attrValueEncoding ) ) {
1149                                         goto parsing_error;
1150                                 }
1151                                 break;
1152
1153                         case LDAP_DN_FORMAT_DCE:
1154                                 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1155                                         goto parsing_error;
1156                                 }
1157                                 break;
1158
1159                         default:
1160                                 assert( 0 );
1161                         }
1162
1163                         state = GOTAVA;
1164                         break;
1165
1166                 case B4IA5VALUE:
1167                         if ( IA52strval( p, &attrValue, &p, flags ) ) {
1168                                 goto parsing_error;
1169                         }
1170
1171                         state = GOTAVA;
1172                         break;
1173                 
1174                 case B4IA5VALUEQUOTED:
1175
1176                         /* lead quote already stripped */
1177                         if ( quotedIA52strval( p, &attrValue, 
1178                                                 &p, flags ) ) {
1179                                 goto parsing_error;
1180                         }
1181
1182                         state = GOTAVA;
1183                         break;
1184
1185                 case GOTAVA: {
1186                         int     rdnsep = 0;
1187
1188                         if ( !( flags & LDAP_DN_SKIP ) ) {
1189                                 LDAPAVA *ava;
1190
1191                                 /*
1192                                  * we accept empty values
1193                                  */
1194                                 ava = ldapava_new( &attrType, &attrValue, 
1195                                                 attrValueEncoding );
1196                                 
1197                                 if ( ava == NULL ) {
1198                                         rc = LDAP_NO_MEMORY;
1199                                         goto parsing_error;
1200                                 }
1201                                 tmpRDN[navas++] = ava;
1202
1203                                 attrValue.bv_val = NULL;
1204                                 attrValue.bv_len = 0;
1205
1206                                 /*
1207                                  * prepare room for new AVAs if needed
1208                                  */
1209                                 if (navas == num_slots) {
1210                                         LDAPAVA **tmp;
1211                                         
1212                                         if ( tmpRDN == tmpRDN_ ) {
1213                                                 tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPAVA * ) );
1214                                                 if ( tmp == NULL ) {
1215                                                         rc = LDAP_NO_MEMORY;
1216                                                         goto parsing_error;
1217                                                 }
1218                                                 AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) );
1219
1220                                         } else {
1221                                                 tmp = LDAP_REALLOC( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ) );
1222                                                 if ( tmp == NULL ) {
1223                                                         rc = LDAP_NO_MEMORY;
1224                                                         goto parsing_error;
1225                                                 }
1226                                         }
1227
1228                                         tmpRDN = tmp;
1229                                         num_slots *= 2;
1230                                 }
1231                         }
1232                         
1233                         /* 
1234                          * if we got an AVA separator ('+', or ',' for DCE ) 
1235                          * we expect a new AVA for this RDN; otherwise 
1236                          * we add the RDN to the DN
1237                          */
1238                         switch ( LDAP_DN_FORMAT( flags ) ) {
1239                         case LDAP_DN_FORMAT_LDAP:
1240                         case LDAP_DN_FORMAT_LDAPV3:
1241                         case LDAP_DN_FORMAT_LDAPV2:
1242                                 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1243                                         rdnsep = 1;
1244                                 }
1245                                 break;
1246
1247                         case LDAP_DN_FORMAT_DCE:
1248                                 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1249                                         rdnsep = 1;
1250                                 }
1251                                 break;
1252                         }
1253
1254                         if ( rdnsep ) {
1255                                 /* 
1256                                  * the RDN is over, phew
1257                                  */
1258                                 *n = p;
1259                                 if ( !( flags & LDAP_DN_SKIP ) ) {
1260                                         newRDN = (LDAPRDN *)LDAP_MALLOC( sizeof(LDAPRDN)
1261                                                 + sizeof(LDAPAVA *) * (navas+1) );
1262                                         if ( newRDN == NULL ) {
1263                                                 rc = LDAP_NO_MEMORY;
1264                                                 goto parsing_error;
1265                                         } else {
1266                                                 int i;
1267
1268                                                 newRDN[0] = (LDAPAVA**)(newRDN+1);
1269
1270                                                 for (i=0; i<navas; i++)
1271                                                         newRDN[0][i] = tmpRDN[i];
1272                                                 newRDN[0][i] = NULL;
1273                                         }
1274
1275                                 }
1276                                 rc = LDAP_SUCCESS;
1277                                 goto return_result;
1278                         }
1279
1280                         /* they should have been used in an AVA */
1281                         attrType.bv_val = NULL;
1282                         attrValue.bv_val = NULL;
1283                         
1284                         p++;
1285                         state = B4AVA;
1286                         break;
1287                 }
1288
1289                 default:
1290                         assert( 0 );
1291                         goto parsing_error;
1292                 }
1293         }
1294         *n = p;
1295         
1296 parsing_error:;
1297         /* They are set to NULL after they're used in an AVA */
1298
1299         if ( attrValue.bv_val ) {
1300                 free( attrValue.bv_val );
1301         }
1302
1303         for ( navas-- ; navas >= 0; navas-- ) {
1304                 ldap_avafree( tmpRDN[navas] );
1305         }
1306
1307 return_result:;
1308
1309         if ( tmpRDN != tmpRDN_ ) {
1310                 LDAP_FREE( tmpRDN );
1311         }
1312
1313         if ( rdn ) {
1314                 *rdn = newRDN;
1315         }
1316         
1317         return( rc );
1318 }
1319
1320 /*
1321  * reads in a UTF-8 string value, unescaping stuff:
1322  * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1323  * '\' + HEXPAIR(p) -> unhex(p)
1324  */
1325 static int
1326 str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, unsigned *retFlags )
1327 {
1328         const char      *p, *end, *startPos, *endPos = NULL;
1329         ber_len_t       len, escapes;
1330
1331         assert( str );
1332         assert( val );
1333         assert( next );
1334
1335         *next = NULL;
1336         end = str + stoplen;
1337         for ( startPos = p = str, escapes = 0; p < end; p++ ) {
1338                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1339                         p++;
1340                         if ( p[ 0 ] == '\0' ) {
1341                                 return( 1 );
1342                         }
1343                         if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
1344                                 escapes++;
1345                                 continue;
1346                         }
1347
1348                         if ( LDAP_DN_HEXPAIR( p ) ) {
1349                                 char c;
1350
1351                                 hexstr2bin( p, &c );
1352                                 escapes += 2;
1353
1354                                 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1355
1356                                         /*
1357                                          * we assume the string is UTF-8
1358                                          */
1359                                         *retFlags = LDAP_AVA_NONPRINTABLE;
1360                                 }
1361                                 p++;
1362
1363                                 continue;
1364                         }
1365
1366                         if ( LDAP_DN_PEDANTIC & flags ) {
1367                                 return( 1 );
1368                         }
1369                         /* 
1370                          * we do not allow escaping 
1371                          * of chars that don't need 
1372                          * to and do not belong to 
1373                          * HEXDIGITS
1374                          */
1375                         return( 1 );
1376
1377                 } else if (!LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) {
1378                         *retFlags = LDAP_AVA_NONPRINTABLE;
1379
1380                 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) 
1381                                 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1382                         break;
1383
1384                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1385                         /* 
1386                          * FIXME: maybe we can add 
1387                          * escapes if not pedantic?
1388                          */
1389                         return( 1 );
1390                 }
1391         }
1392
1393         /*
1394          * we do allow unescaped spaces at the end
1395          * of the value only in non-pedantic mode
1396          */
1397         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1398                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1399                 if ( flags & LDAP_DN_PEDANTIC ) {
1400                         return( 1 );
1401                 }
1402
1403                 /* strip trailing (unescaped) spaces */
1404                 for ( endPos = p - 1; 
1405                                 endPos > startPos + 1 && 
1406                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1407                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1408                                 endPos-- ) {
1409                         /* no op */
1410                 }
1411         }
1412
1413         *next = p;
1414         if ( flags & LDAP_DN_SKIP ) {
1415                 return( 0 );
1416         }
1417
1418         /*
1419          * FIXME: test memory?
1420          */
1421         len = ( endPos ? endPos : p ) - startPos - escapes;
1422         val->bv_len = len;
1423
1424         if ( escapes == 0 ) {
1425                 if ( *retFlags == LDAP_AVA_NONPRINTABLE ) {
1426                         val->bv_val = LDAP_MALLOC( len + 1 );
1427                         AC_MEMCPY( val->bv_val, startPos, len );
1428                         val->bv_val[ len ] = '\0';
1429                 } else {
1430                         val->bv_val = LDAP_STRNDUP( startPos, len );
1431                 }
1432
1433         } else {
1434                 ber_len_t       s, d;
1435
1436                 val->bv_val = LDAP_MALLOC( len + 1 );
1437                 for ( s = 0, d = 0; d < len; ) {
1438                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1439                                 s++;
1440                                 if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
1441                                         val->bv_val[ d++ ] = 
1442                                                 startPos[ s++ ];
1443                                         
1444                                 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1445                                         char    c;
1446
1447                                         hexstr2bin( &startPos[ s ], &c );
1448                                         val->bv_val[ d++ ] = c;
1449                                         s += 2;
1450                                         
1451                                 } else {
1452                                         /* we should never get here */
1453                                         assert( 0 );
1454                                 }
1455
1456                         } else {
1457                                 val->bv_val[ d++ ] = startPos[ s++ ];
1458                         }
1459                 }
1460
1461                 val->bv_val[ d ] = '\0';
1462                 assert( d == len );
1463         }
1464
1465         return( 0 );
1466 }
1467
1468 static int
1469 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags )
1470 {
1471         const char      *p, *startPos, *endPos = NULL;
1472         ber_len_t       len, escapes;
1473
1474         assert( str );
1475         assert( val );
1476         assert( next );
1477
1478         *next = NULL;
1479         
1480         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1481                 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1482                         p++;
1483                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1484                                 escapes++;
1485
1486                         } else {
1487                                 return( 1 );
1488                         }
1489
1490                 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1491                         break;
1492                 }
1493
1494                 /*
1495                  * FIXME: can we accept anything else? I guess we need
1496                  * to stop if a value is not legal
1497                  */
1498         }
1499
1500         /* 
1501          * (unescaped) trailing spaces are trimmed must be silently ignored;
1502          * so we eat them
1503          */
1504         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1505                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1506                 if ( flags & LDAP_DN_PEDANTIC ) {
1507                         return( 1 );
1508                 }
1509
1510                 /* strip trailing (unescaped) spaces */
1511                 for ( endPos = p - 1; 
1512                                 endPos > startPos + 1 && 
1513                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1514                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1515                                 endPos-- ) {
1516                         /* no op */
1517                 }
1518         }
1519
1520         *next = p;
1521         if ( flags & LDAP_DN_SKIP ) {
1522                 return( 0 );
1523         }
1524         
1525         len = ( endPos ? endPos : p ) - startPos - escapes;
1526         val->bv_len = len;
1527         if ( escapes == 0 ){
1528                 val->bv_val = LDAP_STRNDUP( startPos, len );
1529
1530         } else {
1531                 ber_len_t       s, d;
1532
1533                 val->bv_val = LDAP_MALLOC( len + 1 );
1534                 for ( s = 0, d = 0; d < len; ) {
1535                         /*
1536                          * This point is reached only if escapes 
1537                          * are properly used, so all we need to
1538                          * do is eat them
1539                          */
1540                         if (  LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1541                                 s++;
1542
1543                         }
1544                         val->bv_val[ d++ ] = startPos[ s++ ];
1545                 }
1546                 val->bv_val[ d ] = '\0';
1547                 assert( strlen( val->bv_val ) == len );
1548         }
1549         
1550         return( 0 );
1551 }
1552
1553 static int
1554 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1555 {
1556         const char      *p, *startPos, *endPos = NULL;
1557         ber_len_t       len, escapes;
1558
1559         assert( str );
1560         assert( val );
1561         assert( next );
1562
1563         *next = NULL;
1564
1565         /*
1566          * LDAPv2 (RFC 1779)
1567          */
1568         
1569         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1570                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1571                         p++;
1572                         if ( p[ 0 ] == '\0' ) {
1573                                 return( 1 );
1574                         }
1575
1576                         if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1577                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1578                                 return( 1 );
1579                         }
1580                         escapes++;
1581
1582                 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1583                         break;
1584                 }
1585
1586                 /*
1587                  * FIXME: can we accept anything else? I guess we need
1588                  * to stop if a value is not legal
1589                  */
1590         }
1591
1592         /* strip trailing (unescaped) spaces */
1593         for ( endPos = p; 
1594                         endPos > startPos + 1 && 
1595                         LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1596                         !LDAP_DN_ESCAPE( endPos[ -2 ] );
1597                         endPos-- ) {
1598                 /* no op */
1599         }
1600
1601         *next = p;
1602         if ( flags & LDAP_DN_SKIP ) {
1603                 return( 0 );
1604         }
1605
1606         len = ( endPos ? endPos : p ) - startPos - escapes;
1607         val->bv_len = len;
1608         if ( escapes == 0 ) {
1609                 val->bv_val = LDAP_STRNDUP( startPos, len );
1610
1611         } else {
1612                 ber_len_t       s, d;
1613                 
1614                 val->bv_val = LDAP_MALLOC( len + 1 );
1615                 for ( s = 0, d = 0; d < len; ) {
1616                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1617                                 s++;
1618                         }
1619                         val->bv_val[ d++ ] = startPos[ s++ ];
1620                 }
1621                 val->bv_val[ d ] = '\0';
1622                 assert( strlen( val->bv_val ) == len );
1623         }
1624
1625         return( 0 );
1626 }
1627
1628 static int
1629 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1630 {
1631         const char      *p, *startPos, *endPos = NULL;
1632         ber_len_t       len;
1633         unsigned        escapes = 0;
1634
1635         assert( str );
1636         assert( val );
1637         assert( next );
1638
1639         *next = NULL;
1640
1641         /* initial quote already eaten */
1642         for ( startPos = p = str; p[ 0 ]; p++ ) {
1643                 /* 
1644                  * According to RFC 1779, the quoted value can
1645                  * contain escaped as well as unescaped special values;
1646                  * as a consequence we tolerate escaped values 
1647                  * (e.g. '"\,"' -> '\,') and escape unescaped specials
1648                  * (e.g. '","' -> '\,').
1649                  */
1650                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1651                         if ( p[ 1 ] == '\0' ) {
1652                                 return( 1 );
1653                         }
1654                         p++;
1655
1656                         if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1657                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1658                                 /*
1659                                  * do we allow to escape normal chars?
1660                                  * LDAPv2 does not allow any mechanism 
1661                                  * for escaping chars with '\' and hex 
1662                                  * pair
1663                                  */
1664                                 return( 1 );
1665                         }
1666                         escapes++;
1667
1668                 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1669                         endPos = p;
1670                         /* eat closing quotes */
1671                         p++;
1672                         break;
1673                 }
1674
1675                 /*
1676                  * FIXME: can we accept anything else? I guess we need
1677                  * to stop if a value is not legal
1678                  */
1679         }
1680
1681         if ( endPos == NULL ) {
1682                 return( 1 );
1683         }
1684
1685         /* Strip trailing (unescaped) spaces */
1686         for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1687                 /* no op */
1688         }
1689
1690         *next = p;
1691         if ( flags & LDAP_DN_SKIP ) {
1692                 return( 0 );
1693         }
1694
1695         len = endPos - startPos - escapes;
1696         assert( len >= 0 );
1697         val->bv_len = len;
1698         if ( escapes == 0 ) {
1699                 val->bv_val = LDAP_STRNDUP( startPos, len );
1700
1701         } else {
1702                 ber_len_t       s, d;
1703                 
1704                 val->bv_val = LDAP_MALLOC( len + 1 );
1705                 val->bv_len = len;
1706
1707                 for ( s = d = 0; d < len; ) {
1708                         if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1709                                 s++;
1710                         }
1711                         val->bv_val[ d++ ] = str[ s++ ];
1712                 }
1713                 val->bv_val[ d ] = '\0';
1714                 assert( strlen( val->bv_val ) == len );
1715         }
1716
1717         return( 0 );
1718 }
1719
1720 static int
1721 hexstr2bin( const char *str, char *c )
1722 {
1723         char    c1, c2;
1724
1725         assert( str );
1726         assert( c );
1727
1728         c1 = str[ 0 ];
1729         c2 = str[ 1 ];
1730
1731         if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1732                 *c = c1 - '0';
1733
1734         } else {
1735                 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1736                         *c = c1 - 'A' + 10;
1737                 } else {
1738                         assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1739                         *c = c1 - 'a' + 10;
1740                 }
1741         }
1742
1743         *c <<= 4;
1744
1745         if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1746                 *c += c2 - '0';
1747                 
1748         } else {
1749                 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1750                         *c += c2 - 'A' + 10;
1751                 } else {
1752                         assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1753                         *c += c2 - 'a' + 10;
1754                 }
1755         }
1756
1757         return( 0 );
1758 }
1759
1760 static int
1761 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags )
1762 {
1763         const char      *p, *startPos, *endPos = NULL;
1764         ber_len_t       len;
1765         ber_len_t       s, d;
1766
1767         assert( str );
1768         assert( val );
1769         assert( next );
1770
1771         *next = NULL;
1772
1773         for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1774                 switch ( LDAP_DN_FORMAT( flags ) ) {
1775                 case LDAP_DN_FORMAT_LDAPV3:
1776                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1777                                 goto end_of_value;
1778                         }
1779                         break;
1780
1781                 case LDAP_DN_FORMAT_LDAP:
1782                 case LDAP_DN_FORMAT_LDAPV2:
1783                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1784                                 goto end_of_value;
1785                         }
1786                         break;
1787
1788                 case LDAP_DN_FORMAT_DCE:
1789                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1790                                 goto end_of_value;
1791                         }
1792                         break;
1793                 }
1794
1795                 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1796                         if ( flags & LDAP_DN_PEDANTIC ) {
1797                                 return( 1 );
1798                         }
1799                         endPos = p;
1800
1801                         for ( ; p[ 0 ]; p++ ) {
1802                                 switch ( LDAP_DN_FORMAT( flags ) ) {
1803                                 case LDAP_DN_FORMAT_LDAPV3:
1804                                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1805                                                 goto end_of_value;
1806                                         }
1807                                         break;
1808
1809                                 case LDAP_DN_FORMAT_LDAP:
1810                                 case LDAP_DN_FORMAT_LDAPV2:
1811                                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1812                                                 goto end_of_value;
1813                                         }
1814                                         break;
1815
1816                                 case LDAP_DN_FORMAT_DCE:
1817                                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1818                                                 goto end_of_value;
1819                                         }
1820                                         break;
1821                                 }
1822                         }
1823                         break;
1824                 }
1825                 
1826                 if ( !LDAP_DN_HEXPAIR( p ) ) {
1827                         return( 1 );
1828                 }
1829         }
1830
1831 end_of_value:;
1832
1833         *next = p;
1834         if ( flags & LDAP_DN_SKIP ) {
1835                 return( 0 );
1836         }
1837
1838         len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1839         /* must be even! */
1840         assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1841
1842         val->bv_len = len;
1843         val->bv_val = LDAP_MALLOC( len + 1 );
1844         if ( val->bv_val == NULL ) {
1845                 return( LDAP_NO_MEMORY );
1846         }
1847
1848         for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1849                 char    c;
1850
1851                 hexstr2bin( &startPos[ s ], &c );
1852
1853                 val->bv_val[ d ] = c;
1854         }
1855
1856         val->bv_val[ d ] = '\0';
1857
1858         return( 0 );
1859 }
1860
1861 /*
1862  * convert a byte in a hexadecimal pair
1863  */
1864 static int
1865 byte2hexpair( const char *val, char *pair )
1866 {
1867         static const char       hexdig[] = "0123456789ABCDEF";
1868
1869         assert( val );
1870         assert( pair );
1871
1872         /* 
1873          * we assume the string has enough room for the hex encoding
1874          * of the value
1875          */
1876
1877         pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1878         pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1879         
1880         return( 0 );
1881 }
1882
1883 /*
1884  * convert a binary value in hexadecimal pairs
1885  */
1886 static int
1887 binval2hexstr( struct berval *val, char *str )
1888 {
1889         ber_len_t       s, d;
1890
1891         assert( val );
1892         assert( str );
1893
1894         if ( val->bv_len == 0 ) {
1895                 return( 0 );
1896         }
1897
1898         /* 
1899          * we assume the string has enough room for the hex encoding
1900          * of the value
1901          */
1902
1903         for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1904                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1905         }
1906         
1907         return( 0 );
1908 }
1909
1910 /*
1911  * Length of the string representation, accounting for escaped hex
1912  * of UTF-8 chars
1913  */
1914 static int
1915 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1916 {
1917         ber_len_t       l, cl = 1;
1918         char            *p;
1919         int             escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1920 #ifdef PRETTY_ESCAPE
1921         int             escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1922 #endif /* PRETTY_ESCAPE */
1923         
1924         assert( val );
1925         assert( len );
1926
1927         *len = 0;
1928         if ( val->bv_len == 0 ) {
1929                 return( 0 );
1930         }
1931
1932         for ( l = 0, p = val->bv_val; p < val->bv_val + val->bv_len; p += cl ) {
1933
1934                 /* 
1935                  * escape '%x00' 
1936                  */
1937                 if ( p[ 0 ] == '\0' ) {
1938                         cl = 1;
1939                         l += 3;
1940                         continue;
1941                 }
1942
1943                 cl = LDAP_UTF8_CHARLEN2( p, cl );
1944                 if ( cl == 0 ) {
1945                         /* illegal utf-8 char! */
1946                         return( -1 );
1947
1948                 } else if ( cl > 1 ) {
1949                         ber_len_t cnt;
1950
1951                         for ( cnt = 1; cnt < cl; cnt++ ) {
1952                                 if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
1953                                         return( -1 );
1954                                 }
1955                         }
1956                         l += escaped_byte_len * cl;
1957
1958                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1959                                 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1960                                 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1961 #ifdef PRETTY_ESCAPE
1962 #if 0
1963                         if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1964 #else
1965                         if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
1966 #endif
1967
1968                                 /* 
1969                                  * there might be some chars we want 
1970                                  * to escape in form of a couple 
1971                                  * of hexdigits for optimization purposes
1972                                  */
1973                                 l += 3;
1974
1975                         } else {
1976                                 l += escaped_ascii_len;
1977                         }
1978 #else /* ! PRETTY_ESCAPE */
1979                         l += 3;
1980 #endif /* ! PRETTY_ESCAPE */
1981
1982                 } else {
1983                         l++;
1984                 }
1985         }
1986
1987         *len = l;
1988
1989         return( 0 );
1990 }
1991
1992 /*
1993  * convert to string representation, escaping with hex the UTF-8 stuff;
1994  * assume the destination has enough room for escaping
1995  */
1996 static int
1997 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1998 {
1999         ber_len_t       s, d, end;
2000
2001         assert( val );
2002         assert( str );
2003         assert( len );
2004
2005         if ( val->bv_len == 0 ) {
2006                 *len = 0;
2007                 return( 0 );
2008         }
2009
2010         /* 
2011          * we assume the string has enough room for the hex encoding
2012          * of the value
2013          */
2014         for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2015                 ber_len_t       cl;
2016
2017                 /* 
2018                  * escape '%x00' 
2019                  */
2020                 if ( val->bv_val[ s ] == '\0' ) {
2021                         cl = 1;
2022                         str[ d++ ] = '\\';
2023                         str[ d++ ] = '0';
2024                         str[ d++ ] = '0';
2025                         s++;
2026                         continue;
2027                 }
2028                 
2029                 /*
2030                  * The length was checked in strval2strlen();
2031                  * LDAP_UTF8_CHARLEN() should suffice
2032                  */
2033                 cl = LDAP_UTF8_CHARLEN2( &val->bv_val[ s ], cl );
2034                 assert( cl > 0 );
2035                 
2036                 /* 
2037                  * there might be some chars we want to escape in form
2038                  * of a couple of hexdigits for optimization purposes
2039                  */
2040                 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) 
2041 #ifdef PRETTY_ESCAPE
2042 #if 0
2043                                 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] ) 
2044 #else
2045                                 || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] ) 
2046 #endif
2047 #else /* ! PRETTY_ESCAPE */
2048                                 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2049                                 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2050                                 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
2051
2052 #endif /* ! PRETTY_ESCAPE */
2053                                 ) {
2054                         for ( ; cl--; ) {
2055                                 str[ d++ ] = '\\';
2056                                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2057                                 s++;
2058                                 d += 2;
2059                         }
2060
2061                 } else if ( cl > 1 ) {
2062                         for ( ; cl--; ) {
2063                                 str[ d++ ] = val->bv_val[ s++ ];
2064                         }
2065
2066                 } else {
2067 #ifdef PRETTY_ESCAPE
2068                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2069                                         || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2070                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2071                                 str[ d++ ] = '\\';
2072                                 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2073                                         byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2074                                         s++;
2075                                         d += 2;
2076                                         continue;
2077                                 }
2078                         }
2079 #endif /* PRETTY_ESCAPE */
2080                         str[ d++ ] = val->bv_val[ s++ ];
2081                 }
2082         }
2083
2084         *len = d;
2085         
2086         return( 0 );
2087 }
2088
2089 /*
2090  * Length of the IA5 string representation (no UTF-8 allowed)
2091  */
2092 static int
2093 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2094 {
2095         ber_len_t       l;
2096         char            *p;
2097
2098         assert( val );
2099         assert( len );
2100
2101         *len = 0;
2102         if ( val->bv_len == 0 ) {
2103                 return( 0 );
2104         }
2105
2106         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2107                 /*
2108                  * Turn value into a binary encoded BER
2109                  */
2110                 return( -1 );
2111
2112         } else {
2113                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2114                         if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2115                                         || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2116                                         || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2117                                 l += 2;
2118
2119                         } else {
2120                                 l++;
2121                         }
2122                 }
2123         }
2124
2125         *len = l;
2126         
2127         return( 0 );
2128 }
2129
2130 /*
2131  * convert to string representation (np UTF-8)
2132  * assume the destination has enough room for escaping
2133  */
2134 static int
2135 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2136 {
2137         ber_len_t       s, d, end;
2138
2139         assert( val );
2140         assert( str );
2141         assert( len );
2142
2143         if ( val->bv_len == 0 ) {
2144                 *len = 0;
2145                 return( 0 );
2146         }
2147
2148         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2149                 /*
2150                  * Turn value into a binary encoded BER
2151                  */
2152                 *len = 0;
2153                 return( -1 );
2154
2155         } else {
2156                 /* 
2157                  * we assume the string has enough room for the hex encoding
2158                  * of the value
2159                  */
2160
2161                 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2162                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2163                                         || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2164                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2165                                 str[ d++ ] = '\\';
2166                         }
2167                         str[ d++ ] = val->bv_val[ s++ ];
2168                 }
2169         }
2170
2171         *len = d;
2172         
2173         return( 0 );
2174 }
2175
2176 /*
2177  * Length of the (supposedly) DCE string representation, 
2178  * accounting for escaped hex of UTF-8 chars
2179  */
2180 static int
2181 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2182 {
2183         ber_len_t       l;
2184         char            *p;
2185
2186         assert( val );
2187         assert( len );
2188
2189         *len = 0;
2190         if ( val->bv_len == 0 ) {
2191                 return( 0 );
2192         }
2193
2194         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2195                 /* 
2196                  * FIXME: Turn the value into a binary encoded BER?
2197                  */
2198                 return( -1 );
2199                 
2200         } else {
2201                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2202                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2203                                 l += 2;
2204
2205                         } else {
2206                                 l++;
2207                         }
2208                 }
2209         }
2210
2211         *len = l;
2212
2213         return( 0 );
2214 }
2215
2216 /*
2217  * convert to (supposedly) DCE string representation, 
2218  * escaping with hex the UTF-8 stuff;
2219  * assume the destination has enough room for escaping
2220  */
2221 static int
2222 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2223 {
2224         ber_len_t       s, d;
2225
2226         assert( val );
2227         assert( str );
2228         assert( len );
2229
2230         if ( val->bv_len == 0 ) {
2231                 *len = 0;
2232                 return( 0 );
2233         }
2234
2235         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2236                 /*
2237                  * FIXME: Turn the value into a binary encoded BER?
2238                  */
2239                 *len = 0;
2240                 return( -1 );
2241                 
2242         } else {
2243
2244                 /* 
2245                  * we assume the string has enough room for the hex encoding
2246                  * of the value
2247                  */
2248
2249                 for ( s = 0, d = 0; s < val->bv_len; ) {
2250                         if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2251                                 str[ d++ ] = '\\';
2252                         }
2253                         str[ d++ ] = val->bv_val[ s++ ];
2254                 }
2255         }
2256
2257         *len = d;
2258         
2259         return( 0 );
2260 }
2261
2262 /*
2263  * Length of the (supposedly) AD canonical string representation, 
2264  * accounting for escaped hex of UTF-8 chars
2265  */
2266 static int
2267 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2268 {
2269         ber_len_t       l;
2270         char            *p;
2271
2272         assert( val );
2273         assert( len );
2274
2275         *len = 0;
2276         if ( val->bv_len == 0 ) {
2277                 return( 0 );
2278         }
2279
2280         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2281                 /* 
2282                  * FIXME: Turn the value into a binary encoded BER?
2283                  */
2284                 return( -1 );
2285                 
2286         } else {
2287                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2288                         if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2289                                 l += 2;
2290
2291                         } else {
2292                                 l++;
2293                         }
2294                 }
2295         }
2296
2297         *len = l;
2298         
2299         return( 0 );
2300 }
2301
2302 /*
2303  * convert to (supposedly) AD string representation, 
2304  * escaping with hex the UTF-8 stuff;
2305  * assume the destination has enough room for escaping
2306  */
2307 static int
2308 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2309 {
2310         ber_len_t       s, d;
2311
2312         assert( val );
2313         assert( str );
2314         assert( len );
2315
2316         if ( val->bv_len == 0 ) {
2317                 *len = 0;
2318                 return( 0 );
2319         }
2320
2321         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2322                 /*
2323                  * FIXME: Turn the value into a binary encoded BER?
2324                  */
2325                 *len = 0;
2326                 return( -1 );
2327                 
2328         } else {
2329
2330                 /* 
2331                  * we assume the string has enough room for the hex encoding
2332                  * of the value
2333                  */
2334
2335                 for ( s = 0, d = 0; s < val->bv_len; ) {
2336                         if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2337                                 str[ d++ ] = '\\';
2338                         }
2339                         str[ d++ ] = val->bv_val[ s++ ];
2340                 }
2341         }
2342
2343         *len = d;
2344         
2345         return( 0 );
2346 }
2347
2348 /*
2349  * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2350  * the first part of the AD representation of the DN is written in DNS
2351  * form, i.e. dot separated domain name components (as suggested 
2352  * by Luke Howard, http://www.padl.com/~lukeh)
2353  */
2354 static int
2355 dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN )
2356 {
2357         int             i;
2358         int             domain = 0, first = 1;
2359         ber_len_t       l = 1; /* we move the null also */
2360         char            *str;
2361
2362         /* we are guaranteed there's enough memory in str */
2363
2364         /* sanity */
2365         assert( dn );
2366         assert( bv );
2367         assert( iRDN );
2368         assert( *iRDN >= 0 );
2369
2370         str = bv->bv_val + pos;
2371
2372         for ( i = *iRDN; i >= 0; i-- ) {
2373                 LDAPRDN         *rdn;
2374                 LDAPAVA         *ava;
2375
2376                 assert( dn[ 0 ][ i ] );
2377                 rdn = dn[ 0 ][ i ];
2378
2379                 assert( rdn[ 0 ][ 0 ] );
2380                 ava = rdn[ 0 ][ 0 ];
2381
2382                 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2383                         break;
2384                 }
2385
2386                 domain = 1;
2387                 
2388                 if ( first ) {
2389                         first = 0;
2390                         AC_MEMCPY( str, ava->la_value.bv_val, 
2391                                         ava->la_value.bv_len + 1);
2392                         l += ava->la_value.bv_len;
2393
2394                 } else {
2395                         AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l);
2396                         AC_MEMCPY( str, ava->la_value.bv_val, 
2397                                         ava->la_value.bv_len );
2398                         str[ ava->la_value.bv_len ] = '.';
2399                         l += ava->la_value.bv_len + 1;
2400                 }
2401         }
2402
2403         *iRDN = i;
2404         bv->bv_len = pos + l - 1;
2405
2406         return( domain );
2407 }
2408
2409 static int
2410 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2411          int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2412 {
2413         int             iAVA;
2414         ber_len_t       l = 0;
2415
2416         *len = 0;
2417
2418         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2419                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2420
2421                 /* len(type) + '=' + '+' | ',' */
2422                 l += ava->la_attr.bv_len + 2;
2423
2424                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2425                         /* octothorpe + twice the length */
2426                         l += 1 + 2 * ava->la_value.bv_len;
2427
2428                 } else {
2429                         ber_len_t       vl;
2430                         unsigned        f = flags | ava->la_flags;
2431                         
2432                         if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2433                                 return( -1 );
2434                         }
2435                         l += vl;
2436                 }
2437         }
2438         
2439         *len = l;
2440         
2441         return( 0 );
2442 }
2443
2444 static int
2445 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2446         int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2447 {
2448         int             iAVA;
2449         ber_len_t       l = 0;
2450
2451         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2452                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2453
2454                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2455                                 ava->la_attr.bv_len );
2456                 l += ava->la_attr.bv_len;
2457
2458                 str[ l++ ] = '=';
2459
2460                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2461                         str[ l++ ] = '#';
2462                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2463                                 return( -1 );
2464                         }
2465                         l += 2 * ava->la_value.bv_len;
2466
2467                 } else {
2468                         ber_len_t       vl;
2469                         unsigned        f = flags | ava->la_flags;
2470
2471                         if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2472                                 return( -1 );
2473                         }
2474                         l += vl;
2475                 }
2476                 str[ l++ ] = ( rdn[ 0 ][ iAVA + 1 ] ? '+' : ',' );
2477         }
2478
2479         *len = l;
2480
2481         return( 0 );
2482 }
2483
2484 static int
2485 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2486 {
2487         int             iAVA;
2488         ber_len_t       l = 0;
2489
2490         *len = 0;
2491
2492         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2493                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2494
2495                 /* len(type) + '=' + ',' | '/' */
2496                 l += ava->la_attr.bv_len + 2;
2497
2498                 switch ( ava->la_flags ) {
2499                 case LDAP_AVA_BINARY:
2500                         /* octothorpe + twice the length */
2501                         l += 1 + 2 * ava->la_value.bv_len;
2502                         break;
2503
2504                 case LDAP_AVA_STRING: {
2505                         ber_len_t       vl;
2506                         unsigned        f = flags | ava->la_flags;
2507                         
2508                         if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2509                                 return( -1 );
2510                         }
2511                         l += vl;
2512                         break;
2513                 }
2514
2515                 default:
2516                         return( -1 );
2517                 }
2518         }
2519         
2520         *len = l;
2521         
2522         return( 0 );
2523 }
2524
2525 static int
2526 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2527 {
2528         int             iAVA;
2529         ber_len_t       l = 0;
2530
2531         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2532                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2533
2534                 if ( first ) {
2535                         first = 0;
2536                 } else {
2537                         str[ l++ ] = ( iAVA ? ',' : '/' );
2538                 }
2539
2540                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2541                                 ava->la_attr.bv_len );
2542                 l += ava->la_attr.bv_len;
2543
2544                 str[ l++ ] = '=';
2545
2546                 switch ( ava->la_flags ) {
2547                         case LDAP_AVA_BINARY:
2548                         str[ l++ ] = '#';
2549                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2550                                 return( -1 );
2551                         }
2552                         l += 2 * ava->la_value.bv_len;
2553                         break;
2554
2555                 case LDAP_AVA_STRING: {
2556                         ber_len_t       vl;
2557                         unsigned        f = flags | ava->la_flags;
2558
2559                         if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2560                                 return( -1 );
2561                         }
2562                         l += vl;
2563                         break;
2564                 }
2565                                       
2566                 default:
2567                         return( -1 );
2568                 }
2569         }
2570
2571         *len = l;
2572
2573         return( 0 );
2574 }
2575
2576 static int
2577 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2578 {
2579         int             iAVA;
2580         ber_len_t       l = 0;
2581
2582         assert( rdn );
2583         assert( len );
2584
2585         *len = 0;
2586
2587         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2588                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2589
2590                 /* ' + ' | ', ' */
2591                 l += ( rdn[ 0 ][ iAVA + 1 ] ? 3 : 2 );
2592
2593                 /* FIXME: are binary values allowed in UFN? */
2594                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2595                         /* octothorpe + twice the value */
2596                         l += 1 + 2 * ava->la_value.bv_len;
2597
2598                 } else {
2599                         ber_len_t       vl;
2600                         unsigned        f = flags | ava->la_flags;
2601
2602                         if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2603                                 return( -1 );
2604                         }
2605                         l += vl;
2606                 }
2607         }
2608         
2609         *len = l;
2610         
2611         return( 0 );
2612 }
2613
2614 static int
2615 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2616 {
2617         int             iAVA;
2618         ber_len_t       l = 0;
2619
2620         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2621                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2622
2623                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2624                         str[ l++ ] = '#';
2625                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2626                                 return( -1 );
2627                         }
2628                         l += 2 * ava->la_value.bv_len;
2629                         
2630                 } else {
2631                         ber_len_t       vl;
2632                         unsigned        f = flags | ava->la_flags;
2633                         
2634                         if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2635                                 return( -1 );
2636                         }
2637                         l += vl;
2638                 }
2639
2640                 if ( rdn[ 0 ][ iAVA + 1 ]) {
2641                         AC_MEMCPY( &str[ l ], " + ", 3 );
2642                         l += 3;
2643
2644                 } else {
2645                         AC_MEMCPY( &str[ l ], ", ", 2 );
2646                         l += 2;
2647                 }
2648         }
2649
2650         *len = l;
2651
2652         return( 0 );
2653 }
2654
2655 static int
2656 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2657 {
2658         int             iAVA;
2659         ber_len_t       l = 0;
2660
2661         assert( rdn );
2662         assert( len );
2663
2664         *len = 0;
2665
2666         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2667                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2668
2669                 /* ',' | '/' */
2670                 l++;
2671
2672                 /* FIXME: are binary values allowed in UFN? */
2673                 switch ( ava->la_flags ) {
2674                 case LDAP_AVA_BINARY:
2675                         /* octothorpe + twice the value */
2676                         l += 1 + 2 * ava->la_value.bv_len;
2677                         break;
2678
2679                 case LDAP_AVA_STRING: {
2680                         ber_len_t       vl;
2681                         unsigned        f = flags | ava->la_flags;
2682
2683                         if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2684                                 return( -1 );
2685                         }
2686                         l += vl;
2687                         break;
2688                 }
2689
2690                 default:
2691                         return( -1 );
2692                 }
2693         }
2694         
2695         *len = l;
2696         
2697         return( 0 );
2698 }
2699
2700 static int
2701 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2702 {
2703         int             iAVA;
2704         ber_len_t       l = 0;
2705
2706         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2707                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2708
2709                 if ( first ) {
2710                         first = 0;
2711                 } else {
2712                         str[ l++ ] = ( iAVA ? ',' : '/' );
2713                 }
2714
2715                 switch ( ava->la_flags ) {
2716                 case LDAP_AVA_BINARY:
2717                         str[ l++ ] = '#';
2718                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2719                                 return( -1 );
2720                         }
2721                         l += 2 * ava->la_value.bv_len;
2722                         break;
2723                         
2724                 case LDAP_AVA_STRING: {
2725                         ber_len_t       vl;
2726                         unsigned        f = flags | ava->la_flags;
2727                         
2728                         if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2729                                 return( -1 );
2730                         }
2731                         l += vl;
2732                         break;
2733                 }
2734
2735                 default:
2736                         return( -1 );
2737                 }
2738         }
2739
2740         *len = l;
2741
2742         return( 0 );
2743 }
2744
2745 /*
2746  * ldap_rdn2str
2747  *
2748  * Returns in str a string representation of rdn based on flags.
2749  * There is some duplication of code between this and ldap_dn2str;
2750  * this is wanted to reduce the allocation of temporary buffers.
2751  */
2752 int
2753 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2754 {
2755         struct berval bv;
2756         int rc;
2757
2758         assert( str );
2759
2760         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2761                 return LDAP_PARAM_ERROR;
2762         }
2763
2764         rc = ldap_rdn2bv( rdn, &bv, flags );
2765         *str = bv.bv_val;
2766         return rc;
2767 }
2768
2769 int
2770 ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags )
2771 {
2772         int             rc, back;
2773         ber_len_t       l;
2774         
2775         assert( bv );
2776
2777         bv->bv_len = 0;
2778         bv->bv_val = NULL;
2779
2780         if ( rdn == NULL ) {
2781                 bv->bv_val = LDAP_STRDUP( "" );
2782                 return( LDAP_SUCCESS );
2783         }
2784
2785         /*
2786          * This routine wastes "back" bytes at the end of the string
2787          */
2788
2789         switch ( LDAP_DN_FORMAT( flags ) ) {
2790         case LDAP_DN_FORMAT_LDAPV3:
2791                 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2792                         return LDAP_DECODING_ERROR;
2793                 }
2794                 break;
2795
2796         case LDAP_DN_FORMAT_LDAPV2:
2797                 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2798                         return LDAP_DECODING_ERROR;
2799                 }
2800                 break;
2801
2802         case LDAP_DN_FORMAT_UFN:
2803                 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2804                         return LDAP_DECODING_ERROR;
2805                 }
2806                 break;
2807
2808         case LDAP_DN_FORMAT_DCE:
2809                 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2810                         return LDAP_DECODING_ERROR;
2811                 }
2812                 break;
2813
2814         case LDAP_DN_FORMAT_AD_CANONICAL:
2815                 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2816                         return LDAP_DECODING_ERROR;
2817                 }
2818                 break;
2819
2820         default:
2821                 return( LDAP_PARAM_ERROR );
2822         }
2823
2824         bv->bv_val = LDAP_MALLOC( l + 1 );
2825
2826         switch ( LDAP_DN_FORMAT( flags ) ) {
2827         case LDAP_DN_FORMAT_LDAPV3:
2828                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2829                 back = 1;
2830                 break;
2831
2832         case LDAP_DN_FORMAT_LDAPV2:
2833                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2834                 back = 1;
2835                 break;
2836
2837         case LDAP_DN_FORMAT_UFN:
2838                 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2839                 back = 2;
2840                 break;
2841
2842         case LDAP_DN_FORMAT_DCE:
2843                 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2844                 back = 0;
2845                 break;
2846
2847         case LDAP_DN_FORMAT_AD_CANONICAL:
2848                 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2849                 back = 0;
2850                 break;
2851
2852         default:
2853                 /* need at least one of the previous */
2854                 return LDAP_PARAM_ERROR;
2855         }
2856
2857         if ( rc ) {
2858                 ldap_memfree( bv->bv_val );
2859                 return rc;
2860         }
2861
2862         bv->bv_len = l - back;
2863         bv->bv_val[ bv->bv_len ] = '\0';
2864
2865         return LDAP_SUCCESS;
2866 }
2867
2868 /*
2869  * Very bulk implementation; many optimizations can be performed
2870  *   - a NULL dn results in an empty string ""
2871  * 
2872  * FIXME: doubts
2873  *   a) what do we do if a UTF-8 string must be converted in LDAPv2?
2874  *      we must encode it in binary form ('#' + HEXPAIRs)
2875  *   b) does DCE/AD support UTF-8?
2876  *      no clue; don't think so.
2877  *   c) what do we do when binary values must be converted in UTF/DCE/AD?
2878  *      use binary encoded BER
2879  */ 
2880 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2881 {
2882         struct berval bv;
2883         int rc;
2884
2885         assert( str );
2886
2887         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2888                 return LDAP_PARAM_ERROR;
2889         }
2890         
2891         rc = ldap_dn2bv( dn, &bv, flags );
2892         *str = bv.bv_val;
2893         return rc;
2894 }
2895
2896 int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
2897 {
2898         int             iRDN;
2899         int             rc = LDAP_ENCODING_ERROR;
2900         ber_len_t       len, l;
2901
2902         /* stringifying helpers for LDAPv3/LDAPv2 */
2903         int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2904         int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2905
2906         assert( bv );
2907         bv->bv_len = 0;
2908         bv->bv_val = NULL;
2909
2910         Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" );
2911
2912         /* 
2913          * a null dn means an empty dn string 
2914          * FIXME: better raise an error?
2915          */
2916         if ( dn == NULL ) {
2917                 bv->bv_val = LDAP_STRDUP( "" );
2918                 return( LDAP_SUCCESS );
2919         }
2920
2921         switch ( LDAP_DN_FORMAT( flags ) ) {
2922         case LDAP_DN_FORMAT_LDAPV3:
2923                 sv2l = strval2strlen;
2924                 sv2s = strval2str;
2925
2926                 if( 0 ) {
2927         case LDAP_DN_FORMAT_LDAPV2:
2928                         sv2l = strval2IA5strlen;
2929                         sv2s = strval2IA5str;
2930                 }
2931
2932                 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2933                         ber_len_t       rdnl;
2934                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2935                         
2936                         if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2937                                 goto return_results;
2938                         }
2939
2940                         len += rdnl;
2941                 }
2942
2943                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2944                         rc = LDAP_NO_MEMORY;
2945                         break;
2946                 }
2947
2948                 for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2949                         ber_len_t       rdnl;
2950                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2951                         
2952                         if ( rdn2str( rdn, &bv->bv_val[ l ], flags, 
2953                                         &rdnl, sv2s ) ) {
2954                                 LDAP_FREE( bv->bv_val );
2955                                 bv->bv_val = NULL;
2956                                 goto return_results;
2957                         }
2958                         l += rdnl;
2959                 }
2960
2961                 assert( l == len );
2962
2963                 /* 
2964                  * trim the last ',' (the allocated memory 
2965                  * is one byte longer than required)
2966                  */
2967                 bv->bv_len = len - 1;
2968                 bv->bv_val[ bv->bv_len ] = '\0';
2969
2970                 rc = LDAP_SUCCESS;
2971                 break;
2972
2973         case LDAP_DN_FORMAT_UFN: {
2974                 /*
2975                  * FIXME: quoting from RFC 1781:
2976                  *
2977    To take a distinguished name, and generate a name of this format with
2978    attribute types omitted, the following steps are followed.
2979
2980     1.  If the first attribute is of type CommonName, the type may be
2981         omitted.
2982
2983     2.  If the last attribute is of type Country, the type may be
2984         omitted.
2985
2986     3.  If the last attribute is of type Country, the last
2987         Organisation attribute may have the type omitted.
2988
2989     4.  All attributes of type OrganisationalUnit may have the type
2990         omitted, unless they are after an Organisation attribute or
2991         the first attribute is of type OrganisationalUnit.
2992
2993          * this should be the pedantic implementation.
2994                  *
2995                  * Here the standard implementation reflects
2996                  * the one historically provided by OpenLDAP
2997                  * (and UMIch, I presume), with the variant
2998                  * of spaces and plusses (' + ') separating 
2999                  * rdn components.
3000                  * 
3001                  * A non-standard but nice implementation could
3002                  * be to turn the  final "dc" attributes into a 
3003                  * dot-separated domain.
3004                  *
3005                  * Other improvements could involve the use of
3006                  * friendly country names and so.
3007                  */
3008 #ifdef DC_IN_UFN
3009                 int     leftmost_dc = -1;
3010                 int     last_iRDN = -1;
3011 #endif /* DC_IN_UFN */
3012
3013                 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
3014                         ber_len_t       rdnl;
3015                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3016                         
3017                         if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
3018                                 goto return_results;
3019                         }
3020                         len += rdnl;
3021
3022 #ifdef DC_IN_UFN
3023                         if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
3024                                 if ( leftmost_dc == -1 ) {
3025                                         leftmost_dc = iRDN;
3026                                 }
3027                         } else {
3028                                 leftmost_dc = -1;
3029                         }
3030 #endif /* DC_IN_UFN */
3031                 }
3032
3033                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3034                         rc = LDAP_NO_MEMORY;
3035                         break;
3036                 }
3037
3038 #ifdef DC_IN_UFN
3039                 if ( leftmost_dc == -1 ) {
3040 #endif /* DC_IN_UFN */
3041                         for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
3042                                 ber_len_t       vl;
3043                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3044                         
3045                                 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], 
3046                                                 flags, &vl ) ) {
3047                                         LDAP_FREE( bv->bv_val );
3048                                         bv->bv_val = NULL;
3049                                         goto return_results;
3050                                 }
3051                                 l += vl;
3052                         }
3053
3054                         /* 
3055                          * trim the last ', ' (the allocated memory 
3056                          * is two bytes longer than required)
3057                          */
3058                         bv->bv_len = len - 2;
3059                         bv->bv_val[ bv->bv_len ] = '\0';
3060 #ifdef DC_IN_UFN
3061                 } else {
3062                         last_iRDN = iRDN - 1;
3063
3064                         for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3065                                 ber_len_t       vl;
3066                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3067                         
3068                                 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], 
3069                                                 flags, &vl ) ) {
3070                                         LDAP_FREE( bv->bv_val );
3071                                         bv->bv_val = NULL;
3072                                         goto return_results;
3073                                 }
3074                                 l += vl;
3075                         }
3076
3077                         if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
3078                                 LDAP_FREE( bv->bv_val );
3079                                 bv->bv_val = NULL;
3080                                 goto return_results;
3081                         }
3082
3083                         /* the string is correctly terminated by dn2domain */
3084                 }
3085 #endif /* DC_IN_UFN */
3086                 
3087                 rc = LDAP_SUCCESS;
3088
3089         } break;
3090
3091         case LDAP_DN_FORMAT_DCE:
3092                 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
3093                         ber_len_t       rdnl;
3094                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3095                         
3096                         if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3097                                 goto return_results;
3098                         }
3099
3100                         len += rdnl;
3101                 }
3102
3103                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3104                         rc = LDAP_NO_MEMORY;
3105                         break;
3106                 }
3107
3108                 for ( l = 0; iRDN--; ) {
3109                         ber_len_t       rdnl;
3110                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3111                         
3112                         if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags, 
3113                                         &rdnl, 0 ) ) {
3114                                 LDAP_FREE( bv->bv_val );
3115                                 bv->bv_val = NULL;
3116                                 goto return_results;
3117                         }
3118                         l += rdnl;
3119                 }
3120
3121                 assert( l == len );
3122
3123                 bv->bv_len = len;
3124                 bv->bv_val[ bv->bv_len ] = '\0';
3125
3126                 rc = LDAP_SUCCESS;
3127                 break;
3128
3129         case LDAP_DN_FORMAT_AD_CANONICAL: {
3130                 /*
3131                  * Sort of UFN for DCE DNs: a slash ('/') separated
3132                  * global->local DN with no types; strictly speaking,
3133                  * the naming context should be a domain, which is
3134                  * written in DNS-style, e.g. dot-deparated.
3135                  * 
3136                  * Example:
3137                  * 
3138                  *      "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3139                  *
3140                  * will read
3141                  * 
3142                  *      "microsoft.com/People/Bill,Gates"
3143                  */ 
3144                 for ( iRDN = 0, len = -1; dn[ 0 ][ iRDN ]; iRDN++ ) {
3145                         ber_len_t       rdnl;
3146                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3147                         
3148                         if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3149                                 goto return_results;
3150                         }
3151
3152                         len += rdnl;
3153                 }
3154
3155                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3156                         rc = LDAP_NO_MEMORY;
3157                         break;
3158                 }
3159
3160                 iRDN--;
3161                 if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) ) {
3162                         for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3163                                 ber_len_t       rdnl;
3164                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3165                         
3166                                 if ( rdn2ADstr( rdn, &bv->bv_val[ l ], 
3167                                                 flags, &rdnl, 0 ) ) {
3168                                         LDAP_FREE( bv->bv_val );
3169                                         bv->bv_val = NULL;
3170                                         goto return_results;
3171                                 }
3172                                 l += rdnl;
3173                         }
3174
3175                 } else {
3176                         int             first = 1;
3177
3178                         /*
3179                          * Strictly speaking, AD canonical requires
3180                          * a DN to be in the form "..., dc=smtg",
3181                          * i.e. terminated by a domain component
3182                          */
3183                         if ( flags & LDAP_DN_PEDANTIC ) {
3184                                 LDAP_FREE( bv->bv_val );
3185                                 bv->bv_val = NULL;
3186                                 rc = LDAP_ENCODING_ERROR;
3187                                 break;
3188                         }
3189
3190                         for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3191                                 ber_len_t       rdnl;
3192                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3193                         
3194                                 if ( rdn2ADstr( rdn, &bv->bv_val[ l ], 
3195                                                 flags, &rdnl, first ) ) {
3196                                         LDAP_FREE( bv->bv_val );
3197                                         bv->bv_val = NULL;
3198                                         goto return_results;
3199                                 }
3200                                 if ( first ) {
3201                                         first = 0;
3202                                 }
3203                                 l += rdnl;
3204                         }
3205                 }
3206
3207                 bv->bv_len = len;
3208                 bv->bv_val[ bv->bv_len ] = '\0';
3209
3210                 rc = LDAP_SUCCESS;
3211         } break;
3212
3213         default:
3214                 return LDAP_PARAM_ERROR;
3215         }
3216
3217         Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n",
3218                 bv->bv_val, flags, rc );
3219
3220 return_results:;
3221         return( rc );
3222 }
3223