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