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