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