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