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