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