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