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