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