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