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