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