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