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