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