]> git.sur5r.net Git - openldap/blob - libraries/libldap/getdn.c
e102023aa8dec9871f300c35f0f1ef3cf9ce8480
[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, 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 #define TMP_SLOTS       1024
593
594 int
595 ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
596 {
597         const char      *p;
598         int             rc = LDAP_DECODING_ERROR;
599         int             nrdns = 0;
600
601         LDAPDN          *newDN = NULL;
602         LDAPRDN         *newRDN = NULL, *tmpDN[TMP_SLOTS];
603         
604         assert( str );
605         assert( dn );
606
607         Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
608
609         *dn = NULL;
610
611         switch ( LDAP_DN_FORMAT( flags ) ) {
612         case LDAP_DN_FORMAT_LDAP:
613         case LDAP_DN_FORMAT_LDAPV3:
614         case LDAP_DN_FORMAT_LDAPV2:
615         case LDAP_DN_FORMAT_DCE:
616                 break;
617
618         /* unsupported in str2dn */
619         case LDAP_DN_FORMAT_UFN:
620         case LDAP_DN_FORMAT_AD_CANONICAL:
621                 return LDAP_PARAM_ERROR;
622
623         case LDAP_DN_FORMAT_LBER:
624         default:
625                 return LDAP_PARAM_ERROR;
626         }
627
628         if ( str[ 0 ] == '\0' ) {
629                 return LDAP_SUCCESS;
630         }
631
632         p = str;
633         if ( LDAP_DN_DCE( flags ) ) {
634                 
635                 /* 
636                  * (from Luke Howard: thnx) A RDN separator is required
637                  * at the beginning of an (absolute) DN.
638                  */
639                 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
640                         goto parsing_error;
641                 }
642                 p++;
643                 
644         } else if ( LDAP_DN_LDAP( flags ) ) {
645                 /*
646                  * if dn starts with '/' let's make it a DCE dn
647                  */
648                 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
649                         flags |= LDAP_DN_FORMAT_DCE;
650                         p++;
651                 }
652         }
653
654         for ( ; p[ 0 ]; p++ ) {
655                 int             err;
656                 
657                 err = ldap_str2rdn( p, &newRDN, (char **) &p, flags );
658                 if ( err != LDAP_SUCCESS ) {
659                         goto parsing_error;
660                 }
661
662                 /* 
663                  * We expect a rdn separator
664                  */
665                 if ( p[ 0 ] ) {
666                         switch ( LDAP_DN_FORMAT( flags ) ) {
667                         case LDAP_DN_FORMAT_LDAPV3:
668                                 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
669                                         rc = LDAP_DECODING_ERROR;
670                                         goto parsing_error;
671                                 }
672                                 break;
673         
674                         case LDAP_DN_FORMAT_LDAP:
675                         case LDAP_DN_FORMAT_LDAPV2:
676                                 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
677                                         rc = LDAP_DECODING_ERROR;
678                                         goto parsing_error;
679                                 }
680                                 break;
681         
682                         case LDAP_DN_FORMAT_DCE:
683                                 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
684                                         rc = LDAP_DECODING_ERROR;
685                                         goto parsing_error;
686                                 }
687                                 break;
688                         }
689                 }
690
691
692                 tmpDN[nrdns++] = newRDN;
693                 newRDN = NULL;
694
695 #if 0
696                 /*
697                  * prone to attacks?
698                  */
699                 assert (nrdns < TMP_SLOTS);
700 #else
701                 /*
702                  * make the static AVA array dynamically rescalable
703                  */
704                 if (nrdns >= TMP_SLOTS) {
705                         rc = LDAP_DECODING_ERROR;
706                         goto parsing_error;
707                 }
708 #endif
709                                 
710                 if ( p[ 0 ] == '\0' ) {
711                         /* 
712                          * the DN is over, phew
713                          */
714                         newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) +
715                                 sizeof(LDAPRDN *) * (nrdns+1));
716                         if ( newDN == NULL ) {
717                                 rc = LDAP_NO_MEMORY;
718                                 goto parsing_error;
719                         } else {
720                                 int i;
721
722                                 newDN[0] = (LDAPRDN **)(newDN+1);
723
724                                 if ( LDAP_DN_DCE( flags ) ) {
725                                         /* add in reversed order */
726                                         for ( i=0; i<nrdns; i++ )
727                                                 newDN[0][i] = tmpDN[nrdns-1-i];
728                                 } else {
729                                         for ( i=0; i<nrdns; i++ )
730                                                 newDN[0][i] = tmpDN[i];
731                                 }
732                                 newDN[0][nrdns] = NULL;
733                                 rc = LDAP_SUCCESS;
734                         }
735                         goto return_result;
736                 }
737         }
738         
739 parsing_error:;
740         if ( newRDN ) {
741                 ldap_rdnfree( newRDN );
742         }
743
744         for (nrdns-- ;nrdns>=0; nrdns-- )
745                 ldap_rdnfree( tmpDN[nrdns] );
746
747 return_result:;
748         Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
749         *dn = newDN;
750         
751         return( rc );
752 }
753
754 /*
755  * ldap_str2rdn
756  *
757  * Parses a relative DN according to flags up to a rdn separator 
758  * or to the end of str.
759  * Returns the rdn and a pointer to the string continuation, which
760  * corresponds to the rdn separator or to '\0' in case the string is over.
761  */
762 int
763 ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
764         char **n_in, unsigned flags )
765 {
766         const char  **n = (const char **) n_in;
767         const char      *p;
768         int             navas = 0;
769         int             state = B4AVA;
770         int             rc = LDAP_DECODING_ERROR;
771         int             attrTypeEncoding = LDAP_AVA_STRING, 
772                         attrValueEncoding = LDAP_AVA_STRING;
773
774         struct berval   attrType = { 0, NULL };
775         struct berval   attrValue = { 0, NULL };
776
777         LDAPRDN         *newRDN = NULL;
778         LDAPAVA         *tmpRDN[TMP_SLOTS];
779         
780         assert( str );
781         assert( rdn || flags & LDAP_DN_SKIP );
782         assert( n );
783
784         Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
785
786         if ( rdn ) {
787                 *rdn = NULL;
788         }
789         *n = NULL;
790
791         switch ( LDAP_DN_FORMAT( flags ) ) {
792         case LDAP_DN_FORMAT_LDAP:
793         case LDAP_DN_FORMAT_LDAPV3:
794         case LDAP_DN_FORMAT_LDAPV2:
795         case LDAP_DN_FORMAT_DCE:
796                 break;
797
798         /* unsupported in str2dn */
799         case LDAP_DN_FORMAT_UFN:
800         case LDAP_DN_FORMAT_AD_CANONICAL:
801                 return LDAP_PARAM_ERROR;
802
803         case LDAP_DN_FORMAT_LBER:
804         default:
805                 return LDAP_PARAM_ERROR;
806         }
807
808         if ( str[ 0 ] == '\0' ) {
809                 return LDAP_SUCCESS;
810         }
811
812         p = str;
813         for ( ; p[ 0 ] || state == GOTAVA; ) {
814                 
815                 /*
816                  * The parser in principle advances one token a time,
817                  * or toggles state if preferable.
818                  */
819                 switch (state) {
820
821                 /*
822                  * an AttributeType can be encoded as:
823                  * - its string representation; in detail, implementations
824                  *   MUST recognize AttributeType string type names listed 
825                  *   in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
826                  *   MAY recognize other names.
827                  * - its numeric OID (a dotted decimal string); in detail
828                  *   RFC 2253 asserts that ``Implementations MUST allow 
829                  *   an oid in the attribute type to be prefixed by one 
830                  *   of the character strings "oid." or "OID."''.  As soon
831                  *   as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253 
832                  *   I'm not sure whether this is required or not any 
833                  *   longer; to be liberal, we still implement it.
834                  */
835                 case B4AVA:
836                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
837                                 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
838                                         /* error */
839                                         goto parsing_error;
840                                 }
841                                 p++;
842                         }
843
844                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
845                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
846                                         /* error */
847                                         goto parsing_error;
848                                 }
849
850                                 /* whitespace is allowed (and trimmed) */
851                                 p++;
852                                 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
853                                         p++;
854                                 }
855
856                                 if ( !p[ 0 ] ) {
857                                         /* error: we expected an AVA */
858                                         goto parsing_error;
859                                 }
860                         }
861
862                         /* oid */
863                         if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
864                                 state = B4OIDATTRTYPE;
865                                 break;
866                         }
867                         
868                         /* else must be alpha */
869                         if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
870                                 goto parsing_error;
871                         }
872                         
873                         /* LDAPv2 "oid." prefix */
874                         if ( LDAP_DN_LDAPV2( flags ) ) {
875                                 /*
876                                  * to be overly pedantic, we only accept
877                                  * "OID." or "oid."
878                                  */
879                                 if ( flags & LDAP_DN_PEDANTIC ) {
880                                         if ( !strncmp( p, "OID.", 4 )
881                                                 || !strncmp( p, "oid.", 4 ) ) {
882                                                 p += 4;
883                                                 state = B4OIDATTRTYPE;
884                                                 break;
885                                         }
886                                 } else {
887                                        if ( !strncasecmp( p, "oid.", 4 ) ) {
888                                                p += 4;
889                                                state = B4OIDATTRTYPE;
890                                                break;
891                                        }
892                                 }
893                         }
894
895                         state = B4STRINGATTRTYPE;
896                         break;
897                 
898                 case B4OIDATTRTYPE: {
899                         int             err = LDAP_SUCCESS;
900                         
901                         attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
902                                 LDAP_SCHEMA_SKIP);
903
904                         if ( err != LDAP_SUCCESS ) {
905                                 goto parsing_error;
906                         }
907                         attrType.bv_len = p - attrType.bv_val;
908
909                         attrTypeEncoding = LDAP_AVA_BINARY;
910
911                         state = B4AVAEQUALS;
912                         break;
913                 }
914
915                 case B4STRINGATTRTYPE: {
916                         const char      *startPos, *endPos = NULL;
917                         ber_len_t       len;
918                         
919                         /* 
920                          * the starting char has been found to be
921                          * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
922                          * FIXME: DCE attr types seem to have a more
923                          * restrictive syntax (no '-' ...) 
924                          */
925                         for ( startPos = p++; p[ 0 ]; p++ ) {
926                                 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
927                                         continue;
928                                 }
929
930                                 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
931                                         
932                                         /*
933                                          * RFC 2253 does not explicitly
934                                          * allow lang extensions to attribute 
935                                          * types in DNs ... 
936                                          */
937                                         if ( flags & LDAP_DN_PEDANTIC ) {
938                                                 goto parsing_error;
939                                         }
940
941                                         /*
942                                          * we trim ';' and following lang 
943                                          * and so from attribute types
944                                          */
945                                         endPos = p;
946                                         for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
947                                                         || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
948                                                 /* no op */ ;
949                                         }
950                                         break;
951                                 }
952                                 break;
953                         }
954
955                         len = ( endPos ? endPos : p ) - startPos;
956                         if ( len == 0 ) {
957                                 goto parsing_error;
958                         }
959                         
960                         attrTypeEncoding = LDAP_AVA_STRING;
961
962                         /*
963                          * here we need to decide whether to use it as is 
964                          * or turn it in OID form; as a consequence, we
965                          * need to decide whether to binary encode the value
966                          */
967                         
968                         state = B4AVAEQUALS;
969
970                         if ( flags & LDAP_DN_SKIP ) {
971                                 break;
972                         }
973
974                         attrType.bv_val = (char *)startPos;
975                         attrType.bv_len = len;
976
977                         break;
978                 }
979                                 
980                 case B4AVAEQUALS:
981                         /* spaces may not be allowed */
982                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
983                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
984                                         goto parsing_error;
985                                 }
986                         
987                                 /* trim spaces */
988                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
989                                         /* no op */
990                                 }
991                         }
992
993                         /* need equal sign */
994                         if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
995                                 goto parsing_error;
996                         }
997                         p++;
998
999                         /* spaces may not be allowed */
1000                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1001                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1002                                         goto parsing_error;
1003                                 }
1004
1005                                 /* trim spaces */
1006                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1007                                         /* no op */
1008                                 }
1009                         }
1010
1011                         /*
1012                          * octothorpe means a BER encoded value will follow
1013                          * FIXME: I don't think DCE will allow it
1014                          */
1015                         if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1016                                 p++;
1017                                 attrValueEncoding = LDAP_AVA_BINARY;
1018                                 state = B4BINARYVALUE;
1019                                 break;
1020                         }
1021
1022                         /* STRING value expected */
1023
1024                         /* 
1025                          * if we're pedantic, an attribute type in OID form
1026                          * SHOULD imply a BER encoded attribute value; we
1027                          * should at least issue a warning
1028                          */
1029                         if ( ( flags & LDAP_DN_PEDANTIC )
1030                                 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1031                                 /* OID attrType SHOULD use binary encoding */
1032                                 goto parsing_error;
1033                         }
1034
1035                         attrValueEncoding = LDAP_AVA_STRING;
1036
1037                         /* 
1038                          * LDAPv2 allows the attribute value to be quoted;
1039                          * also, IA5 values are expected, in principle
1040                          */
1041                         if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1042                                 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1043                                         p++;
1044                                         state = B4IA5VALUEQUOTED;
1045                                         break;
1046                                 }
1047
1048                                 if ( LDAP_DN_LDAPV2( flags ) ) {
1049                                         state = B4IA5VALUE;
1050                                         break;
1051                                 }
1052                         }
1053
1054                         /*
1055                          * here STRING means RFC 2253 string
1056                          * FIXME: what about DCE strings? 
1057                          */
1058                         if ( !p[ 0 ] ) {
1059                                 /* empty value */
1060                                 state = GOTAVA;
1061                         } else {
1062                                 state = B4STRINGVALUE;
1063                         }
1064                         break;
1065
1066                 case B4BINARYVALUE:
1067                         if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1068                                 goto parsing_error;
1069                         }
1070
1071                         state = GOTAVA;
1072                         break;
1073
1074                 case B4STRINGVALUE:
1075                         switch ( LDAP_DN_FORMAT( flags ) ) {
1076                         case LDAP_DN_FORMAT_LDAP:
1077                         case LDAP_DN_FORMAT_LDAPV3:
1078                                 if ( str2strval( p, &attrValue, &p, flags, 
1079                                                         &attrValueEncoding ) ) {
1080                                         goto parsing_error;
1081                                 }
1082                                 break;
1083
1084                         case LDAP_DN_FORMAT_DCE:
1085                                 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1086                                         goto parsing_error;
1087                                 }
1088                                 break;
1089
1090                         default:
1091                                 assert( 0 );
1092                         }
1093
1094                         state = GOTAVA;
1095                         break;
1096
1097                 case B4IA5VALUE:
1098                         if ( IA52strval( p, &attrValue, &p, flags ) ) {
1099                                 goto parsing_error;
1100                         }
1101
1102                         state = GOTAVA;
1103                         break;
1104                 
1105                 case B4IA5VALUEQUOTED:
1106
1107                         /* lead quote already stripped */
1108                         if ( quotedIA52strval( p, &attrValue, 
1109                                                 &p, flags ) ) {
1110                                 goto parsing_error;
1111                         }
1112
1113                         state = GOTAVA;
1114                         break;
1115
1116                 case GOTAVA: {
1117                         int     rdnsep = 0;
1118
1119                         if ( !( flags & LDAP_DN_SKIP ) ) {
1120                                 LDAPAVA *ava;
1121
1122                                 /*
1123                                  * we accept empty values
1124                                  */
1125                                 ava = ldapava_new( &attrType, &attrValue, 
1126                                                 attrValueEncoding );
1127                                 
1128                                 if ( ava == NULL ) {
1129                                         rc = LDAP_NO_MEMORY;
1130                                         goto parsing_error;
1131                                 }
1132                                 tmpRDN[navas++] = ava;
1133
1134                                 attrValue.bv_val = NULL;
1135                                 attrValue.bv_len = 0;
1136
1137                                 assert(navas < TMP_SLOTS);
1138                         }
1139                         
1140                         /* 
1141                          * if we got an AVA separator ('+', or ',' for DCE ) 
1142                          * we expect a new AVA for this RDN; otherwise 
1143                          * we add the RDN to the DN
1144                          */
1145                         switch ( LDAP_DN_FORMAT( flags ) ) {
1146                         case LDAP_DN_FORMAT_LDAP:
1147                         case LDAP_DN_FORMAT_LDAPV3:
1148                         case LDAP_DN_FORMAT_LDAPV2:
1149                                 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1150                                         rdnsep = 1;
1151                                 }
1152                                 break;
1153
1154                         case LDAP_DN_FORMAT_DCE:
1155                                 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1156                                         rdnsep = 1;
1157                                 }
1158                                 break;
1159                         }
1160
1161                         if ( rdnsep ) {
1162                                 /* 
1163                                  * the RDN is over, phew
1164                                  */
1165                                 *n = p;
1166                                 if ( !( flags & LDAP_DN_SKIP ) ) {
1167                                         newRDN = (LDAPRDN *)LDAP_MALLOC( sizeof(LDAPRDN)
1168                                                 + sizeof(LDAPAVA *) * (navas+1) );
1169                                         if ( newRDN == NULL ) {
1170                                                 rc = LDAP_NO_MEMORY;
1171                                                 goto parsing_error;
1172                                         } else {
1173                                                 int i;
1174
1175                                                 newRDN[0] = (LDAPAVA**)(newRDN+1);
1176
1177                                                 for (i=0; i<navas; i++)
1178                                                         newRDN[0][i] = tmpRDN[i];
1179                                                 newRDN[0][i] = NULL;
1180                                         }
1181
1182                                 }
1183                                 rc = LDAP_SUCCESS;
1184                                 goto return_result;
1185                         }
1186
1187                         /* they should have been used in an AVA */
1188                         attrType.bv_val = NULL;
1189                         attrValue.bv_val = NULL;
1190                         
1191                         p++;
1192                         state = B4AVA;
1193                         break;
1194                 }
1195
1196                 default:
1197                         assert( 0 );
1198                         goto parsing_error;
1199                 }
1200         }
1201         *n = p;
1202         
1203 parsing_error:;
1204         /* They are set to NULL after they're used in an AVA */
1205
1206         if ( attrValue.bv_val ) {
1207                 free( attrValue.bv_val );
1208         }
1209
1210         for (navas-- ; navas>=0; navas-- )
1211                 ldap_avafree( tmpRDN[navas] );
1212
1213 return_result:;
1214
1215         Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n", 
1216                         p - str, str, rc );
1217         if ( rdn ) {
1218                 *rdn = newRDN;
1219         }
1220         
1221         return( rc );
1222 }
1223
1224 /*
1225  * reads in a UTF-8 string value, unescaping stuff:
1226  * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1227  * '\' + HEXPAIR(p) -> unhex(p)
1228  */
1229 static int
1230 str2strval( const char *str, struct berval *val, const char **next, unsigned flags, unsigned *retFlags )
1231 {
1232         const char      *p, *startPos, *endPos = NULL;
1233         ber_len_t       len, escapes;
1234
1235         assert( str );
1236         assert( val );
1237         assert( next );
1238
1239         *next = NULL;
1240
1241         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1242                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1243                         p++;
1244                         if ( p[ 0 ] == '\0' ) {
1245                                 return( 1 );
1246                         }
1247                         if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
1248                                 escapes++;
1249                                 continue;
1250                         }
1251
1252                         if ( LDAP_DN_HEXPAIR( p ) ) {
1253                                 char c;
1254
1255                                 hexstr2bin( p, &c );
1256                                 escapes += 2;
1257
1258                                 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1259
1260                                         /*
1261                                          * we assume the string is UTF-8
1262                                          */
1263                                         *retFlags = LDAP_AVA_NONPRINTABLE;
1264                                 }
1265                                 p++;
1266
1267                                 continue;
1268                         }
1269
1270                         if ( LDAP_DN_PEDANTIC & flags ) {
1271                                 return( 1 );
1272                         }
1273                         /* 
1274                          * we do not allow escaping 
1275                          * of chars that don't need 
1276                          * to and do not belong to 
1277                          * HEXDIGITS
1278                          */
1279                         return( 1 );
1280
1281                 } else if (!LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) {
1282                         *retFlags = LDAP_AVA_NONPRINTABLE;
1283
1284                 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) 
1285                                 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1286                         break;
1287
1288                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1289                         /* 
1290                          * FIXME: maybe we can add 
1291                          * escapes if not pedantic?
1292                          */
1293                         return( 1 );
1294                 }
1295         }
1296
1297         /*
1298          * we do allow unescaped spaces at the end
1299          * of the value only in non-pedantic mode
1300          */
1301         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1302                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1303                 if ( flags & LDAP_DN_PEDANTIC ) {
1304                         return( 1 );
1305                 }
1306
1307                 /* strip trailing (unescaped) spaces */
1308                 for ( endPos = p - 1; 
1309                                 endPos > startPos + 1 && 
1310                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1311                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1312                                 endPos-- ) {
1313                         /* no op */
1314                 }
1315         }
1316
1317         *next = p;
1318         if ( flags & LDAP_DN_SKIP ) {
1319                 return( 0 );
1320         }
1321
1322         /*
1323          * FIXME: test memory?
1324          */
1325         len = ( endPos ? endPos : p ) - startPos - escapes;
1326         val->bv_len = len;
1327
1328         if ( escapes == 0 ) {
1329                 val->bv_val = LDAP_STRNDUP( startPos, len );
1330
1331         } else {
1332                 ber_len_t       s, d;
1333
1334                 val->bv_val = LDAP_MALLOC( len + 1 );
1335                 for ( s = 0, d = 0; d < len; ) {
1336                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1337                                 s++;
1338                                 if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
1339                                         val->bv_val[ d++ ] = 
1340                                                 startPos[ s++ ];
1341                                         
1342                                 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1343                                         char    c;
1344
1345                                         hexstr2bin( &startPos[ s ], &c );
1346                                         val->bv_val[ d++ ] = c;
1347                                         s += 2;
1348                                         
1349                                 } else {
1350                                         /* we should never get here */
1351                                         assert( 0 );
1352                                 }
1353
1354                         } else {
1355                                 val->bv_val[ d++ ] = startPos[ s++ ];
1356                         }
1357                 }
1358
1359                 val->bv_val[ d ] = '\0';
1360                 assert( d == len );
1361         }
1362
1363         return( 0 );
1364 }
1365
1366 static int
1367 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags )
1368 {
1369         const char      *p, *startPos, *endPos = NULL;
1370         ber_len_t       len, escapes;
1371
1372         assert( str );
1373         assert( val );
1374         assert( next );
1375
1376         *next = NULL;
1377         
1378         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1379                 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1380                         p++;
1381                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1382                                 escapes++;
1383
1384                         } else {
1385                                 return( 1 );
1386                         }
1387
1388                 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1389                         break;
1390                 }
1391
1392                 /*
1393                  * FIXME: can we accept anything else? I guess we need
1394                  * to stop if a value is not legal
1395                  */
1396         }
1397
1398         /* 
1399          * (unescaped) trailing spaces are trimmed must be silently ignored;
1400          * so we eat them
1401          */
1402         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1403                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1404                 if ( flags & LDAP_DN_PEDANTIC ) {
1405                         return( 1 );
1406                 }
1407
1408                 /* strip trailing (unescaped) spaces */
1409                 for ( endPos = p - 1; 
1410                                 endPos > startPos + 1 && 
1411                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1412                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1413                                 endPos-- ) {
1414                         /* no op */
1415                 }
1416         }
1417
1418         *next = p;
1419         if ( flags & LDAP_DN_SKIP ) {
1420                 return( 0 );
1421         }
1422         
1423         len = ( endPos ? endPos : p ) - startPos - escapes;
1424         val->bv_len = len;
1425         if ( escapes == 0 ){
1426                 val->bv_val = LDAP_STRNDUP( startPos, len );
1427
1428         } else {
1429                 ber_len_t       s, d;
1430
1431                 val->bv_val = LDAP_MALLOC( len + 1 );
1432                 for ( s = 0, d = 0; d < len; ) {
1433                         /*
1434                          * This point is reached only if escapes 
1435                          * are properly used, so all we need to
1436                          * do is eat them
1437                          */
1438                         if (  LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1439                                 s++;
1440
1441                         }
1442                         val->bv_val[ d++ ] = startPos[ s++ ];
1443                 }
1444                 val->bv_val[ d ] = '\0';
1445                 assert( strlen( val->bv_val ) == len );
1446         }
1447         
1448         return( 0 );
1449 }
1450
1451 static int
1452 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1453 {
1454         const char      *p, *startPos, *endPos = NULL;
1455         ber_len_t       len, escapes;
1456
1457         assert( str );
1458         assert( val );
1459         assert( next );
1460
1461         *next = NULL;
1462
1463         /*
1464          * LDAPv2 (RFC 1779)
1465          */
1466         
1467         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1468                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1469                         p++;
1470                         if ( p[ 0 ] == '\0' ) {
1471                                 return( 1 );
1472                         }
1473
1474                         if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1475                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1476                                 return( 1 );
1477                         }
1478                         escapes++;
1479
1480                 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1481                         break;
1482                 }
1483
1484                 /*
1485                  * FIXME: can we accept anything else? I guess we need
1486                  * to stop if a value is not legal
1487                  */
1488         }
1489
1490         /* strip trailing (unescaped) spaces */
1491         for ( endPos = p; 
1492                         endPos > startPos + 1 && 
1493                         LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1494                         !LDAP_DN_ESCAPE( endPos[ -2 ] );
1495                         endPos-- ) {
1496                 /* no op */
1497         }
1498
1499         *next = p;
1500         if ( flags & LDAP_DN_SKIP ) {
1501                 return( 0 );
1502         }
1503
1504         len = ( endPos ? endPos : p ) - startPos - escapes;
1505         val->bv_len = len;
1506         if ( escapes == 0 ) {
1507                 val->bv_val = LDAP_STRNDUP( startPos, len );
1508
1509         } else {
1510                 ber_len_t       s, d;
1511                 
1512                 val->bv_val = LDAP_MALLOC( len + 1 );
1513                 for ( s = 0, d = 0; d < len; ) {
1514                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1515                                 s++;
1516                         }
1517                         val->bv_val[ d++ ] = startPos[ s++ ];
1518                 }
1519                 val->bv_val[ d ] = '\0';
1520                 assert( strlen( val->bv_val ) == len );
1521         }
1522
1523         return( 0 );
1524 }
1525
1526 static int
1527 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1528 {
1529         const char      *p, *startPos, *endPos = NULL;
1530         ber_len_t       len;
1531         unsigned        escapes = 0;
1532
1533         assert( str );
1534         assert( val );
1535         assert( next );
1536
1537         *next = NULL;
1538
1539         /* initial quote already eaten */
1540         for ( startPos = p = str; p[ 0 ]; p++ ) {
1541                 /* 
1542                  * According to RFC 1779, the quoted value can
1543                  * contain escaped as well as unescaped special values;
1544                  * as a consequence we tolerate escaped values 
1545                  * (e.g. '"\,"' -> '\,') and escape unescaped specials
1546                  * (e.g. '","' -> '\,').
1547                  */
1548                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1549                         if ( p[ 1 ] == '\0' ) {
1550                                 return( 1 );
1551                         }
1552                         p++;
1553
1554                         if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1555                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1556                                 /*
1557                                  * do we allow to escape normal chars?
1558                                  * LDAPv2 does not allow any mechanism 
1559                                  * for escaping chars with '\' and hex 
1560                                  * pair
1561                                  */
1562                                 return( 1 );
1563                         }
1564                         escapes++;
1565
1566                 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1567                         endPos = p;
1568                         /* eat closing quotes */
1569                         p++;
1570                         break;
1571                 }
1572
1573                 /*
1574                  * FIXME: can we accept anything else? I guess we need
1575                  * to stop if a value is not legal
1576                  */
1577         }
1578
1579         if ( endPos == NULL ) {
1580                 return( 1 );
1581         }
1582
1583         /* Strip trailing (unescaped) spaces */
1584         for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1585                 /* no op */
1586         }
1587
1588         *next = p;
1589         if ( flags & LDAP_DN_SKIP ) {
1590                 return( 0 );
1591         }
1592
1593         len = endPos - startPos - escapes;
1594         assert( len >= 0 );
1595         val->bv_len = len;
1596         if ( escapes == 0 ) {
1597                 val->bv_val = LDAP_STRNDUP( startPos, len );
1598
1599         } else {
1600                 ber_len_t       s, d;
1601                 
1602                 val->bv_val = LDAP_MALLOC( len + 1 );
1603                 val->bv_len = len;
1604
1605                 for ( s = d = 0; d < len; ) {
1606                         if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1607                                 s++;
1608                         }
1609                         val->bv_val[ d++ ] = str[ s++ ];
1610                 }
1611                 val->bv_val[ d ] = '\0';
1612                 assert( strlen( val->bv_val ) == len );
1613         }
1614
1615         return( 0 );
1616 }
1617
1618 static int
1619 hexstr2bin( const char *str, char *c )
1620 {
1621         char    c1, c2;
1622
1623         assert( str );
1624         assert( c );
1625
1626         c1 = str[ 0 ];
1627         c2 = str[ 1 ];
1628
1629         if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1630                 *c = c1 - '0';
1631
1632         } else {
1633                 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1634                         *c = c1 - 'A' + 10;
1635                 } else {
1636                         assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1637                         *c = c1 - 'a' + 10;
1638                 }
1639         }
1640
1641         *c <<= 4;
1642
1643         if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1644                 *c += c2 - '0';
1645                 
1646         } else {
1647                 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1648                         *c += c2 - 'A' + 10;
1649                 } else {
1650                         assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1651                         *c += c2 - 'a' + 10;
1652                 }
1653         }
1654
1655         return( 0 );
1656 }
1657
1658 static int
1659 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags )
1660 {
1661         const char      *p, *startPos, *endPos = NULL;
1662         ber_len_t       len;
1663         ber_len_t       s, d;
1664
1665         assert( str );
1666         assert( val );
1667         assert( next );
1668
1669         *next = NULL;
1670
1671         for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1672                 switch ( LDAP_DN_FORMAT( flags ) ) {
1673                 case LDAP_DN_FORMAT_LDAPV3:
1674                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1675                                 goto end_of_value;
1676                         }
1677                         break;
1678
1679                 case LDAP_DN_FORMAT_LDAP:
1680                 case LDAP_DN_FORMAT_LDAPV2:
1681                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1682                                 goto end_of_value;
1683                         }
1684                         break;
1685
1686                 case LDAP_DN_FORMAT_DCE:
1687                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1688                                 goto end_of_value;
1689                         }
1690                         break;
1691                 }
1692
1693                 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1694                         if ( flags & LDAP_DN_PEDANTIC ) {
1695                                 return( 1 );
1696                         }
1697                         endPos = p;
1698
1699                         for ( ; p[ 0 ]; p++ ) {
1700                                 switch ( LDAP_DN_FORMAT( flags ) ) {
1701                                 case LDAP_DN_FORMAT_LDAPV3:
1702                                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1703                                                 goto end_of_value;
1704                                         }
1705                                         break;
1706
1707                                 case LDAP_DN_FORMAT_LDAP:
1708                                 case LDAP_DN_FORMAT_LDAPV2:
1709                                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1710                                                 goto end_of_value;
1711                                         }
1712                                         break;
1713
1714                                 case LDAP_DN_FORMAT_DCE:
1715                                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1716                                                 goto end_of_value;
1717                                         }
1718                                         break;
1719                                 }
1720                         }
1721                         break;
1722                 }
1723                 
1724                 if ( !LDAP_DN_HEXPAIR( p ) ) {
1725                         return( 1 );
1726                 }
1727         }
1728
1729 end_of_value:;
1730
1731         *next = p;
1732         if ( flags & LDAP_DN_SKIP ) {
1733                 return( 0 );
1734         }
1735
1736         len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1737         /* must be even! */
1738         assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1739
1740         val->bv_len = len;
1741         val->bv_val = LDAP_MALLOC( len + 1 );
1742         if ( val->bv_val == NULL ) {
1743                 return( LDAP_NO_MEMORY );
1744         }
1745
1746         for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1747                 char    c;
1748
1749                 hexstr2bin( &startPos[ s ], &c );
1750
1751                 val->bv_val[ d ] = c;
1752         }
1753
1754         val->bv_val[ d ] = '\0';
1755
1756         return( 0 );
1757 }
1758
1759 /*
1760  * convert a byte in a hexadecimal pair
1761  */
1762 static int
1763 byte2hexpair( const char *val, char *pair )
1764 {
1765         static const char       hexdig[] = "0123456789ABCDEF";
1766
1767         assert( val );
1768         assert( pair );
1769
1770         /* 
1771          * we assume the string has enough room for the hex encoding
1772          * of the value
1773          */
1774
1775         pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1776         pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1777         
1778         return( 0 );
1779 }
1780
1781 /*
1782  * convert a binary value in hexadecimal pairs
1783  */
1784 static int
1785 binval2hexstr( struct berval *val, char *str )
1786 {
1787         ber_len_t       s, d;
1788
1789         assert( val );
1790         assert( str );
1791
1792         if ( val->bv_len == 0 ) {
1793                 return( 0 );
1794         }
1795
1796         /* 
1797          * we assume the string has enough room for the hex encoding
1798          * of the value
1799          */
1800
1801         for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1802                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1803         }
1804         
1805         return( 0 );
1806 }
1807
1808 /*
1809  * Length of the string representation, accounting for escaped hex
1810  * of UTF-8 chars
1811  */
1812 static int
1813 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1814 {
1815         ber_len_t       l, cl = 1;
1816         char            *p;
1817         int             escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1818 #ifdef PRETTY_ESCAPE
1819         int             escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1820 #endif /* PRETTY_ESCAPE */
1821         
1822         assert( val );
1823         assert( len );
1824
1825         *len = 0;
1826         if ( val->bv_len == 0 ) {
1827                 return( 0 );
1828         }
1829
1830         for ( l = 0, p = val->bv_val; p < val->bv_val + val->bv_len; p += cl ) {
1831
1832                 /* 
1833                  * escape '%x00' 
1834                  */
1835                 if ( p[ 0 ] == '\0' ) {
1836                         cl = 1;
1837                         l += 3;
1838                         continue;
1839                 }
1840
1841                 cl = LDAP_UTF8_CHARLEN( p );
1842                 if ( cl == 0 ) {
1843                         /* illegal utf-8 char! */
1844                         return( -1 );
1845
1846                 } else if ( cl > 1 ) {
1847                         ber_len_t cnt;
1848
1849                         for ( cnt = 1; cnt < cl; cnt++ ) {
1850                                 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1851                                         return( -1 );
1852                                 }
1853                         }
1854                         l += escaped_byte_len * cl;
1855
1856                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1857                                 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1858                                 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1859 #ifdef PRETTY_ESCAPE
1860 #if 0
1861                         if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1862 #else
1863                         if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
1864 #endif
1865
1866                                 /* 
1867                                  * there might be some chars we want 
1868                                  * to escape in form of a couple 
1869                                  * of hexdigits for optimization purposes
1870                                  */
1871                                 l += 3;
1872
1873                         } else {
1874                                 l += escaped_ascii_len;
1875                         }
1876 #else /* ! PRETTY_ESCAPE */
1877                         l += 3;
1878 #endif /* ! PRETTY_ESCAPE */
1879
1880                 } else {
1881                         l++;
1882                 }
1883         }
1884
1885         *len = l;
1886
1887         return( 0 );
1888 }
1889
1890 /*
1891  * convert to string representation, escaping with hex the UTF-8 stuff;
1892  * assume the destination has enough room for escaping
1893  */
1894 static int
1895 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1896 {
1897         ber_len_t       s, d, end;
1898
1899         assert( val );
1900         assert( str );
1901         assert( len );
1902
1903         if ( val->bv_len == 0 ) {
1904                 *len = 0;
1905                 return( 0 );
1906         }
1907
1908         /* 
1909          * we assume the string has enough room for the hex encoding
1910          * of the value
1911          */
1912         for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1913                 ber_len_t       cl;
1914
1915                 /* 
1916                  * escape '%x00' 
1917                  */
1918                 if ( val->bv_val[ s ] == '\0' ) {
1919                         cl = 1;
1920                         str[ d++ ] = '\\';
1921                         str[ d++ ] = '0';
1922                         str[ d++ ] = '0';
1923                         s++;
1924                         continue;
1925                 }
1926                 
1927                 cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] );
1928                 
1929                 /* 
1930                  * there might be some chars we want to escape in form
1931                  * of a couple of hexdigits for optimization purposes
1932                  */
1933                 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) 
1934 #ifdef PRETTY_ESCAPE
1935 #if 0
1936                                 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] ) 
1937 #else
1938                                 || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] ) 
1939 #endif
1940 #else /* ! PRETTY_ESCAPE */
1941                                 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1942                                 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1943                                 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
1944
1945 #endif /* ! PRETTY_ESCAPE */
1946                                 ) {
1947                         for ( ; cl--; ) {
1948                                 str[ d++ ] = '\\';
1949                                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1950                                 s++;
1951                                 d += 2;
1952                         }
1953
1954                 } else if ( cl > 1 ) {
1955                         for ( ; cl--; ) {
1956                                 str[ d++ ] = val->bv_val[ s++ ];
1957                         }
1958
1959                 } else {
1960 #ifdef PRETTY_ESCAPE
1961                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1962                                         || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1963                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
1964                                 str[ d++ ] = '\\';
1965                                 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
1966                                         byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1967                                         s++;
1968                                         d += 2;
1969                                         continue;
1970                                 }
1971                         }
1972 #endif /* PRETTY_ESCAPE */
1973                         str[ d++ ] = val->bv_val[ s++ ];
1974                 }
1975         }
1976
1977         *len = d;
1978         
1979         return( 0 );
1980 }
1981
1982 /*
1983  * Length of the IA5 string representation (no UTF-8 allowed)
1984  */
1985 static int
1986 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
1987 {
1988         ber_len_t       l;
1989         char            *p;
1990
1991         assert( val );
1992         assert( len );
1993
1994         *len = 0;
1995         if ( val->bv_len == 0 ) {
1996                 return( 0 );
1997         }
1998
1999         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2000                 /*
2001                  * Turn value into a binary encoded BER
2002                  */
2003                 return( -1 );
2004
2005         } else {
2006                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2007                         if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2008                                         || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2009                                         || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2010                                 l += 2;
2011
2012                         } else {
2013                                 l++;
2014                         }
2015                 }
2016         }
2017
2018         *len = l;
2019         
2020         return( 0 );
2021 }
2022
2023 /*
2024  * convert to string representation (np UTF-8)
2025  * assume the destination has enough room for escaping
2026  */
2027 static int
2028 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2029 {
2030         ber_len_t       s, d, end;
2031
2032         assert( val );
2033         assert( str );
2034         assert( len );
2035
2036         if ( val->bv_len == 0 ) {
2037                 *len = 0;
2038                 return( 0 );
2039         }
2040
2041         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2042                 /*
2043                  * Turn value into a binary encoded BER
2044                  */
2045                 *len = 0;
2046                 return( -1 );
2047
2048         } else {
2049                 /* 
2050                  * we assume the string has enough room for the hex encoding
2051                  * of the value
2052                  */
2053
2054                 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2055                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2056                                         || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2057                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2058                                 str[ d++ ] = '\\';
2059                         }
2060                         str[ d++ ] = val->bv_val[ s++ ];
2061                 }
2062         }
2063
2064         *len = d;
2065         
2066         return( 0 );
2067 }
2068
2069 /*
2070  * Length of the (supposedly) DCE string representation, 
2071  * accounting for escaped hex of UTF-8 chars
2072  */
2073 static int
2074 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2075 {
2076         ber_len_t       l;
2077         char            *p;
2078
2079         assert( val );
2080         assert( len );
2081
2082         *len = 0;
2083         if ( val->bv_len == 0 ) {
2084                 return( 0 );
2085         }
2086
2087         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2088                 /* 
2089                  * FIXME: Turn the value into a binary encoded BER?
2090                  */
2091                 return( -1 );
2092                 
2093         } else {
2094                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2095                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2096                                 l += 2;
2097
2098                         } else {
2099                                 l++;
2100                         }
2101                 }
2102         }
2103
2104         *len = l;
2105
2106         return( 0 );
2107 }
2108
2109 /*
2110  * convert to (supposedly) DCE string representation, 
2111  * escaping with hex the UTF-8 stuff;
2112  * assume the destination has enough room for escaping
2113  */
2114 static int
2115 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2116 {
2117         ber_len_t       s, d;
2118
2119         assert( val );
2120         assert( str );
2121         assert( len );
2122
2123         if ( val->bv_len == 0 ) {
2124                 *len = 0;
2125                 return( 0 );
2126         }
2127
2128         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2129                 /*
2130                  * FIXME: Turn the value into a binary encoded BER?
2131                  */
2132                 *len = 0;
2133                 return( -1 );
2134                 
2135         } else {
2136
2137                 /* 
2138                  * we assume the string has enough room for the hex encoding
2139                  * of the value
2140                  */
2141
2142                 for ( s = 0, d = 0; s < val->bv_len; ) {
2143                         if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2144                                 str[ d++ ] = '\\';
2145                         }
2146                         str[ d++ ] = val->bv_val[ s++ ];
2147                 }
2148         }
2149
2150         *len = d;
2151         
2152         return( 0 );
2153 }
2154
2155 /*
2156  * Length of the (supposedly) AD canonical string representation, 
2157  * accounting for escaped hex of UTF-8 chars
2158  */
2159 static int
2160 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2161 {
2162         ber_len_t       l;
2163         char            *p;
2164
2165         assert( val );
2166         assert( len );
2167
2168         *len = 0;
2169         if ( val->bv_len == 0 ) {
2170                 return( 0 );
2171         }
2172
2173         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2174                 /* 
2175                  * FIXME: Turn the value into a binary encoded BER?
2176                  */
2177                 return( -1 );
2178                 
2179         } else {
2180                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2181                         if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2182                                 l += 2;
2183
2184                         } else {
2185                                 l++;
2186                         }
2187                 }
2188         }
2189
2190         *len = l;
2191         
2192         return( 0 );
2193 }
2194
2195 /*
2196  * convert to (supposedly) AD string representation, 
2197  * escaping with hex the UTF-8 stuff;
2198  * assume the destination has enough room for escaping
2199  */
2200 static int
2201 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2202 {
2203         ber_len_t       s, d;
2204
2205         assert( val );
2206         assert( str );
2207         assert( len );
2208
2209         if ( val->bv_len == 0 ) {
2210                 *len = 0;
2211                 return( 0 );
2212         }
2213
2214         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2215                 /*
2216                  * FIXME: Turn the value into a binary encoded BER?
2217                  */
2218                 *len = 0;
2219                 return( -1 );
2220                 
2221         } else {
2222
2223                 /* 
2224                  * we assume the string has enough room for the hex encoding
2225                  * of the value
2226                  */
2227
2228                 for ( s = 0, d = 0; s < val->bv_len; ) {
2229                         if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2230                                 str[ d++ ] = '\\';
2231                         }
2232                         str[ d++ ] = val->bv_val[ s++ ];
2233                 }
2234         }
2235
2236         *len = d;
2237         
2238         return( 0 );
2239 }
2240
2241 /*
2242  * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2243  * the first part of the AD representation of the DN is written in DNS
2244  * form, i.e. dot separated domain name components (as suggested 
2245  * by Luke Howard, http://www.padl.com/~lukeh)
2246  */
2247 static int
2248 dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN )
2249 {
2250         int             i;
2251         int             domain = 0, first = 1;
2252         ber_len_t       l = 1; /* we move the null also */
2253         char            *str;
2254
2255         /* we are guaranteed there's enough memory in str */
2256
2257         /* sanity */
2258         assert( dn );
2259         assert( bv );
2260         assert( iRDN );
2261         assert( *iRDN >= 0 );
2262
2263         str = bv->bv_val + pos;
2264
2265         for ( i = *iRDN; i >= 0; i-- ) {
2266                 LDAPRDN         *rdn;
2267                 LDAPAVA         *ava;
2268
2269                 assert( dn[ 0 ][ i ] );
2270                 rdn = dn[ 0 ][ i ];
2271
2272                 assert( rdn[ 0 ][ 0 ] );
2273                 ava = rdn[ 0 ][ 0 ];
2274
2275                 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2276                         break;
2277                 }
2278
2279                 domain = 1;
2280                 
2281                 if ( first ) {
2282                         first = 0;
2283                         AC_MEMCPY( str, ava->la_value.bv_val, 
2284                                         ava->la_value.bv_len + 1);
2285                         l += ava->la_value.bv_len;
2286
2287                 } else {
2288                         AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l);
2289                         AC_MEMCPY( str, ava->la_value.bv_val, 
2290                                         ava->la_value.bv_len );
2291                         str[ ava->la_value.bv_len ] = '.';
2292                         l += ava->la_value.bv_len + 1;
2293                 }
2294         }
2295
2296         *iRDN = i;
2297         bv->bv_len = pos + l - 1;
2298
2299         return( domain );
2300 }
2301
2302 static int
2303 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2304          int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2305 {
2306         int             iAVA;
2307         ber_len_t       l = 0;
2308
2309         *len = 0;
2310
2311         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2312                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2313
2314                 /* len(type) + '=' + '+' | ',' */
2315                 l += ava->la_attr.bv_len + 2;
2316
2317                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2318                         /* octothorpe + twice the length */
2319                         l += 1 + 2 * ava->la_value.bv_len;
2320
2321                 } else {
2322                         ber_len_t       vl;
2323                         unsigned        f = flags | ava->la_flags;
2324                         
2325                         if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2326                                 return( -1 );
2327                         }
2328                         l += vl;
2329                 }
2330         }
2331         
2332         *len = l;
2333         
2334         return( 0 );
2335 }
2336
2337 static int
2338 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2339         int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2340 {
2341         int             iAVA;
2342         ber_len_t       l = 0;
2343
2344         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2345                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2346
2347                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2348                                 ava->la_attr.bv_len );
2349                 l += ava->la_attr.bv_len;
2350
2351                 str[ l++ ] = '=';
2352
2353                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2354                         str[ l++ ] = '#';
2355                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2356                                 return( -1 );
2357                         }
2358                         l += 2 * ava->la_value.bv_len;
2359
2360                 } else {
2361                         ber_len_t       vl;
2362                         unsigned        f = flags | ava->la_flags;
2363
2364                         if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2365                                 return( -1 );
2366                         }
2367                         l += vl;
2368                 }
2369                 str[ l++ ] = ( rdn[ 0 ][ iAVA + 1 ] ? '+' : ',' );
2370         }
2371
2372         *len = l;
2373
2374         return( 0 );
2375 }
2376
2377 static int
2378 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2379 {
2380         int             iAVA;
2381         ber_len_t       l = 0;
2382
2383         *len = 0;
2384
2385         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2386                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2387
2388                 /* len(type) + '=' + ',' | '/' */
2389                 l += ava->la_attr.bv_len + 2;
2390
2391                 switch ( ava->la_flags ) {
2392                 case LDAP_AVA_BINARY:
2393                         /* octothorpe + twice the length */
2394                         l += 1 + 2 * ava->la_value.bv_len;
2395                         break;
2396
2397                 case LDAP_AVA_STRING: {
2398                         ber_len_t       vl;
2399                         unsigned        f = flags | ava->la_flags;
2400                         
2401                         if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2402                                 return( -1 );
2403                         }
2404                         l += vl;
2405                         break;
2406                 }
2407
2408                 default:
2409                         return( -1 );
2410                 }
2411         }
2412         
2413         *len = l;
2414         
2415         return( 0 );
2416 }
2417
2418 static int
2419 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2420 {
2421         int             iAVA;
2422         ber_len_t       l = 0;
2423
2424         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2425                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2426
2427                 if ( first ) {
2428                         first = 0;
2429                 } else {
2430                         str[ l++ ] = ( iAVA ? ',' : '/' );
2431                 }
2432
2433                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2434                                 ava->la_attr.bv_len );
2435                 l += ava->la_attr.bv_len;
2436
2437                 str[ l++ ] = '=';
2438
2439                 switch ( ava->la_flags ) {
2440                         case LDAP_AVA_BINARY:
2441                         str[ l++ ] = '#';
2442                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2443                                 return( -1 );
2444                         }
2445                         l += 2 * ava->la_value.bv_len;
2446                         break;
2447
2448                 case LDAP_AVA_STRING: {
2449                         ber_len_t       vl;
2450                         unsigned        f = flags | ava->la_flags;
2451
2452                         if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2453                                 return( -1 );
2454                         }
2455                         l += vl;
2456                         break;
2457                 }
2458                                       
2459                 default:
2460                         return( -1 );
2461                 }
2462         }
2463
2464         *len = l;
2465
2466         return( 0 );
2467 }
2468
2469 static int
2470 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2471 {
2472         int             iAVA;
2473         ber_len_t       l = 0;
2474
2475         assert( rdn );
2476         assert( len );
2477
2478         *len = 0;
2479
2480         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2481                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2482
2483                 /* ' + ' | ', ' */
2484                 l += ( rdn[ 0 ][ iAVA + 1 ] ? 3 : 2 );
2485
2486                 /* FIXME: are binary values allowed in UFN? */
2487                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2488                         /* octothorpe + twice the value */
2489                         l += 1 + 2 * ava->la_value.bv_len;
2490
2491                 } else {
2492                         ber_len_t       vl;
2493                         unsigned        f = flags | ava->la_flags;
2494
2495                         if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2496                                 return( -1 );
2497                         }
2498                         l += vl;
2499                 }
2500         }
2501         
2502         *len = l;
2503         
2504         return( 0 );
2505 }
2506
2507 static int
2508 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2509 {
2510         int             iAVA;
2511         ber_len_t       l = 0;
2512
2513         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2514                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2515
2516                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2517                         str[ l++ ] = '#';
2518                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2519                                 return( -1 );
2520                         }
2521                         l += 2 * ava->la_value.bv_len;
2522                         
2523                 } else {
2524                         ber_len_t       vl;
2525                         unsigned        f = flags | ava->la_flags;
2526                         
2527                         if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2528                                 return( -1 );
2529                         }
2530                         l += vl;
2531                 }
2532
2533                 if ( rdn[ 0 ][ iAVA + 1 ]) {
2534                         AC_MEMCPY( &str[ l ], " + ", 3 );
2535                         l += 3;
2536
2537                 } else {
2538                         AC_MEMCPY( &str[ l ], ", ", 2 );
2539                         l += 2;
2540                 }
2541         }
2542
2543         *len = l;
2544
2545         return( 0 );
2546 }
2547
2548 static int
2549 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2550 {
2551         int             iAVA;
2552         ber_len_t       l = 0;
2553
2554         assert( rdn );
2555         assert( len );
2556
2557         *len = 0;
2558
2559         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2560                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2561
2562                 /* ',' | '/' */
2563                 l++;
2564
2565                 /* FIXME: are binary values allowed in UFN? */
2566                 switch ( ava->la_flags ) {
2567                 case LDAP_AVA_BINARY:
2568                         /* octothorpe + twice the value */
2569                         l += 1 + 2 * ava->la_value.bv_len;
2570                         break;
2571
2572                 case LDAP_AVA_STRING: {
2573                         ber_len_t       vl;
2574                         unsigned        f = flags | ava->la_flags;
2575
2576                         if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2577                                 return( -1 );
2578                         }
2579                         l += vl;
2580                         break;
2581                 }
2582
2583                 default:
2584                         return( -1 );
2585                 }
2586         }
2587         
2588         *len = l;
2589         
2590         return( 0 );
2591 }
2592
2593 static int
2594 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2595 {
2596         int             iAVA;
2597         ber_len_t       l = 0;
2598
2599         for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2600                 LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
2601
2602                 if ( first ) {
2603                         first = 0;
2604                 } else {
2605                         str[ l++ ] = ( iAVA ? ',' : '/' );
2606                 }
2607
2608                 switch ( ava->la_flags ) {
2609                 case LDAP_AVA_BINARY:
2610                         str[ l++ ] = '#';
2611                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2612                                 return( -1 );
2613                         }
2614                         l += 2 * ava->la_value.bv_len;
2615                         break;
2616                         
2617                 case LDAP_AVA_STRING: {
2618                         ber_len_t       vl;
2619                         unsigned        f = flags | ava->la_flags;
2620                         
2621                         if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2622                                 return( -1 );
2623                         }
2624                         l += vl;
2625                         break;
2626                 }
2627
2628                 default:
2629                         return( -1 );
2630                 }
2631         }
2632
2633         *len = l;
2634
2635         return( 0 );
2636 }
2637
2638 /*
2639  * ldap_rdn2str
2640  *
2641  * Returns in str a string representation of rdn based on flags.
2642  * There is some duplication of code between this and ldap_dn2str;
2643  * this is wanted to reduce the allocation of temporary buffers.
2644  */
2645 int
2646 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2647 {
2648         struct berval bv;
2649         int rc;
2650
2651         assert( str );
2652
2653         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2654                 return LDAP_PARAM_ERROR;
2655         }
2656
2657         rc = ldap_rdn2bv( rdn, &bv, flags );
2658         *str = bv.bv_val;
2659         return rc;
2660 }
2661
2662 int
2663 ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags )
2664 {
2665         int             rc, back;
2666         ber_len_t       l;
2667         
2668         assert( bv );
2669
2670         bv->bv_len = 0;
2671         bv->bv_val = NULL;
2672
2673         if ( rdn == NULL ) {
2674                 bv->bv_val = LDAP_STRDUP( "" );
2675                 return( LDAP_SUCCESS );
2676         }
2677
2678         /*
2679          * This routine wastes "back" bytes at the end of the string
2680          */
2681
2682         switch ( LDAP_DN_FORMAT( flags ) ) {
2683         case LDAP_DN_FORMAT_LDAPV3:
2684                 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2685                         return LDAP_DECODING_ERROR;
2686                 }
2687                 break;
2688
2689         case LDAP_DN_FORMAT_LDAPV2:
2690                 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2691                         return LDAP_DECODING_ERROR;
2692                 }
2693                 break;
2694
2695         case LDAP_DN_FORMAT_UFN:
2696                 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2697                         return LDAP_DECODING_ERROR;
2698                 }
2699                 break;
2700
2701         case LDAP_DN_FORMAT_DCE:
2702                 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2703                         return LDAP_DECODING_ERROR;
2704                 }
2705                 break;
2706
2707         case LDAP_DN_FORMAT_AD_CANONICAL:
2708                 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2709                         return LDAP_DECODING_ERROR;
2710                 }
2711                 break;
2712
2713         default:
2714                 return( LDAP_PARAM_ERROR );
2715         }
2716
2717         bv->bv_val = LDAP_MALLOC( l + 1 );
2718
2719         switch ( LDAP_DN_FORMAT( flags ) ) {
2720         case LDAP_DN_FORMAT_LDAPV3:
2721                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2722                 back = 1;
2723                 break;
2724
2725         case LDAP_DN_FORMAT_LDAPV2:
2726                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2727                 back = 1;
2728                 break;
2729
2730         case LDAP_DN_FORMAT_UFN:
2731                 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2732                 back = 2;
2733                 break;
2734
2735         case LDAP_DN_FORMAT_DCE:
2736                 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2737                 back = 0;
2738                 break;
2739
2740         case LDAP_DN_FORMAT_AD_CANONICAL:
2741                 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2742                 back = 0;
2743                 break;
2744
2745         default:
2746                 /* need at least one of the previous */
2747                 return LDAP_PARAM_ERROR;
2748         }
2749
2750         if ( rc ) {
2751                 ldap_memfree( bv->bv_val );
2752                 return rc;
2753         }
2754
2755         bv->bv_len = l - back;
2756         bv->bv_val[ bv->bv_len ] = '\0';
2757
2758         return LDAP_SUCCESS;
2759 }
2760
2761 /*
2762  * Very bulk implementation; many optimizations can be performed
2763  *   - a NULL dn results in an empty string ""
2764  * 
2765  * FIXME: doubts
2766  *   a) what do we do if a UTF-8 string must be converted in LDAPv2?
2767  *      we must encode it in binary form ('#' + HEXPAIRs)
2768  *   b) does DCE/AD support UTF-8?
2769  *      no clue; don't think so.
2770  *   c) what do we do when binary values must be converted in UTF/DCE/AD?
2771  *      use binary encoded BER
2772  */ 
2773 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2774 {
2775         struct berval bv;
2776         int rc;
2777
2778         assert( str );
2779
2780         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2781                 return LDAP_PARAM_ERROR;
2782         }
2783         
2784         rc = ldap_dn2bv( dn, &bv, flags );
2785         *str = bv.bv_val;
2786         return rc;
2787 }
2788
2789 int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
2790 {
2791         int             iRDN;
2792         int             rc = LDAP_ENCODING_ERROR;
2793         ber_len_t       len, l;
2794
2795         /* stringifying helpers for LDAPv3/LDAPv2 */
2796         int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2797         int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2798
2799         assert( bv );
2800
2801         bv->bv_len = 0;
2802         bv->bv_val = NULL;
2803
2804         Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" );
2805
2806         /* 
2807          * a null dn means an empty dn string 
2808          * FIXME: better raise an error?
2809          */
2810         if ( dn == NULL ) {
2811                 bv->bv_val = LDAP_STRDUP( "" );
2812                 return( LDAP_SUCCESS );
2813         }
2814
2815         switch ( LDAP_DN_FORMAT( flags ) ) {
2816         case LDAP_DN_FORMAT_LDAPV3:
2817                 sv2l = strval2strlen;
2818                 sv2s = strval2str;
2819                 goto got_funcs;
2820
2821         case LDAP_DN_FORMAT_LDAPV2:
2822                 sv2l = strval2IA5strlen;
2823                 sv2s = strval2IA5str;
2824 got_funcs:
2825                 
2826                 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2827                         ber_len_t       rdnl;
2828                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2829                         
2830                         if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2831                                 goto return_results;
2832                         }
2833
2834                         len += rdnl;
2835                 }
2836
2837                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2838                         rc = LDAP_NO_MEMORY;
2839                         break;
2840                 }
2841
2842                 for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2843                         ber_len_t       rdnl;
2844                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2845                         
2846                         if ( rdn2str( rdn, &bv->bv_val[ l ], flags, 
2847                                         &rdnl, sv2s ) ) {
2848                                 LDAP_FREE( bv->bv_val );
2849                                 bv->bv_val = NULL;
2850                                 goto return_results;
2851                         }
2852                         l += rdnl;
2853                 }
2854
2855                 assert( l == len );
2856
2857                 /* 
2858                  * trim the last ',' (the allocated memory 
2859                  * is one byte longer than required)
2860                  */
2861                 bv->bv_len = len - 1;
2862                 bv->bv_val[ bv->bv_len ] = '\0';
2863
2864                 rc = LDAP_SUCCESS;
2865                 break;
2866
2867         case LDAP_DN_FORMAT_UFN: {
2868
2869                 /*
2870                  * FIXME: quoting from RFC 1781:
2871                  *
2872    To take a distinguished name, and generate a name of this format with
2873    attribute types omitted, the following steps are followed.
2874
2875     1.  If the first attribute is of type CommonName, the type may be
2876         omitted.
2877
2878     2.  If the last attribute is of type Country, the type may be
2879         omitted.
2880
2881     3.  If the last attribute is of type Country, the last
2882         Organisation attribute may have the type omitted.
2883
2884     4.  All attributes of type OrganisationalUnit may have the type
2885         omitted, unless they are after an Organisation attribute or
2886         the first attribute is of type OrganisationalUnit.
2887
2888          * this should be the pedantic implementation.
2889                  *
2890                  * Here the standard implementation reflects
2891                  * the one historically provided by OpenLDAP
2892                  * (and UMIch, I presume), with the variant
2893                  * of spaces and plusses (' + ') separating 
2894                  * rdn components.
2895                  * 
2896                  * A non-standard but nice implementation could
2897                  * be to turn the  final "dc" attributes into a 
2898                  * dot-separated domain.
2899                  *
2900                  * Other improvements could involve the use of
2901                  * friendly country names and so.
2902                  */
2903 #ifdef DC_IN_UFN
2904                 int     leftmost_dc = -1;
2905                 int     last_iRDN = -1;
2906 #endif /* DC_IN_UFN */
2907
2908                 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2909                         ber_len_t       rdnl;
2910                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2911                         
2912                         if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2913                                 goto return_results;
2914                         }
2915                         len += rdnl;
2916
2917 #ifdef DC_IN_UFN
2918                         if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2919                                 if ( leftmost_dc == -1 ) {
2920                                         leftmost_dc = iRDN;
2921                                 }
2922                         } else {
2923                                 leftmost_dc = -1;
2924                         }
2925 #endif /* DC_IN_UFN */
2926                 }
2927
2928                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2929                         rc = LDAP_NO_MEMORY;
2930                         break;
2931                 }
2932
2933 #ifdef DC_IN_UFN
2934                 if ( leftmost_dc == -1 ) {
2935 #endif /* DC_IN_UFN */
2936                         for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2937                                 ber_len_t       vl;
2938                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2939                         
2940                                 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], 
2941                                                 flags, &vl ) ) {
2942                                         LDAP_FREE( bv->bv_val );
2943                                         bv->bv_val = NULL;
2944                                         goto return_results;
2945                                 }
2946                                 l += vl;
2947                         }
2948
2949                         /* 
2950                          * trim the last ', ' (the allocated memory 
2951                          * is two bytes longer than required)
2952                          */
2953                         bv->bv_len = len - 2;
2954                         bv->bv_val[ bv->bv_len ] = '\0';
2955 #ifdef DC_IN_UFN
2956                 } else {
2957                         last_iRDN = iRDN - 1;
2958
2959                         for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2960                                 ber_len_t       vl;
2961                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2962                         
2963                                 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], 
2964                                                 flags, &vl ) ) {
2965                                         LDAP_FREE( bv->bv_val );
2966                                         bv->bv_val = NULL;
2967                                         goto return_results;
2968                                 }
2969                                 l += vl;
2970                         }
2971
2972                         if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
2973                                 LDAP_FREE( bv->bv_val );
2974                                 bv->bv_val = NULL;
2975                                 goto return_results;
2976                         }
2977
2978                         /* the string is correctly terminated by dn2domain */
2979                 }
2980 #endif /* DC_IN_UFN */
2981                 
2982                 rc = LDAP_SUCCESS;
2983                 break;
2984         }
2985
2986         case LDAP_DN_FORMAT_DCE:
2987
2988                 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2989                         ber_len_t       rdnl;
2990                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
2991                         
2992                         if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
2993                                 goto return_results;
2994                         }
2995
2996                         len += rdnl;
2997                 }
2998
2999                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3000                         rc = LDAP_NO_MEMORY;
3001                         break;
3002                 }
3003
3004                 for ( l = 0; iRDN--; ) {
3005                         ber_len_t       rdnl;
3006                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3007                         
3008                         if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags, 
3009                                         &rdnl, 0 ) ) {
3010                                 LDAP_FREE( bv->bv_val );
3011                                 bv->bv_val = NULL;
3012                                 goto return_results;
3013                         }
3014                         l += rdnl;
3015                 }
3016
3017                 assert( l == len );
3018
3019                 bv->bv_len = len;
3020                 bv->bv_val[ bv->bv_len ] = '\0';
3021
3022                 rc = LDAP_SUCCESS;
3023                 break;
3024
3025         case LDAP_DN_FORMAT_AD_CANONICAL: {
3026                 
3027                 /*
3028                  * Sort of UFN for DCE DNs: a slash ('/') separated
3029                  * global->local DN with no types; strictly speaking,
3030                  * the naming context should be a domain, which is
3031                  * written in DNS-style, e.g. dot-deparated.
3032                  * 
3033                  * Example:
3034                  * 
3035                  *      "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3036                  *
3037                  * will read
3038                  * 
3039                  *      "microsoft.com/People/Bill,Gates"
3040                  */ 
3041                 for ( iRDN = 0, len = -1; dn[ 0 ][ iRDN ]; iRDN++ ) {
3042                         ber_len_t       rdnl;
3043                         LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3044                         
3045                         if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3046                                 goto return_results;
3047                         }
3048
3049                         len += rdnl;
3050                 }
3051
3052                 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3053                         rc = LDAP_NO_MEMORY;
3054                         break;
3055                 }
3056
3057                 iRDN--;
3058                 if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) ) {
3059                         for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3060                                 ber_len_t       rdnl;
3061                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3062                         
3063                                 if ( rdn2ADstr( rdn, &bv->bv_val[ l ], 
3064                                                 flags, &rdnl, 0 ) ) {
3065                                         LDAP_FREE( bv->bv_val );
3066                                         bv->bv_val = NULL;
3067                                         goto return_results;
3068                                 }
3069                                 l += rdnl;
3070                         }
3071
3072                 } else {
3073                         int             first = 1;
3074
3075                         /*
3076                          * Strictly speaking, AD canonical requires
3077                          * a DN to be in the form "..., dc=smtg",
3078                          * i.e. terminated by a domain component
3079                          */
3080                         if ( flags & LDAP_DN_PEDANTIC ) {
3081                                 LDAP_FREE( bv->bv_val );
3082                                 bv->bv_val = NULL;
3083                                 rc = LDAP_ENCODING_ERROR;
3084                                 break;
3085                         }
3086
3087                         for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3088                                 ber_len_t       rdnl;
3089                                 LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
3090                         
3091                                 if ( rdn2ADstr( rdn, &bv->bv_val[ l ], 
3092                                                 flags, &rdnl, first ) ) {
3093                                         LDAP_FREE( bv->bv_val );
3094                                         bv->bv_val = NULL;
3095                                         goto return_results;
3096                                 }
3097                                 if ( first ) {
3098                                         first = 0;
3099                                 }
3100                                 l += rdnl;
3101                         }
3102                 }
3103
3104                 bv->bv_len = len;
3105                 bv->bv_val[ bv->bv_len ] = '\0';
3106
3107                 rc = LDAP_SUCCESS;
3108                 break;
3109         }
3110
3111         default:
3112                 return LDAP_PARAM_ERROR;
3113         }
3114
3115         Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n",
3116                 bv->bv_val, flags, rc );
3117 return_results:;
3118         return( rc );
3119 }
3120