]> git.sur5r.net Git - openldap/blob - libraries/libldap/getdn.c
strval2strlen fix from HEAD
[openldap] / libraries / libldap / getdn.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2006 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* Portions Copyright (c) 1994 Regents of the University of Michigan.
16  * All rights reserved.
17  */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22
23 #include <ac/stdlib.h>
24 #include <ac/socket.h>
25 #include <ac/string.h>
26 #include <ac/time.h>
27
28 #include "ldap-int.h"
29 #include "ldap_schema.h"
30
31 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
32  * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
33 #define DC_IN_UFN
34
35 /* parsing/printing routines */
36 static int str2strval( const char *str, ber_len_t stoplen, struct berval *val, 
37                 const char **next, unsigned flags, int *retFlags, void *ctx );
38 static int DCE2strval( const char *str, struct berval *val, 
39                 const char **next, unsigned flags, void *ctx );
40 static int IA52strval( const char *str, struct berval *val, 
41                 const char **next, unsigned flags, void *ctx );
42 static int quotedIA52strval( const char *str, struct berval *val, 
43                 const char **next, unsigned flags, void *ctx );
44 static int hexstr2binval( const char *str, struct berval *val, 
45                 const char **next, unsigned flags, void *ctx );
46 static int hexstr2bin( const char *str, char *c );
47 static int byte2hexpair( const char *val, char *pair );
48 static int binval2hexstr( struct berval *val, char *str );
49 static int strval2strlen( struct berval *val, unsigned flags, 
50                 ber_len_t *len );
51 static int strval2str( struct berval *val, char *str, unsigned flags, 
52                 ber_len_t *len );
53 static int strval2IA5strlen( struct berval *val, unsigned flags,
54                 ber_len_t *len );
55 static int strval2IA5str( struct berval *val, char *str, unsigned flags, 
56                 ber_len_t *len );
57 static int strval2DCEstrlen( struct berval *val, unsigned flags,
58                 ber_len_t *len );
59 static int strval2DCEstr( struct berval *val, char *str, unsigned flags, 
60                 ber_len_t *len );
61 static int strval2ADstrlen( struct berval *val, unsigned flags,
62                 ber_len_t *len );
63 static int strval2ADstr( struct berval *val, char *str, unsigned flags, 
64                 ber_len_t *len );
65 static int dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN );
66
67 /* AVA helpers */
68 static LDAPAVA * ldapava_new(
69         const struct berval *attr, const struct berval *val, unsigned flags, void *ctx );
70
71 /* Higher level helpers */
72 static int rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
73                 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
74 static int rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
75                 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
76 static int rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len  );
77 static int rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len );
78 static int rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
79 static int rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flag, ber_len_t *len, int first );
80 static int rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
81 static int rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first );
82
83 /*
84  * RFC 1823 ldap_get_dn
85  */
86 char *
87 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
88 {
89         char            *dn;
90         BerElement      tmp;
91
92         Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
93
94         assert( ld != NULL );
95         assert( LDAP_VALID(ld) );
96         assert( entry != NULL );
97
98         tmp = *entry->lm_ber;   /* struct copy */
99         if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
100                 ld->ld_errno = LDAP_DECODING_ERROR;
101                 return( NULL );
102         }
103
104         return( dn );
105 }
106
107 int
108 ldap_get_dn_ber( LDAP *ld, LDAPMessage *entry, BerElement **berout,
109         BerValue *dn )
110 {
111         BerElement      tmp, *ber;
112         ber_len_t       len = 0;
113         int rc = LDAP_SUCCESS;
114
115         Debug( LDAP_DEBUG_TRACE, "ldap_get_dn_ber\n", 0, 0, 0 );
116
117         assert( ld != NULL );
118         assert( LDAP_VALID(ld) );
119         assert( entry != NULL );
120         assert( dn != NULL );
121
122         dn->bv_val = NULL;
123         dn->bv_len = 0;
124
125         if ( berout ) {
126                 *berout = NULL;
127                 ber = ldap_alloc_ber_with_options( ld );
128                 if( ber == NULL ) {
129                         return LDAP_NO_MEMORY;
130                 }
131                 *berout = ber;
132         } else {
133                 ber = &tmp;
134         }
135                 
136         *ber = *entry->lm_ber;  /* struct copy */
137         if ( ber_scanf( ber, "{ml{" /*}*/, dn, &len ) == LBER_ERROR ) {
138                 rc = ld->ld_errno = LDAP_DECODING_ERROR;
139         }
140         if ( rc == LDAP_SUCCESS ) {
141                 /* set the length to avoid overrun */
142                 rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len );
143                 if( rc != LBER_OPT_SUCCESS ) {
144                         rc = ld->ld_errno = LDAP_LOCAL_ERROR;
145                 }
146         }
147         if ( rc != LDAP_SUCCESS && berout ) {
148                 ber_free( ber, 0 );
149                 *berout = NULL;
150         }
151         return rc;
152 }
153
154 /*
155  * RFC 1823 ldap_dn2ufn
156  */
157 char *
158 ldap_dn2ufn( LDAP_CONST char *dn )
159 {
160         char    *out = NULL;
161
162         Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
163
164         ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
165                 &out, LDAP_DN_FORMAT_UFN );
166         
167         return( out );
168 }
169
170 /*
171  * RFC 1823 ldap_explode_dn
172  */
173 char **
174 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
175 {
176         LDAPDN  tmpDN;
177         char    **values = NULL;
178         int     iRDN;
179         unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
180         
181         Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
182
183         if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) 
184                         != LDAP_SUCCESS ) {
185                 return NULL;
186         }
187
188         if( tmpDN == NULL ) {
189                 values = LDAP_MALLOC( sizeof( char * ) );
190                 if( values == NULL ) return NULL;
191
192                 values[0] = NULL;
193                 return values;
194         }
195
196         for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ );
197
198         values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
199         if ( values == NULL ) {
200                 ldap_dnfree( tmpDN );
201                 return NULL;
202         }
203
204         for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
205                 ldap_rdn2str( tmpDN[ iRDN ], &values[ iRDN ], flag );
206         }
207         ldap_dnfree( tmpDN );
208         values[ iRDN ] = NULL;
209
210         return values;
211 }
212
213 char **
214 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
215 {
216         LDAPRDN         tmpRDN;
217         char            **values = NULL;
218         const char      *p;
219         int             iAVA;
220         
221         Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
222
223         /*
224          * we only parse the first rdn
225          * FIXME: we prefer efficiency over checking if the _ENTIRE_
226          * dn can be parsed
227          */
228         if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP ) 
229                         != LDAP_SUCCESS ) {
230                 return( NULL );
231         }
232
233         for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ;
234         values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
235         if ( values == NULL ) {
236                 ldap_rdnfree( tmpRDN );
237                 return( NULL );
238         }
239
240         for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
241                 ber_len_t       l = 0, vl, al = 0;
242                 char            *str;
243                 LDAPAVA         *ava = tmpRDN[ iAVA ];
244                 
245                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
246                         vl = 1 + 2 * ava->la_value.bv_len;
247
248                 } else {
249                         if ( strval2strlen( &ava->la_value, 
250                                                 ava->la_flags, &vl ) ) {
251                                 goto error_return;
252                         }
253                 }
254                 
255                 if ( !notypes ) {
256                         al = ava->la_attr.bv_len;
257                         l = vl + ava->la_attr.bv_len + 1;
258
259                         str = LDAP_MALLOC( l + 1 );
260                         AC_MEMCPY( str, ava->la_attr.bv_val, 
261                                         ava->la_attr.bv_len );
262                         str[ al++ ] = '=';
263
264                 } else {
265                         l = vl;
266                         str = LDAP_MALLOC( l + 1 );
267                 }
268                 
269                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
270                         str[ al++ ] = '#';
271                         if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
272                                 goto error_return;
273                         }
274
275                 } else {
276                         if ( strval2str( &ava->la_value, &str[ al ], 
277                                         ava->la_flags, &vl ) ) {
278                                 goto error_return;
279                         }
280                 }
281
282                 str[ l ] = '\0';
283                 values[ iAVA ] = str;
284         }
285         values[ iAVA ] = NULL;
286
287         ldap_rdnfree( tmpRDN );
288
289         return( values );
290
291 error_return:;
292         LBER_VFREE( values );
293         ldap_rdnfree( tmpRDN );
294         return( NULL );
295 }
296
297 char *
298 ldap_dn2dcedn( LDAP_CONST char *dn )
299 {
300         char    *out = NULL;
301
302         Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
303
304         ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
305                                    &out, LDAP_DN_FORMAT_DCE );
306
307         return( out );
308 }
309
310 char *
311 ldap_dcedn2dn( LDAP_CONST char *dce )
312 {
313         char    *out = NULL;
314
315         Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
316
317         ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
318
319         return( out );
320 }
321
322 char *
323 ldap_dn2ad_canonical( LDAP_CONST char *dn )
324 {
325         char    *out = NULL;
326
327         Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
328
329         ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
330                        &out, LDAP_DN_FORMAT_AD_CANONICAL );
331
332         return( out );
333 }
334
335 /*
336  * function that changes the string representation of dnin
337  * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
338  * 
339  * fin can be one of:
340  *      LDAP_DN_FORMAT_LDAP             (rfc 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_ARGS, "=> 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_ARGS, "<= ldap_bv2dn(%s)=%d %s\n", str, rc,
894                         rc ? 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, *end;
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         end = val->bv_val + val->bv_len - 1;
2043         for ( l = 0, p = val->bv_val; p <= end; p += cl ) {
2044
2045                 /* 
2046                  * escape '%x00' 
2047                  */
2048                 if ( p[ 0 ] == '\0' ) {
2049                         cl = 1;
2050                         l += 3;
2051                         continue;
2052                 }
2053
2054                 cl = LDAP_UTF8_CHARLEN2( p, cl );
2055                 if ( cl == 0 ) {
2056                         /* illegal utf-8 char! */
2057                         return( -1 );
2058
2059                 } else if ( cl > 1 ) {
2060                         ber_len_t cnt;
2061
2062                         for ( cnt = 1; cnt < cl; cnt++ ) {
2063                                 if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
2064                                         return( -1 );
2065                                 }
2066                         }
2067                         l += escaped_byte_len * cl;
2068
2069                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2070                                 || LDAP_DN_SHOULDESCAPE( p[ 0 ] )
2071                                 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2072                                 || ( p == end && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2073 #ifdef PRETTY_ESCAPE
2074 #if 0
2075                         if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
2076 #else
2077                         if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
2078 #endif
2079
2080                                 /* 
2081                                  * there might be some chars we want 
2082                                  * to escape in form of a couple 
2083                                  * of hexdigits for optimization purposes
2084                                  */
2085                                 l += 3;
2086
2087                         } else {
2088                                 l += escaped_ascii_len;
2089                         }
2090 #else /* ! PRETTY_ESCAPE */
2091                         l += 3;
2092 #endif /* ! PRETTY_ESCAPE */
2093
2094                 } else {
2095                         l++;
2096                 }
2097         }
2098
2099         *len = l;
2100
2101         return( 0 );
2102 }
2103
2104 /*
2105  * convert to string representation, escaping with hex the UTF-8 stuff;
2106  * assume the destination has enough room for escaping
2107  */
2108 static int
2109 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2110 {
2111         ber_len_t       s, d, end;
2112
2113         assert( val != NULL );
2114         assert( str != NULL );
2115         assert( len != NULL );
2116
2117         if ( val->bv_len == 0 ) {
2118                 *len = 0;
2119                 return( 0 );
2120         }
2121
2122         /* 
2123          * we assume the string has enough room for the hex encoding
2124          * of the value
2125          */
2126         for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2127                 ber_len_t       cl;
2128
2129                 /* 
2130                  * escape '%x00' 
2131                  */
2132                 if ( val->bv_val[ s ] == '\0' ) {
2133                         cl = 1;
2134                         str[ d++ ] = '\\';
2135                         str[ d++ ] = '0';
2136                         str[ d++ ] = '0';
2137                         s++;
2138                         continue;
2139                 }
2140                 
2141                 /*
2142                  * The length was checked in strval2strlen();
2143                  * LDAP_UTF8_CHARLEN() should suffice
2144                  */
2145                 cl = LDAP_UTF8_CHARLEN2( &val->bv_val[ s ], cl );
2146                 assert( cl > 0 );
2147                 
2148                 /* 
2149                  * there might be some chars we want to escape in form
2150                  * of a couple of hexdigits for optimization purposes
2151                  */
2152                 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) 
2153 #ifdef PRETTY_ESCAPE
2154 #if 0
2155                                 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] ) 
2156 #else
2157                                 || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] ) 
2158 #endif
2159 #else /* ! PRETTY_ESCAPE */
2160                                 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2161                                 || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
2162                                 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2163                                 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
2164
2165 #endif /* ! PRETTY_ESCAPE */
2166                                 ) {
2167                         for ( ; cl--; ) {
2168                                 str[ d++ ] = '\\';
2169                                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2170                                 s++;
2171                                 d += 2;
2172                         }
2173
2174                 } else if ( cl > 1 ) {
2175                         for ( ; cl--; ) {
2176                                 str[ d++ ] = val->bv_val[ s++ ];
2177                         }
2178
2179                 } else {
2180 #ifdef PRETTY_ESCAPE
2181                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2182                                         || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
2183                                         || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2184                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2185                                 str[ d++ ] = '\\';
2186                                 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2187                                         byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2188                                         s++;
2189                                         d += 2;
2190                                         continue;
2191                                 }
2192                         }
2193 #endif /* PRETTY_ESCAPE */
2194                         str[ d++ ] = val->bv_val[ s++ ];
2195                 }
2196         }
2197
2198         *len = d;
2199         
2200         return( 0 );
2201 }
2202
2203 /*
2204  * Length of the IA5 string representation (no UTF-8 allowed)
2205  */
2206 static int
2207 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2208 {
2209         ber_len_t       l;
2210         char            *p;
2211
2212         assert( val != NULL );
2213         assert( len != NULL );
2214
2215         *len = 0;
2216         if ( val->bv_len == 0 ) {
2217                 return( 0 );
2218         }
2219
2220         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2221                 /*
2222                  * Turn value into a binary encoded BER
2223                  */
2224                 return( -1 );
2225
2226         } else {
2227                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2228                         if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2229                                         || LDAP_DN_SHOULDESCAPE( p[ 0 ] )
2230                                         || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2231                                         || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2232                                 l += 2;
2233
2234                         } else {
2235                                 l++;
2236                         }
2237                 }
2238         }
2239
2240         *len = l;
2241         
2242         return( 0 );
2243 }
2244
2245 /*
2246  * convert to string representation (np UTF-8)
2247  * assume the destination has enough room for escaping
2248  */
2249 static int
2250 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2251 {
2252         ber_len_t       s, d, end;
2253
2254         assert( val != NULL );
2255         assert( str != NULL );
2256         assert( len != NULL );
2257
2258         if ( val->bv_len == 0 ) {
2259                 *len = 0;
2260                 return( 0 );
2261         }
2262
2263         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2264                 /*
2265                  * Turn value into a binary encoded BER
2266                  */
2267                 *len = 0;
2268                 return( -1 );
2269
2270         } else {
2271                 /* 
2272                  * we assume the string has enough room for the hex encoding
2273                  * of the value
2274                  */
2275
2276                 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2277                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2278                                         || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
2279                                         || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2280                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2281                                 str[ d++ ] = '\\';
2282                         }
2283                         str[ d++ ] = val->bv_val[ s++ ];
2284                 }
2285         }
2286
2287         *len = d;
2288         
2289         return( 0 );
2290 }
2291
2292 /*
2293  * Length of the (supposedly) DCE string representation, 
2294  * accounting for escaped hex of UTF-8 chars
2295  */
2296 static int
2297 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2298 {
2299         ber_len_t       l;
2300         char            *p;
2301
2302         assert( val != NULL );
2303         assert( len != NULL );
2304
2305         *len = 0;
2306         if ( val->bv_len == 0 ) {
2307                 return( 0 );
2308         }
2309
2310         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2311                 /* 
2312                  * FIXME: Turn the value into a binary encoded BER?
2313                  */
2314                 return( -1 );
2315                 
2316         } else {
2317                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2318                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2319                                 l += 2;
2320
2321                         } else {
2322                                 l++;
2323                         }
2324                 }
2325         }
2326
2327         *len = l;
2328
2329         return( 0 );
2330 }
2331
2332 /*
2333  * convert to (supposedly) DCE string representation, 
2334  * escaping with hex the UTF-8 stuff;
2335  * assume the destination has enough room for escaping
2336  */
2337 static int
2338 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2339 {
2340         ber_len_t       s, d;
2341
2342         assert( val != NULL );
2343         assert( str != NULL );
2344         assert( len != NULL );
2345
2346         if ( val->bv_len == 0 ) {
2347                 *len = 0;
2348                 return( 0 );
2349         }
2350
2351         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2352                 /*
2353                  * FIXME: Turn the value into a binary encoded BER?
2354                  */
2355                 *len = 0;
2356                 return( -1 );
2357                 
2358         } else {
2359
2360                 /* 
2361                  * we assume the string has enough room for the hex encoding
2362                  * of the value
2363                  */
2364
2365                 for ( s = 0, d = 0; s < val->bv_len; ) {
2366                         if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2367                                 str[ d++ ] = '\\';
2368                         }
2369                         str[ d++ ] = val->bv_val[ s++ ];
2370                 }
2371         }
2372
2373         *len = d;
2374         
2375         return( 0 );
2376 }
2377
2378 /*
2379  * Length of the (supposedly) AD canonical string representation, 
2380  * accounting for escaped hex of UTF-8 chars
2381  */
2382 static int
2383 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2384 {
2385         ber_len_t       l;
2386         char            *p;
2387
2388         assert( val != NULL );
2389         assert( len != NULL );
2390
2391         *len = 0;
2392         if ( val->bv_len == 0 ) {
2393                 return( 0 );
2394         }
2395
2396         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2397                 /* 
2398                  * FIXME: Turn the value into a binary encoded BER?
2399                  */
2400                 return( -1 );
2401                 
2402         } else {
2403                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2404                         if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2405                                 l += 2;
2406
2407                         } else {
2408                                 l++;
2409                         }
2410                 }
2411         }
2412
2413         *len = l;
2414         
2415         return( 0 );
2416 }
2417
2418 /*
2419  * convert to (supposedly) AD string representation, 
2420  * escaping with hex the UTF-8 stuff;
2421  * assume the destination has enough room for escaping
2422  */
2423 static int
2424 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2425 {
2426         ber_len_t       s, d;
2427
2428         assert( val != NULL );
2429         assert( str != NULL );
2430         assert( len != NULL );
2431
2432         if ( val->bv_len == 0 ) {
2433                 *len = 0;
2434                 return( 0 );
2435         }
2436
2437         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2438                 /*
2439                  * FIXME: Turn the value into a binary encoded BER?
2440                  */
2441                 *len = 0;
2442                 return( -1 );
2443                 
2444         } else {
2445
2446                 /* 
2447                  * we assume the string has enough room for the hex encoding
2448                  * of the value
2449                  */
2450
2451                 for ( s = 0, d = 0; s < val->bv_len; ) {
2452                         if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2453                                 str[ d++ ] = '\\';
2454                         }
2455                         str[ d++ ] = val->bv_val[ s++ ];
2456                 }
2457         }
2458
2459         *len = d;
2460         
2461         return( 0 );
2462 }
2463
2464 /*
2465  * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2466  * the first part of the AD representation of the DN is written in DNS
2467  * form, i.e. dot separated domain name components (as suggested 
2468  * by Luke Howard, http://www.padl.com/~lukeh)
2469  */
2470 static int
2471 dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN )
2472 {
2473         int             i;
2474         int             domain = 0, first = 1;
2475         ber_len_t       l = 1; /* we move the null also */
2476         char            *str;
2477
2478         /* we are guaranteed there's enough memory in str */
2479
2480         /* sanity */
2481         assert( dn != NULL );
2482         assert( bv != NULL );
2483         assert( iRDN != NULL );
2484         assert( *iRDN >= 0 );
2485
2486         str = bv->bv_val + pos;
2487
2488         for ( i = *iRDN; i >= 0; i-- ) {
2489                 LDAPRDN         rdn;
2490                 LDAPAVA         *ava;
2491
2492                 assert( dn[ i ] != NULL );
2493                 rdn = dn[ i ];
2494
2495                 assert( rdn[ 0 ] != NULL );
2496                 ava = rdn[ 0 ];
2497
2498                 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2499                         break;
2500                 }
2501
2502                 domain = 1;
2503                 
2504                 if ( first ) {
2505                         first = 0;
2506                         AC_MEMCPY( str, ava->la_value.bv_val, 
2507                                         ava->la_value.bv_len + 1);
2508                         l += ava->la_value.bv_len;
2509
2510                 } else {
2511                         AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l);
2512                         AC_MEMCPY( str, ava->la_value.bv_val, 
2513                                         ava->la_value.bv_len );
2514                         str[ ava->la_value.bv_len ] = '.';
2515                         l += ava->la_value.bv_len + 1;
2516                 }
2517         }
2518
2519         *iRDN = i;
2520         bv->bv_len = pos + l - 1;
2521
2522         return( domain );
2523 }
2524
2525 static int
2526 rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
2527          int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2528 {
2529         int             iAVA;
2530         ber_len_t       l = 0;
2531
2532         *len = 0;
2533
2534         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2535                 LDAPAVA         *ava = rdn[ iAVA ];
2536
2537                 /* len(type) + '=' + '+' | ',' */
2538                 l += ava->la_attr.bv_len + 2;
2539
2540                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2541                         /* octothorpe + twice the length */
2542                         l += 1 + 2 * ava->la_value.bv_len;
2543
2544                 } else {
2545                         ber_len_t       vl;
2546                         unsigned        f = flags | ava->la_flags;
2547                         
2548                         if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2549                                 return( -1 );
2550                         }
2551                         l += vl;
2552                 }
2553         }
2554         
2555         *len = l;
2556         
2557         return( 0 );
2558 }
2559
2560 static int
2561 rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
2562         int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2563 {
2564         int             iAVA;
2565         ber_len_t       l = 0;
2566
2567         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2568                 LDAPAVA         *ava = rdn[ iAVA ];
2569
2570                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2571                                 ava->la_attr.bv_len );
2572                 l += ava->la_attr.bv_len;
2573
2574                 str[ l++ ] = '=';
2575
2576                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2577                         str[ l++ ] = '#';
2578                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2579                                 return( -1 );
2580                         }
2581                         l += 2 * ava->la_value.bv_len;
2582
2583                 } else {
2584                         ber_len_t       vl;
2585                         unsigned        f = flags | ava->la_flags;
2586
2587                         if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2588                                 return( -1 );
2589                         }
2590                         l += vl;
2591                 }
2592                 str[ l++ ] = ( rdn[ iAVA + 1] ? '+' : ',' );
2593         }
2594
2595         *len = l;
2596
2597         return( 0 );
2598 }
2599
2600 static int
2601 rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2602 {
2603         int             iAVA;
2604         ber_len_t       l = 0;
2605
2606         *len = 0;
2607
2608         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2609                 LDAPAVA         *ava = rdn[ iAVA ];
2610
2611                 /* len(type) + '=' + ',' | '/' */
2612                 l += ava->la_attr.bv_len + 2;
2613
2614                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2615                         /* octothorpe + twice the length */
2616                         l += 1 + 2 * ava->la_value.bv_len;
2617                 } else {
2618                         ber_len_t       vl;
2619                         unsigned        f = flags | ava->la_flags;
2620                         
2621                         if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2622                                 return( -1 );
2623                         }
2624                         l += vl;
2625                 }
2626         }
2627         
2628         *len = l;
2629         
2630         return( 0 );
2631 }
2632
2633 static int
2634 rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
2635 {
2636         int             iAVA;
2637         ber_len_t       l = 0;
2638
2639         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2640                 LDAPAVA         *ava = rdn[ iAVA ];
2641
2642                 if ( first ) {
2643                         first = 0;
2644                 } else {
2645                         str[ l++ ] = ( iAVA ? ',' : '/' );
2646                 }
2647
2648                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2649                                 ava->la_attr.bv_len );
2650                 l += ava->la_attr.bv_len;
2651
2652                 str[ l++ ] = '=';
2653
2654                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2655                         str[ l++ ] = '#';
2656                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2657                                 return( -1 );
2658                         }
2659                         l += 2 * ava->la_value.bv_len;
2660                 } else {
2661                         ber_len_t       vl;
2662                         unsigned        f = flags | ava->la_flags;
2663
2664                         if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2665                                 return( -1 );
2666                         }
2667                         l += vl;
2668                 }
2669         }
2670
2671         *len = l;
2672
2673         return( 0 );
2674 }
2675
2676 static int
2677 rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2678 {
2679         int             iAVA;
2680         ber_len_t       l = 0;
2681
2682         assert( rdn != NULL );
2683         assert( len != NULL );
2684
2685         *len = 0;
2686
2687         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2688                 LDAPAVA         *ava = rdn[ iAVA ];
2689
2690                 /* ' + ' | ', ' */
2691                 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2692
2693                 /* FIXME: are binary values allowed in UFN? */
2694                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2695                         /* octothorpe + twice the value */
2696                         l += 1 + 2 * ava->la_value.bv_len;
2697
2698                 } else {
2699                         ber_len_t       vl;
2700                         unsigned        f = flags | ava->la_flags;
2701
2702                         if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2703                                 return( -1 );
2704                         }
2705                         l += vl;
2706                 }
2707         }
2708         
2709         *len = l;
2710         
2711         return( 0 );
2712 }
2713
2714 static int
2715 rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len )
2716 {
2717         int             iAVA;
2718         ber_len_t       l = 0;
2719
2720         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2721                 LDAPAVA         *ava = rdn[ iAVA ];
2722
2723                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2724                         str[ l++ ] = '#';
2725                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2726                                 return( -1 );
2727                         }
2728                         l += 2 * ava->la_value.bv_len;
2729                         
2730                 } else {
2731                         ber_len_t       vl;
2732                         unsigned        f = flags | ava->la_flags;
2733                         
2734                         if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2735                                 return( -1 );
2736                         }
2737                         l += vl;
2738                 }
2739
2740                 if ( rdn[ iAVA + 1 ] ) {
2741                         AC_MEMCPY( &str[ l ], " + ", 3 );
2742                         l += 3;
2743
2744                 } else {
2745                         AC_MEMCPY( &str[ l ], ", ", 2 );
2746                         l += 2;
2747                 }
2748         }
2749
2750         *len = l;
2751
2752         return( 0 );
2753 }
2754
2755 static int
2756 rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2757 {
2758         int             iAVA;
2759         ber_len_t       l = 0;
2760
2761         assert( rdn != NULL );
2762         assert( len != NULL );
2763
2764         *len = 0;
2765
2766         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2767                 LDAPAVA         *ava = rdn[ iAVA ];
2768
2769                 /* ',' | '/' */
2770                 l++;
2771
2772                 /* FIXME: are binary values allowed in UFN? */
2773                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2774                         /* octothorpe + twice the value */
2775                         l += 1 + 2 * ava->la_value.bv_len;
2776                 } else {
2777                         ber_len_t       vl;
2778                         unsigned        f = flags | ava->la_flags;
2779
2780                         if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2781                                 return( -1 );
2782                         }
2783                         l += vl;
2784                 }
2785         }
2786         
2787         *len = l;
2788         
2789         return( 0 );
2790 }
2791
2792 static int
2793 rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
2794 {
2795         int             iAVA;
2796         ber_len_t       l = 0;
2797
2798         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2799                 LDAPAVA         *ava = rdn[ iAVA ];
2800
2801                 if ( first ) {
2802                         first = 0;
2803                 } else {
2804                         str[ l++ ] = ( iAVA ? ',' : '/' );
2805                 }
2806
2807                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2808                         str[ l++ ] = '#';
2809                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2810                                 return( -1 );
2811                         }
2812                         l += 2 * ava->la_value.bv_len;
2813                 } else {
2814                         ber_len_t       vl;
2815                         unsigned        f = flags | ava->la_flags;
2816                         
2817                         if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2818                                 return( -1 );
2819                         }
2820                         l += vl;
2821                 }
2822         }
2823
2824         *len = l;
2825
2826         return( 0 );
2827 }
2828
2829 /*
2830  * ldap_rdn2str
2831  *
2832  * Returns in str a string representation of rdn based on flags.
2833  * There is some duplication of code between this and ldap_dn2str;
2834  * this is wanted to reduce the allocation of temporary buffers.
2835  */
2836 int
2837 ldap_rdn2str( LDAPRDN rdn, char **str, unsigned flags )
2838 {
2839         struct berval bv;
2840         int rc;
2841
2842         assert( str != NULL );
2843
2844         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2845                 return LDAP_PARAM_ERROR;
2846         }
2847
2848         rc = ldap_rdn2bv_x( rdn, &bv, flags, NULL );
2849         *str = bv.bv_val;
2850         return rc;
2851 }
2852
2853 int
2854 ldap_rdn2bv( LDAPRDN rdn, struct berval *bv, unsigned flags )
2855 {
2856         return ldap_rdn2bv_x( rdn, bv, flags, NULL );
2857 }
2858
2859 int
2860 ldap_rdn2bv_x( LDAPRDN rdn, struct berval *bv, unsigned flags, void *ctx )
2861 {
2862         int             rc, back;
2863         ber_len_t       l;
2864         
2865         assert( bv != NULL );
2866
2867         bv->bv_len = 0;
2868         bv->bv_val = NULL;
2869
2870         if ( rdn == NULL ) {
2871                 bv->bv_val = LDAP_STRDUPX( "", ctx );
2872                 return( LDAP_SUCCESS );
2873         }
2874
2875         /*
2876          * This routine wastes "back" bytes at the end of the string
2877          */
2878
2879         switch ( LDAP_DN_FORMAT( flags ) ) {
2880         case LDAP_DN_FORMAT_LDAPV3:
2881                 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2882                         return LDAP_DECODING_ERROR;
2883                 }
2884                 break;
2885
2886         case LDAP_DN_FORMAT_LDAPV2:
2887                 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2888                         return LDAP_DECODING_ERROR;
2889                 }
2890                 break;
2891
2892         case LDAP_DN_FORMAT_UFN:
2893                 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2894                         return LDAP_DECODING_ERROR;
2895                 }
2896                 break;
2897
2898         case LDAP_DN_FORMAT_DCE:
2899                 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2900                         return LDAP_DECODING_ERROR;
2901                 }
2902                 break;
2903
2904         case LDAP_DN_FORMAT_AD_CANONICAL:
2905                 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2906                         return LDAP_DECODING_ERROR;
2907                 }
2908                 break;
2909
2910         default:
2911                 return LDAP_PARAM_ERROR;
2912         }
2913
2914         bv->bv_val = LDAP_MALLOCX( l + 1, ctx );
2915
2916         switch ( LDAP_DN_FORMAT( flags ) ) {
2917         case LDAP_DN_FORMAT_LDAPV3:
2918                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2919                 back = 1;
2920                 break;
2921
2922         case LDAP_DN_FORMAT_LDAPV2:
2923                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2924                 back = 1;
2925                 break;
2926
2927         case LDAP_DN_FORMAT_UFN:
2928                 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2929                 back = 2;
2930                 break;
2931
2932         case LDAP_DN_FORMAT_DCE:
2933                 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2934                 back = 0;
2935                 break;
2936
2937         case LDAP_DN_FORMAT_AD_CANONICAL:
2938                 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2939                 back = 0;
2940                 break;
2941
2942         default:
2943                 /* need at least one of the previous */
2944                 return LDAP_PARAM_ERROR;
2945         }
2946
2947         if ( rc ) {
2948                 LDAP_FREEX( bv->bv_val, ctx );
2949                 return rc;
2950         }
2951
2952         bv->bv_len = l - back;
2953         bv->bv_val[ bv->bv_len ] = '\0';
2954
2955         return LDAP_SUCCESS;
2956 }
2957
2958 /*
2959  * Very bulk implementation; many optimizations can be performed
2960  *   - a NULL dn results in an empty string ""
2961  * 
2962  * FIXME: doubts
2963  *   a) what do we do if a UTF-8 string must be converted in LDAPv2?
2964  *      we must encode it in binary form ('#' + HEXPAIRs)
2965  *   b) does DCE/AD support UTF-8?
2966  *      no clue; don't think so.
2967  *   c) what do we do when binary values must be converted in UTF/DCE/AD?
2968  *      use binary encoded BER
2969  */ 
2970 int ldap_dn2str( LDAPDN dn, char **str, unsigned flags )
2971 {
2972         struct berval bv;
2973         int rc;
2974
2975         assert( str != NULL );
2976
2977         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2978                 return LDAP_PARAM_ERROR;
2979         }
2980         
2981         rc = ldap_dn2bv_x( dn, &bv, flags, NULL );
2982         *str = bv.bv_val;
2983         return rc;
2984 }
2985
2986 int ldap_dn2bv( LDAPDN dn, struct berval *bv, unsigned flags )
2987 {
2988         return ldap_dn2bv_x( dn, bv, flags, NULL );
2989 }
2990
2991 int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx )
2992 {
2993         int             iRDN;
2994         int             rc = LDAP_ENCODING_ERROR;
2995         ber_len_t       len, l;
2996
2997         /* stringifying helpers for LDAPv3/LDAPv2 */
2998         int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2999         int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
3000
3001         assert( bv != NULL );
3002         bv->bv_len = 0;
3003         bv->bv_val = NULL;
3004
3005         Debug( LDAP_DEBUG_ARGS, "=> ldap_dn2bv(%u)\n", flags, 0, 0 );
3006
3007         /* 
3008          * a null dn means an empty dn string 
3009          * FIXME: better raise an error?
3010          */
3011         if ( dn == NULL ) {
3012                 bv->bv_val = LDAP_STRDUPX( "", ctx );
3013                 return( LDAP_SUCCESS );
3014         }
3015
3016         switch ( LDAP_DN_FORMAT( flags ) ) {
3017         case LDAP_DN_FORMAT_LDAPV3:
3018                 sv2l = strval2strlen;
3019                 sv2s = strval2str;
3020
3021                 if( 0 ) {
3022         case LDAP_DN_FORMAT_LDAPV2:
3023                         sv2l = strval2IA5strlen;
3024                         sv2s = strval2IA5str;
3025                 }
3026
3027                 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3028                         ber_len_t       rdnl;
3029                         if ( rdn2strlen( dn[ iRDN ], flags, &rdnl, sv2l ) ) {
3030                                 goto return_results;
3031                         }
3032
3033                         len += rdnl;
3034                 }
3035
3036                 if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
3037                         rc = LDAP_NO_MEMORY;
3038                         break;
3039                 }
3040
3041                 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3042                         ber_len_t       rdnl;
3043                         
3044                         if ( rdn2str( dn[ iRDN ], &bv->bv_val[ l ], flags, 
3045                                         &rdnl, sv2s ) ) {
3046                                 LDAP_FREEX( bv->bv_val, ctx );
3047                                 bv->bv_val = NULL;
3048                                 goto return_results;
3049                         }
3050                         l += rdnl;
3051                 }
3052
3053                 assert( l == len );
3054
3055                 /* 
3056                  * trim the last ',' (the allocated memory 
3057                  * is one byte longer than required)
3058                  */
3059                 bv->bv_len = len - 1;
3060                 bv->bv_val[ bv->bv_len ] = '\0';
3061
3062                 rc = LDAP_SUCCESS;
3063                 break;
3064
3065         case LDAP_DN_FORMAT_UFN: {
3066                 /*
3067                  * FIXME: quoting from RFC 1781:
3068                  *
3069    To take a distinguished name, and generate a name of this format with
3070    attribute types omitted, the following steps are followed.
3071
3072     1.  If the first attribute is of type CommonName, the type may be
3073         omitted.
3074
3075     2.  If the last attribute is of type Country, the type may be
3076         omitted.
3077
3078     3.  If the last attribute is of type Country, the last
3079         Organisation attribute may have the type omitted.
3080
3081     4.  All attributes of type OrganisationalUnit may have the type
3082         omitted, unless they are after an Organisation attribute or
3083         the first attribute is of type OrganisationalUnit.
3084
3085          * this should be the pedantic implementation.
3086                  *
3087                  * Here the standard implementation reflects
3088                  * the one historically provided by OpenLDAP
3089                  * (and UMIch, I presume), with the variant
3090                  * of spaces and plusses (' + ') separating 
3091                  * rdn components.
3092                  * 
3093                  * A non-standard but nice implementation could
3094                  * be to turn the  final "dc" attributes into a 
3095                  * dot-separated domain.
3096                  *
3097                  * Other improvements could involve the use of
3098                  * friendly country names and so.
3099                  */
3100 #ifdef DC_IN_UFN
3101                 int     leftmost_dc = -1;
3102                 int     last_iRDN = -1;
3103 #endif /* DC_IN_UFN */
3104
3105                 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3106                         ber_len_t       rdnl;
3107                         
3108                         if ( rdn2UFNstrlen( dn[ iRDN ], flags, &rdnl ) ) {
3109                                 goto return_results;
3110                         }
3111                         len += rdnl;
3112
3113 #ifdef DC_IN_UFN
3114                         if ( LDAP_DN_IS_RDN_DC( dn[ iRDN ] ) ) {
3115                                 if ( leftmost_dc == -1 ) {
3116                                         leftmost_dc = iRDN;
3117                                 }
3118                         } else {
3119                                 leftmost_dc = -1;
3120                         }
3121 #endif /* DC_IN_UFN */
3122                 }
3123
3124                 if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
3125                         rc = LDAP_NO_MEMORY;
3126                         break;
3127                 }
3128
3129 #ifdef DC_IN_UFN
3130                 if ( leftmost_dc == -1 ) {
3131 #endif /* DC_IN_UFN */
3132                         for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3133                                 ber_len_t       vl;
3134                         
3135                                 if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], 
3136                                                 flags, &vl ) ) {
3137                                         LDAP_FREEX( bv->bv_val, ctx );
3138                                         bv->bv_val = NULL;
3139                                         goto return_results;
3140                                 }
3141                                 l += vl;
3142                         }
3143
3144                         /* 
3145                          * trim the last ', ' (the allocated memory 
3146                          * is two bytes longer than required)
3147                          */
3148                         bv->bv_len = len - 2;
3149                         bv->bv_val[ bv->bv_len ] = '\0';
3150 #ifdef DC_IN_UFN
3151                 } else {
3152                         last_iRDN = iRDN - 1;
3153
3154                         for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3155                                 ber_len_t       vl;
3156                         
3157                                 if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], 
3158                                                 flags, &vl ) ) {
3159                                         LDAP_FREEX( bv->bv_val, ctx );
3160                                         bv->bv_val = NULL;
3161                                         goto return_results;
3162                                 }
3163                                 l += vl;
3164                         }
3165
3166                         if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
3167                                 LDAP_FREEX( bv->bv_val, ctx );
3168                                 bv->bv_val = NULL;
3169                                 goto return_results;
3170                         }
3171
3172                         /* the string is correctly terminated by dn2domain */
3173                 }
3174 #endif /* DC_IN_UFN */
3175                 
3176                 rc = LDAP_SUCCESS;
3177
3178         } break;
3179
3180         case LDAP_DN_FORMAT_DCE:
3181                 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3182                         ber_len_t       rdnl;
3183                         if ( rdn2DCEstrlen( dn[ iRDN ], flags, &rdnl ) ) {
3184                                 goto return_results;
3185                         }
3186
3187                         len += rdnl;
3188                 }
3189
3190                 if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
3191                         rc = LDAP_NO_MEMORY;
3192                         break;
3193                 }
3194
3195                 for ( l = 0; iRDN--; ) {
3196                         ber_len_t       rdnl;
3197                         
3198                         if ( rdn2DCEstr( dn[ iRDN ], &bv->bv_val[ l ], flags, 
3199                                         &rdnl, 0 ) ) {
3200                                 LDAP_FREEX( bv->bv_val, ctx );
3201                                 bv->bv_val = NULL;
3202                                 goto return_results;
3203                         }
3204                         l += rdnl;
3205                 }
3206
3207                 assert( l == len );
3208
3209                 bv->bv_len = len;
3210                 bv->bv_val[ bv->bv_len ] = '\0';
3211
3212                 rc = LDAP_SUCCESS;
3213                 break;
3214
3215         case LDAP_DN_FORMAT_AD_CANONICAL: {
3216                 int     trailing_slash = 1;
3217
3218                 /*
3219                  * Sort of UFN for DCE DNs: a slash ('/') separated
3220                  * global->local DN with no types; strictly speaking,
3221                  * the naming context should be a domain, which is
3222                  * written in DNS-style, e.g. dot-deparated.
3223                  * 
3224                  * Example:
3225                  * 
3226                  *      "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3227                  *
3228                  * will read
3229                  * 
3230                  *      "microsoft.com/People/Bill,Gates"
3231                  */ 
3232                 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3233                         ber_len_t       rdnl;
3234                         
3235                         if ( rdn2ADstrlen( dn[ iRDN ], flags, &rdnl ) ) {
3236                                 goto return_results;
3237                         }
3238
3239                         len += rdnl;
3240                 }
3241
3242                 /* reserve room for trailing '/' in case the DN 
3243                  * is exactly a domain */
3244                 if ( ( bv->bv_val = LDAP_MALLOCX( len + 1 + 1, ctx ) ) == NULL )
3245                 {
3246                         rc = LDAP_NO_MEMORY;
3247                         break;
3248                 }
3249
3250                 iRDN--;
3251                 if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) != 0 ) {
3252                         for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3253                                 ber_len_t       rdnl;
3254
3255                                 trailing_slash = 0;
3256                         
3257                                 if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], 
3258                                                 flags, &rdnl, 0 ) ) {
3259                                         LDAP_FREEX( bv->bv_val, ctx );
3260                                         bv->bv_val = NULL;
3261                                         goto return_results;
3262                                 }
3263                                 l += rdnl;
3264                         }
3265
3266                 } else {
3267                         int             first = 1;
3268
3269                         /*
3270                          * Strictly speaking, AD canonical requires
3271                          * a DN to be in the form "..., dc=smtg",
3272                          * i.e. terminated by a domain component
3273                          */
3274                         if ( flags & LDAP_DN_PEDANTIC ) {
3275                                 LDAP_FREEX( bv->bv_val, ctx );
3276                                 bv->bv_val = NULL;
3277                                 rc = LDAP_ENCODING_ERROR;
3278                                 break;
3279                         }
3280
3281                         for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3282                                 ber_len_t       rdnl;
3283                         
3284                                 if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], 
3285                                                 flags, &rdnl, first ) ) {
3286                                         LDAP_FREEX( bv->bv_val, ctx );
3287                                         bv->bv_val = NULL;
3288                                         goto return_results;
3289                                 }
3290                                 if ( first ) {
3291                                         first = 0;
3292                                 }
3293                                 l += rdnl;
3294                         }
3295                 }
3296
3297                 if ( trailing_slash ) {
3298                         /* the DN is exactly a domain -- need a trailing
3299                          * slash; room was reserved in advance */
3300                         bv->bv_val[ len ] = '/';
3301                         len++;
3302                 }
3303
3304                 bv->bv_len = len;
3305                 bv->bv_val[ bv->bv_len ] = '\0';
3306
3307                 rc = LDAP_SUCCESS;
3308         } break;
3309
3310         default:
3311                 return LDAP_PARAM_ERROR;
3312         }
3313
3314         Debug( LDAP_DEBUG_ARGS, "<= ldap_dn2bv(%s)=%d %s\n",
3315                 bv->bv_val, rc, rc ? ldap_err2string( rc ) : "" );
3316
3317 return_results:;
3318         return( rc );
3319 }
3320
3321 #ifdef HAVE_TLS
3322 #include <openssl/x509.h>
3323 #include <openssl/err.h>
3324
3325 /* Convert a structured DN from an X.509 certificate into an LDAPV3 DN.
3326  * x509_name must be an (X509_NAME *). If func is non-NULL, the
3327  * constructed DN will use numeric OIDs to identify attributeTypes,
3328  * and the func() will be invoked to rewrite the DN with the given
3329  * flags.
3330  *
3331  * Otherwise the DN will use shortNames as defined in the OpenSSL
3332  * library.
3333  *
3334  * It's preferable to let slapd do the OID to attributeType mapping,
3335  * because the OpenSSL tables are known to have many typos in versions
3336  * up to (at least) 0.9.6c. However, the LDAP client has no schema tables,
3337  * so we're forced to use OpenSSL's mapping there.
3338  *  -- Howard Chu 2002-04-18
3339  */
3340
3341 int
3342 ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func,
3343         unsigned flags )
3344 {
3345         LDAPDN  newDN;
3346         LDAPRDN newRDN;
3347         LDAPAVA *newAVA, *baseAVA;
3348         X509_NAME_ENTRY *ne;
3349         ASN1_OBJECT *obj;
3350         ASN1_STRING *str;
3351         char oids[8192], *oidptr = oids, *oidbuf = NULL;
3352         void *ptrs[2048];
3353         int i, j, k = 0, navas, nrdns, rc = LDAP_SUCCESS;
3354         int set = -1;
3355         size_t dnsize, oidrem = sizeof(oids), oidsize = 0;
3356         int csize;
3357
3358         struct berval   Val;
3359
3360         assert( bv != NULL );
3361         bv->bv_len = 0;
3362         bv->bv_val = NULL;
3363
3364         /* Get the number of AVAs. This is not necessarily the same as
3365          * the number of RDNs.
3366          */
3367         navas = X509_NAME_entry_count( x509_name );
3368
3369         /* Get the last element, to see how many RDNs there are */
3370         ne = X509_NAME_get_entry( x509_name, navas - 1 );
3371         nrdns = ne->set + 1;
3372
3373         /* Allocate the DN/RDN/AVA stuff as a single block */    
3374         dnsize = sizeof(LDAPRDN) * (nrdns+1);
3375         dnsize += sizeof(LDAPAVA *) * (navas+nrdns);
3376         dnsize += sizeof(LDAPAVA) * navas;
3377         if (dnsize > sizeof(ptrs)) {
3378                 newDN = (LDAPDN)LDAP_MALLOC( dnsize );
3379                 if ( newDN == NULL )
3380                         return LDAP_NO_MEMORY;
3381         } else {
3382                 newDN = (LDAPDN)ptrs;
3383         }
3384         
3385         newDN[nrdns] = NULL;
3386         newRDN = (LDAPRDN)(newDN + nrdns+1);
3387         newAVA = (LDAPAVA *)(newRDN + navas + nrdns);
3388         baseAVA = newAVA;
3389
3390         /* Retrieve RDNs in reverse order; LDAP is backwards from X.500. */
3391         for ( i = nrdns - 1, j = 0; i >= 0; i-- ) {
3392                 ne = X509_NAME_get_entry( x509_name, i );
3393                 obj = X509_NAME_ENTRY_get_object( ne );
3394                 str = X509_NAME_ENTRY_get_data( ne );
3395
3396                 /* If set changed, move to next RDN */
3397                 if ( set != ne->set ) {
3398                         /* If this is not the first time, end the
3399                          * previous RDN and advance.
3400                          */
3401                         if ( j > 0 ) {
3402                                 newRDN[k] = NULL;
3403                                 newRDN += k+1;
3404                         }
3405                         newDN[j++] = newRDN;
3406
3407                         k = 0;
3408                         set = ne->set;
3409                 }
3410                 newAVA->la_private = NULL;
3411                 newAVA->la_flags = LDAP_AVA_STRING;
3412
3413                 if ( !func ) {
3414                         int n = OBJ_obj2nid( obj );
3415
3416                         if (n == NID_undef)
3417                                 goto get_oid;
3418                         newAVA->la_attr.bv_val = (char *)OBJ_nid2sn( n );
3419                         newAVA->la_attr.bv_len = strlen( newAVA->la_attr.bv_val );
3420 #ifdef HAVE_EBCDIC
3421                         newAVA->la_attr.bv_val = LDAP_STRDUP( newAVA->la_attr.bv_val );
3422                         __etoa( newAVA->la_attr.bv_val );
3423                         newAVA->la_flags |= LDAP_AVA_FREE_ATTR;
3424 #endif
3425                 } else {
3426 get_oid:                newAVA->la_attr.bv_val = oidptr;
3427                         newAVA->la_attr.bv_len = OBJ_obj2txt( oidptr, oidrem, obj, 1 );
3428 #ifdef HAVE_EBCDIC
3429                         __etoa( newAVA->la_attr.bv_val );
3430 #endif
3431                         oidptr += newAVA->la_attr.bv_len + 1;
3432                         oidrem -= newAVA->la_attr.bv_len + 1;
3433
3434                         /* Running out of OID buffer space? */
3435                         if (oidrem < 128) {
3436                                 if ( oidsize == 0 ) {
3437                                         oidsize = sizeof(oids) * 2;
3438                                         oidrem = oidsize;
3439                                         oidbuf = LDAP_MALLOC( oidsize );
3440                                         if ( oidbuf == NULL ) goto nomem;
3441                                         oidptr = oidbuf;
3442                                 } else {
3443                                         char *old = oidbuf;
3444                                         oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 );
3445                                         if ( oidbuf == NULL ) goto nomem;
3446                                         /* Buffer moved! Fix AVA pointers */
3447                                         if ( old != oidbuf ) {
3448                                                 LDAPAVA *a;
3449                                                 long dif = oidbuf - old;
3450
3451                                                 for (a=baseAVA; a<=newAVA; a++){
3452                                                         if (a->la_attr.bv_val >= old &&
3453                                                                 a->la_attr.bv_val <= (old + oidsize))
3454                                                                 a->la_attr.bv_val += dif;
3455                                                 }
3456                                         }
3457                                         oidptr = oidbuf + oidsize - oidrem;
3458                                         oidrem += oidsize;
3459                                         oidsize *= 2;
3460                                 }
3461                         }
3462                 }
3463                 Val.bv_val = (char *) str->data;
3464                 Val.bv_len = str->length;
3465                 switch( str->type ) {
3466                 case V_ASN1_UNIVERSALSTRING:
3467                         /* This uses 32-bit ISO 10646-1 */
3468                         csize = 4; goto to_utf8;
3469                 case V_ASN1_BMPSTRING:
3470                         /* This uses 16-bit ISO 10646-1 */
3471                         csize = 2; goto to_utf8;
3472                 case V_ASN1_T61STRING:
3473                         /* This uses 8-bit, assume ISO 8859-1 */
3474                         csize = 1;
3475 to_utf8:                rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value );
3476                         newAVA->la_flags |= LDAP_AVA_FREE_VALUE;
3477                         if (rc != LDAP_SUCCESS) goto nomem;
3478                         newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
3479                         break;
3480                 case V_ASN1_UTF8STRING:
3481                         newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
3482                         /* This is already in UTF-8 encoding */
3483                 case V_ASN1_IA5STRING:
3484                 case V_ASN1_PRINTABLESTRING:
3485                         /* These are always 7-bit strings */
3486                         newAVA->la_value = Val;
3487                 default:
3488                         ;
3489                 }
3490                 newRDN[k] = newAVA;
3491                 newAVA++;
3492                 k++;
3493         }
3494         newRDN[k] = NULL;
3495
3496         if ( func ) {
3497                 rc = func( newDN, flags, NULL );
3498                 if ( rc != LDAP_SUCCESS )
3499                         goto nomem;
3500         }
3501
3502         rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL );
3503
3504 nomem:
3505         for (;baseAVA < newAVA; baseAVA++) {
3506                 if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR)
3507                         LDAP_FREE( baseAVA->la_attr.bv_val );
3508                 if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE)
3509                         LDAP_FREE( baseAVA->la_value.bv_val );
3510         }
3511
3512         if ( oidsize != 0 )
3513                 LDAP_FREE( oidbuf );
3514         if ( newDN != (LDAPDN) ptrs )
3515                 LDAP_FREE( newDN );
3516         return rc;
3517 }
3518 #endif /* HAVE_TLS */
3519