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