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