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