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