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