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