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