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