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