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