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