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