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