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