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