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