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