]> git.sur5r.net Git - openldap/blob - libraries/libldap/getdn.c
log error string
[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", str, flags, 0 );
740 #else
741         Debug( LDAP_DEBUG_TRACE, "=> ldap_bv2dn(%s,%u)\n", str, flags, 0 );
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)=%d %s\n", 
926                 str, rc, ldap_err2string( rc ) );
927 #else
928         Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s)=%d %s\n", str, rc,
929                         ldap_err2string( rc ) );
930 #endif
931         *dn = newDN;
932         
933         return( rc );
934 }
935
936 /*
937  * ldap_str2rdn
938  *
939  * Parses a relative DN according to flags up to a rdn separator 
940  * or to the end of str.
941  * Returns the rdn and a pointer to the string continuation, which
942  * corresponds to the rdn separator or to '\0' in case the string is over.
943  */
944 int
945 ldap_str2rdn( LDAP_CONST char *str, LDAPRDN *rdn,
946         char **n_in, unsigned flags )
947 {
948         struct berval   bv;
949
950         assert( str );
951         assert( str[ 0 ] != '\0' );     /* FIXME: is this required? */
952
953         bv.bv_len = strlen( str );
954         bv.bv_val = (char *) str;
955
956         return ldap_bv2rdn_x( &bv, rdn, n_in, flags, NULL );
957 }
958
959 int
960 ldap_bv2rdn( struct berval *bv, LDAPRDN *rdn,
961         char **n_in, unsigned flags )
962 {
963         return ldap_bv2rdn_x( bv, rdn, n_in, flags, NULL );
964 }
965
966 int
967 ldap_bv2rdn_x( struct berval *bv, LDAPRDN *rdn,
968         char **n_in, unsigned flags, void *ctx )
969 {
970         const char      **n = (const char **) n_in;
971         const char      *p;
972         int             navas = 0;
973         int             state = B4AVA;
974         int             rc = LDAP_DECODING_ERROR;
975         int             attrTypeEncoding = LDAP_AVA_STRING, 
976                         attrValueEncoding = LDAP_AVA_STRING;
977
978         struct berval   attrType = BER_BVNULL;
979         struct berval   attrValue = BER_BVNULL;
980
981         LDAPRDN         newRDN = NULL;
982         LDAPAVA         *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
983         int             num_slots = TMP_AVA_SLOTS;
984
985         char            *str;
986         ber_len_t       stoplen;
987         
988         assert( bv );
989         assert( bv->bv_len );
990         assert( bv->bv_val );
991         assert( rdn || flags & LDAP_DN_SKIP );
992         assert( n );
993
994         str = bv->bv_val;
995         stoplen = bv->bv_len;
996
997         if ( rdn ) {
998                 *rdn = NULL;
999         }
1000         *n = NULL;
1001
1002         switch ( LDAP_DN_FORMAT( flags ) ) {
1003         case LDAP_DN_FORMAT_LDAP:
1004         case LDAP_DN_FORMAT_LDAPV3:
1005         case LDAP_DN_FORMAT_LDAPV2:
1006         case LDAP_DN_FORMAT_DCE:
1007                 break;
1008
1009         /* unsupported in str2dn */
1010         case LDAP_DN_FORMAT_UFN:
1011         case LDAP_DN_FORMAT_AD_CANONICAL:
1012                 return LDAP_PARAM_ERROR;
1013
1014         case LDAP_DN_FORMAT_LBER:
1015         default:
1016                 return LDAP_PARAM_ERROR;
1017         }
1018
1019         if ( bv->bv_len == 0 ) {
1020                 return LDAP_SUCCESS;
1021
1022         }
1023
1024         if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
1025                 /* value must have embedded NULs */
1026                 return LDAP_DECODING_ERROR;
1027         }
1028
1029         p = str;
1030         for ( ; p[ 0 ] || state == GOTAVA; ) {
1031                 
1032                 /*
1033                  * The parser in principle advances one token a time,
1034                  * or toggles state if preferable.
1035                  */
1036                 switch (state) {
1037
1038                 /*
1039                  * an AttributeType can be encoded as:
1040                  * - its string representation; in detail, implementations
1041                  *   MUST recognize AttributeType string type names listed 
1042                  *   in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
1043                  *   MAY recognize other names.
1044                  * - its numeric OID (a dotted decimal string); in detail
1045                  *   RFC 2253 asserts that ``Implementations MUST allow 
1046                  *   an oid in the attribute type to be prefixed by one 
1047                  *   of the character strings "oid." or "OID."''.  As soon
1048                  *   as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253 
1049                  *   I'm not sure whether this is required or not any 
1050                  *   longer; to be liberal, we still implement it.
1051                  */
1052                 case B4AVA:
1053                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1054                                 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
1055                                         /* error */
1056                                         goto parsing_error;
1057                                 }
1058                                 p++;
1059                         }
1060
1061                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1062                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1063                                         /* error */
1064                                         goto parsing_error;
1065                                 }
1066
1067                                 /* whitespace is allowed (and trimmed) */
1068                                 p++;
1069                                 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1070                                         p++;
1071                                 }
1072
1073                                 if ( !p[ 0 ] ) {
1074                                         /* error: we expected an AVA */
1075                                         goto parsing_error;
1076                                 }
1077                         }
1078
1079                         /* oid */
1080                         if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
1081                                 state = B4OIDATTRTYPE;
1082                                 break;
1083                         }
1084                         
1085                         /* else must be alpha */
1086                         if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
1087                                 goto parsing_error;
1088                         }
1089                         
1090                         /* LDAPv2 "oid." prefix */
1091                         if ( LDAP_DN_LDAPV2( flags ) ) {
1092                                 /*
1093                                  * to be overly pedantic, we only accept
1094                                  * "OID." or "oid."
1095                                  */
1096                                 if ( flags & LDAP_DN_PEDANTIC ) {
1097                                         if ( !strncmp( p, "OID.", 4 )
1098                                                 || !strncmp( p, "oid.", 4 ) ) {
1099                                                 p += 4;
1100                                                 state = B4OIDATTRTYPE;
1101                                                 break;
1102                                         }
1103                                 } else {
1104                                        if ( !strncasecmp( p, "oid.", 4 ) ) {
1105                                                p += 4;
1106                                                state = B4OIDATTRTYPE;
1107                                                break;
1108                                        }
1109                                 }
1110                         }
1111
1112                         state = B4STRINGATTRTYPE;
1113                         break;
1114                 
1115                 case B4OIDATTRTYPE: {
1116                         int             err = LDAP_SUCCESS;
1117                         
1118                         attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
1119                                 LDAP_SCHEMA_SKIP);
1120
1121                         if ( err != LDAP_SUCCESS ) {
1122                                 goto parsing_error;
1123                         }
1124                         attrType.bv_len = p - attrType.bv_val;
1125
1126                         attrTypeEncoding = LDAP_AVA_BINARY;
1127
1128                         state = B4AVAEQUALS;
1129                         break;
1130                 }
1131
1132                 case B4STRINGATTRTYPE: {
1133                         const char      *startPos, *endPos = NULL;
1134                         ber_len_t       len;
1135                         
1136                         /* 
1137                          * the starting char has been found to be
1138                          * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1139                          * FIXME: DCE attr types seem to have a more
1140                          * restrictive syntax (no '-' ...) 
1141                          */
1142                         for ( startPos = p++; p[ 0 ]; p++ ) {
1143                                 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1144                                         continue;
1145                                 }
1146
1147                                 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1148                                         
1149                                         /*
1150                                          * RFC 2253 does not explicitly
1151                                          * allow lang extensions to attribute 
1152                                          * types in DNs ... 
1153                                          */
1154                                         if ( flags & LDAP_DN_PEDANTIC ) {
1155                                                 goto parsing_error;
1156                                         }
1157
1158                                         /*
1159                                          * we trim ';' and following lang 
1160                                          * and so from attribute types
1161                                          */
1162                                         endPos = p;
1163                                         for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1164                                                         || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1165                                                 /* no op */ ;
1166                                         }
1167                                         break;
1168                                 }
1169                                 break;
1170                         }
1171
1172                         len = ( endPos ? endPos : p ) - startPos;
1173                         if ( len == 0 ) {
1174                                 goto parsing_error;
1175                         }
1176                         
1177                         attrTypeEncoding = LDAP_AVA_STRING;
1178
1179                         /*
1180                          * here we need to decide whether to use it as is 
1181                          * or turn it in OID form; as a consequence, we
1182                          * need to decide whether to binary encode the value
1183                          */
1184                         
1185                         state = B4AVAEQUALS;
1186
1187                         if ( flags & LDAP_DN_SKIP ) {
1188                                 break;
1189                         }
1190
1191                         attrType.bv_val = (char *)startPos;
1192                         attrType.bv_len = len;
1193
1194                         break;
1195                 }
1196                                 
1197                 case B4AVAEQUALS:
1198                         /* spaces may not be allowed */
1199                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1200                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1201                                         goto parsing_error;
1202                                 }
1203                         
1204                                 /* trim spaces */
1205                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1206                                         /* no op */
1207                                 }
1208                         }
1209
1210                         /* need equal sign */
1211                         if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1212                                 goto parsing_error;
1213                         }
1214                         p++;
1215
1216                         /* spaces may not be allowed */
1217                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1218                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1219                                         goto parsing_error;
1220                                 }
1221
1222                                 /* trim spaces */
1223                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1224                                         /* no op */
1225                                 }
1226                         }
1227
1228                         /*
1229                          * octothorpe means a BER encoded value will follow
1230                          * FIXME: I don't think DCE will allow it
1231                          */
1232                         if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1233                                 p++;
1234                                 attrValueEncoding = LDAP_AVA_BINARY;
1235                                 state = B4BINARYVALUE;
1236                                 break;
1237                         }
1238
1239                         /* STRING value expected */
1240
1241                         /* 
1242                          * if we're pedantic, an attribute type in OID form
1243                          * SHOULD imply a BER encoded attribute value; we
1244                          * should at least issue a warning
1245                          */
1246                         if ( ( flags & LDAP_DN_PEDANTIC )
1247                                 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1248                                 /* OID attrType SHOULD use binary encoding */
1249                                 goto parsing_error;
1250                         }
1251
1252                         attrValueEncoding = LDAP_AVA_STRING;
1253
1254                         /* 
1255                          * LDAPv2 allows the attribute value to be quoted;
1256                          * also, IA5 values are expected, in principle
1257                          */
1258                         if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1259                                 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1260                                         p++;
1261                                         state = B4IA5VALUEQUOTED;
1262                                         break;
1263                                 }
1264
1265                                 if ( LDAP_DN_LDAPV2( flags ) ) {
1266                                         state = B4IA5VALUE;
1267                                         break;
1268                                 }
1269                         }
1270
1271                         /*
1272                          * here STRING means RFC 2253 string
1273                          * FIXME: what about DCE strings? 
1274                          */
1275                         if ( !p[ 0 ] ) {
1276                                 /* empty value */
1277                                 state = GOTAVA;
1278                         } else {
1279                                 state = B4STRINGVALUE;
1280                         }
1281                         break;
1282
1283                 case B4BINARYVALUE:
1284                         if ( hexstr2binval( p, &attrValue, &p, flags, ctx ) ) {
1285                                 goto parsing_error;
1286                         }
1287
1288                         state = GOTAVA;
1289                         break;
1290
1291                 case B4STRINGVALUE:
1292                         switch ( LDAP_DN_FORMAT( flags ) ) {
1293                         case LDAP_DN_FORMAT_LDAP:
1294                         case LDAP_DN_FORMAT_LDAPV3:
1295                                 if ( str2strval( p, stoplen - ( p - str ),
1296                                                         &attrValue, &p, flags, 
1297                                                         &attrValueEncoding, ctx ) ) {
1298                                         goto parsing_error;
1299                                 }
1300                                 break;
1301
1302                         case LDAP_DN_FORMAT_DCE:
1303                                 if ( DCE2strval( p, &attrValue, &p, flags, ctx ) ) {
1304                                         goto parsing_error;
1305                                 }
1306                                 break;
1307
1308                         default:
1309                                 assert( 0 );
1310                         }
1311
1312                         state = GOTAVA;
1313                         break;
1314
1315                 case B4IA5VALUE:
1316                         if ( IA52strval( p, &attrValue, &p, flags, ctx ) ) {
1317                                 goto parsing_error;
1318                         }
1319
1320                         state = GOTAVA;
1321                         break;
1322                 
1323                 case B4IA5VALUEQUOTED:
1324
1325                         /* lead quote already stripped */
1326                         if ( quotedIA52strval( p, &attrValue, 
1327                                                 &p, flags, ctx ) ) {
1328                                 goto parsing_error;
1329                         }
1330
1331                         state = GOTAVA;
1332                         break;
1333
1334                 case GOTAVA: {
1335                         int     rdnsep = 0;
1336
1337                         if ( !( flags & LDAP_DN_SKIP ) ) {
1338                                 LDAPAVA *ava;
1339
1340                                 /*
1341                                  * we accept empty values
1342                                  */
1343                                 ava = ldapava_new( &attrType, &attrValue, 
1344                                                 attrValueEncoding, ctx );
1345                                 if ( ava == NULL ) {
1346                                         rc = LDAP_NO_MEMORY;
1347                                         goto parsing_error;
1348                                 }
1349                                 tmpRDN[navas++] = ava;
1350
1351                                 attrValue.bv_val = NULL;
1352                                 attrValue.bv_len = 0;
1353
1354                                 /*
1355                                  * prepare room for new AVAs if needed
1356                                  */
1357                                 if (navas == num_slots) {
1358                                         LDAPAVA **tmp;
1359                                         
1360                                         if ( tmpRDN == tmpRDN_ ) {
1361                                                 tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPAVA * ), ctx );
1362                                                 if ( tmp == NULL ) {
1363                                                         rc = LDAP_NO_MEMORY;
1364                                                         goto parsing_error;
1365                                                 }
1366                                                 AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) );
1367
1368                                         } else {
1369                                                 tmp = LDAP_REALLOCX( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ), ctx );
1370                                                 if ( tmp == NULL ) {
1371                                                         rc = LDAP_NO_MEMORY;
1372                                                         goto parsing_error;
1373                                                 }
1374                                         }
1375
1376                                         tmpRDN = tmp;
1377                                         num_slots *= 2;
1378                                 }
1379                         }
1380                         
1381                         /* 
1382                          * if we got an AVA separator ('+', or ',' for DCE ) 
1383                          * we expect a new AVA for this RDN; otherwise 
1384                          * we add the RDN to the DN
1385                          */
1386                         switch ( LDAP_DN_FORMAT( flags ) ) {
1387                         case LDAP_DN_FORMAT_LDAP:
1388                         case LDAP_DN_FORMAT_LDAPV3:
1389                         case LDAP_DN_FORMAT_LDAPV2:
1390                                 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1391                                         rdnsep = 1;
1392                                 }
1393                                 break;
1394
1395                         case LDAP_DN_FORMAT_DCE:
1396                                 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1397                                         rdnsep = 1;
1398                                 }
1399                                 break;
1400                         }
1401
1402                         if ( rdnsep ) {
1403                                 /* 
1404                                  * the RDN is over, phew
1405                                  */
1406                                 *n = p;
1407                                 if ( !( flags & LDAP_DN_SKIP ) ) {
1408                                         newRDN = (LDAPRDN)LDAP_MALLOCX( 
1409                                                 sizeof(LDAPAVA) * (navas+1), ctx );
1410                                         if ( newRDN == NULL ) {
1411                                                 rc = LDAP_NO_MEMORY;
1412                                                 goto parsing_error;
1413                                         } else {
1414                                                 AC_MEMCPY( newRDN, tmpRDN, sizeof(LDAPAVA *) * navas);
1415                                                 newRDN[navas] = NULL;
1416                                         }
1417
1418                                 }
1419                                 rc = LDAP_SUCCESS;
1420                                 goto return_result;
1421                         }
1422
1423                         /* they should have been used in an AVA */
1424                         attrType.bv_val = NULL;
1425                         attrValue.bv_val = NULL;
1426                         
1427                         p++;
1428                         state = B4AVA;
1429                         break;
1430                 }
1431
1432                 default:
1433                         assert( 0 );
1434                         goto parsing_error;
1435                 }
1436         }
1437         *n = p;
1438         
1439 parsing_error:;
1440         /* They are set to NULL after they're used in an AVA */
1441
1442         if ( attrValue.bv_val ) {
1443                 LDAP_FREEX( attrValue.bv_val, ctx );
1444         }
1445
1446         for ( navas-- ; navas >= 0; navas-- ) {
1447                 ldapava_free( tmpRDN[navas], ctx );
1448         }
1449
1450 return_result:;
1451
1452         if ( tmpRDN != tmpRDN_ ) {
1453                 LDAP_FREEX( tmpRDN, ctx );
1454         }
1455
1456         if ( rdn ) {
1457                 *rdn = newRDN;
1458         }
1459         
1460         return( rc );
1461 }
1462
1463 /*
1464  * reads in a UTF-8 string value, unescaping stuff:
1465  * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1466  * '\' + HEXPAIR(p) -> unhex(p)
1467  */
1468 static int
1469 str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, int *retFlags, void *ctx )
1470 {
1471         const char      *p, *end, *startPos, *endPos = NULL;
1472         ber_len_t       len, escapes;
1473
1474         assert( str );
1475         assert( val );
1476         assert( next );
1477
1478         *next = NULL;
1479         end = str + stoplen;
1480         for ( startPos = p = str, escapes = 0; p < end; p++ ) {
1481                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1482                         p++;
1483                         if ( p[ 0 ] == '\0' ) {
1484                                 return( 1 );
1485                         }
1486                         if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
1487                                 escapes++;
1488                                 continue;
1489                         }
1490
1491                         if ( LDAP_DN_HEXPAIR( p ) ) {
1492                                 char c;
1493
1494                                 hexstr2bin( p, &c );
1495                                 escapes += 2;
1496
1497                                 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1498
1499                                         /*
1500                                          * we assume the string is UTF-8
1501                                          */
1502                                         *retFlags = LDAP_AVA_NONPRINTABLE;
1503                                 }
1504                                 p++;
1505
1506                                 continue;
1507                         }
1508
1509                         if ( LDAP_DN_PEDANTIC & flags ) {
1510                                 return( 1 );
1511                         }
1512                         /* 
1513                          * we do not allow escaping 
1514                          * of chars that don't need 
1515                          * to and do not belong to 
1516                          * HEXDIGITS
1517                          */
1518                         return( 1 );
1519
1520                 } else if (!LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) {
1521                         if ( p[ 0 ] == '\0' ) {
1522                                 return( 1 );
1523                         }
1524                         *retFlags = LDAP_AVA_NONPRINTABLE;
1525
1526                 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) 
1527                                 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1528                         break;
1529
1530                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1531                         /* 
1532                          * FIXME: maybe we can add 
1533                          * escapes if not pedantic?
1534                          */
1535                         return( 1 );
1536                 }
1537         }
1538
1539         /*
1540          * we do allow unescaped spaces at the end
1541          * of the value only in non-pedantic mode
1542          */
1543         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1544                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1545                 if ( flags & LDAP_DN_PEDANTIC ) {
1546                         return( 1 );
1547                 }
1548
1549                 /* strip trailing (unescaped) spaces */
1550                 for ( endPos = p - 1; 
1551                                 endPos > startPos + 1 && 
1552                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1553                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1554                                 endPos-- ) {
1555                         /* no op */
1556                 }
1557         }
1558
1559         *next = p;
1560         if ( flags & LDAP_DN_SKIP ) {
1561                 return( 0 );
1562         }
1563
1564         /*
1565          * FIXME: test memory?
1566          */
1567         len = ( endPos ? endPos : p ) - startPos - escapes;
1568         val->bv_len = len;
1569
1570         if ( escapes == 0 ) {
1571                 if ( *retFlags & LDAP_AVA_NONPRINTABLE ) {
1572                         val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1573                         AC_MEMCPY( val->bv_val, startPos, len );
1574                         val->bv_val[ len ] = '\0';
1575                 } else {
1576                         val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1577                 }
1578
1579         } else {
1580                 ber_len_t       s, d;
1581
1582                 val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1583                 for ( s = 0, d = 0; d < len; ) {
1584                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1585                                 s++;
1586                                 if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
1587                                         val->bv_val[ d++ ] = 
1588                                                 startPos[ s++ ];
1589                                         
1590                                 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1591                                         char    c;
1592
1593                                         hexstr2bin( &startPos[ s ], &c );
1594                                         val->bv_val[ d++ ] = c;
1595                                         s += 2;
1596                                         
1597                                 } else {
1598                                         /* we should never get here */
1599                                         assert( 0 );
1600                                 }
1601
1602                         } else {
1603                                 val->bv_val[ d++ ] = startPos[ s++ ];
1604                         }
1605                 }
1606
1607                 val->bv_val[ d ] = '\0';
1608                 assert( d == len );
1609         }
1610
1611         return( 0 );
1612 }
1613
1614 static int
1615 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1616 {
1617         const char      *p, *startPos, *endPos = NULL;
1618         ber_len_t       len, escapes;
1619
1620         assert( str );
1621         assert( val );
1622         assert( next );
1623
1624         *next = NULL;
1625         
1626         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1627                 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1628                         p++;
1629                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1630                                 escapes++;
1631
1632                         } else {
1633                                 return( 1 );
1634                         }
1635
1636                 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1637                         break;
1638                 }
1639
1640                 /*
1641                  * FIXME: can we accept anything else? I guess we need
1642                  * to stop if a value is not legal
1643                  */
1644         }
1645
1646         /* 
1647          * (unescaped) trailing spaces are trimmed must be silently ignored;
1648          * so we eat them
1649          */
1650         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1651                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1652                 if ( flags & LDAP_DN_PEDANTIC ) {
1653                         return( 1 );
1654                 }
1655
1656                 /* strip trailing (unescaped) spaces */
1657                 for ( endPos = p - 1; 
1658                                 endPos > startPos + 1 && 
1659                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1660                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1661                                 endPos-- ) {
1662                         /* no op */
1663                 }
1664         }
1665
1666         *next = p;
1667         if ( flags & LDAP_DN_SKIP ) {
1668                 return( 0 );
1669         }
1670         
1671         len = ( endPos ? endPos : p ) - startPos - escapes;
1672         val->bv_len = len;
1673         if ( escapes == 0 ){
1674                 val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1675
1676         } else {
1677                 ber_len_t       s, d;
1678
1679                 val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1680                 for ( s = 0, d = 0; d < len; ) {
1681                         /*
1682                          * This point is reached only if escapes 
1683                          * are properly used, so all we need to
1684                          * do is eat them
1685                          */
1686                         if (  LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1687                                 s++;
1688
1689                         }
1690                         val->bv_val[ d++ ] = startPos[ s++ ];
1691                 }
1692                 val->bv_val[ d ] = '\0';
1693                 assert( strlen( val->bv_val ) == len );
1694         }
1695         
1696         return( 0 );
1697 }
1698
1699 static int
1700 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1701 {
1702         const char      *p, *startPos, *endPos = NULL;
1703         ber_len_t       len, escapes;
1704
1705         assert( str );
1706         assert( val );
1707         assert( next );
1708
1709         *next = NULL;
1710
1711         /*
1712          * LDAPv2 (RFC 1779)
1713          */
1714         
1715         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1716                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1717                         p++;
1718                         if ( p[ 0 ] == '\0' ) {
1719                                 return( 1 );
1720                         }
1721
1722                         if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1723                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1724                                 return( 1 );
1725                         }
1726                         escapes++;
1727
1728                 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1729                         break;
1730                 }
1731
1732                 /*
1733                  * FIXME: can we accept anything else? I guess we need
1734                  * to stop if a value is not legal
1735                  */
1736         }
1737
1738         /* strip trailing (unescaped) spaces */
1739         for ( endPos = p; 
1740                         endPos > startPos + 1 && 
1741                         LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1742                         !LDAP_DN_ESCAPE( endPos[ -2 ] );
1743                         endPos-- ) {
1744                 /* no op */
1745         }
1746
1747         *next = p;
1748         if ( flags & LDAP_DN_SKIP ) {
1749                 return( 0 );
1750         }
1751
1752         len = ( endPos ? endPos : p ) - startPos - escapes;
1753         val->bv_len = len;
1754         if ( escapes == 0 ) {
1755                 val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1756
1757         } else {
1758                 ber_len_t       s, d;
1759                 
1760                 val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1761                 for ( s = 0, d = 0; d < len; ) {
1762                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1763                                 s++;
1764                         }
1765                         val->bv_val[ d++ ] = startPos[ s++ ];
1766                 }
1767                 val->bv_val[ d ] = '\0';
1768                 assert( strlen( val->bv_val ) == len );
1769         }
1770
1771         return( 0 );
1772 }
1773
1774 static int
1775 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1776 {
1777         const char      *p, *startPos, *endPos = NULL;
1778         ber_len_t       len;
1779         unsigned        escapes = 0;
1780
1781         assert( str );
1782         assert( val );
1783         assert( next );
1784
1785         *next = NULL;
1786
1787         /* initial quote already eaten */
1788         for ( startPos = p = str; p[ 0 ]; p++ ) {
1789                 /* 
1790                  * According to RFC 1779, the quoted value can
1791                  * contain escaped as well as unescaped special values;
1792                  * as a consequence we tolerate escaped values 
1793                  * (e.g. '"\,"' -> '\,') and escape unescaped specials
1794                  * (e.g. '","' -> '\,').
1795                  */
1796                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1797                         if ( p[ 1 ] == '\0' ) {
1798                                 return( 1 );
1799                         }
1800                         p++;
1801
1802                         if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1803                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1804                                 /*
1805                                  * do we allow to escape normal chars?
1806                                  * LDAPv2 does not allow any mechanism 
1807                                  * for escaping chars with '\' and hex 
1808                                  * pair
1809                                  */
1810                                 return( 1 );
1811                         }
1812                         escapes++;
1813
1814                 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1815                         endPos = p;
1816                         /* eat closing quotes */
1817                         p++;
1818                         break;
1819                 }
1820
1821                 /*
1822                  * FIXME: can we accept anything else? I guess we need
1823                  * to stop if a value is not legal
1824                  */
1825         }
1826
1827         if ( endPos == NULL ) {
1828                 return( 1 );
1829         }
1830
1831         /* Strip trailing (unescaped) spaces */
1832         for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1833                 /* no op */
1834         }
1835
1836         *next = p;
1837         if ( flags & LDAP_DN_SKIP ) {
1838                 return( 0 );
1839         }
1840
1841         len = endPos - startPos - escapes;
1842         assert( endPos >= startPos + escapes );
1843         val->bv_len = len;
1844         if ( escapes == 0 ) {
1845                 val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1846
1847         } else {
1848                 ber_len_t       s, d;
1849                 
1850                 val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1851                 val->bv_len = len;
1852
1853                 for ( s = d = 0; d < len; ) {
1854                         if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1855                                 s++;
1856                         }
1857                         val->bv_val[ d++ ] = str[ s++ ];
1858                 }
1859                 val->bv_val[ d ] = '\0';
1860                 assert( strlen( val->bv_val ) == len );
1861         }
1862
1863         return( 0 );
1864 }
1865
1866 static int
1867 hexstr2bin( const char *str, char *c )
1868 {
1869         char    c1, c2;
1870
1871         assert( str );
1872         assert( c );
1873
1874         c1 = str[ 0 ];
1875         c2 = str[ 1 ];
1876
1877         if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1878                 *c = c1 - '0';
1879
1880         } else {
1881                 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1882                         *c = c1 - 'A' + 10;
1883                 } else {
1884                         assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1885                         *c = c1 - 'a' + 10;
1886                 }
1887         }
1888
1889         *c <<= 4;
1890
1891         if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1892                 *c += c2 - '0';
1893                 
1894         } else {
1895                 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1896                         *c += c2 - 'A' + 10;
1897                 } else {
1898                         assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1899                         *c += c2 - 'a' + 10;
1900                 }
1901         }
1902
1903         return( 0 );
1904 }
1905
1906 static int
1907 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1908 {
1909         const char      *p, *startPos, *endPos = NULL;
1910         ber_len_t       len;
1911         ber_len_t       s, d;
1912
1913         assert( str );
1914         assert( val );
1915         assert( next );
1916
1917         *next = NULL;
1918
1919         for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1920                 switch ( LDAP_DN_FORMAT( flags ) ) {
1921                 case LDAP_DN_FORMAT_LDAPV3:
1922                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1923                                 goto end_of_value;
1924                         }
1925                         break;
1926
1927                 case LDAP_DN_FORMAT_LDAP:
1928                 case LDAP_DN_FORMAT_LDAPV2:
1929                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1930                                 goto end_of_value;
1931                         }
1932                         break;
1933
1934                 case LDAP_DN_FORMAT_DCE:
1935                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1936                                 goto end_of_value;
1937                         }
1938                         break;
1939                 }
1940
1941                 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1942                         if ( flags & LDAP_DN_PEDANTIC ) {
1943                                 return( 1 );
1944                         }
1945                         endPos = p;
1946
1947                         for ( ; p[ 0 ]; p++ ) {
1948                                 switch ( LDAP_DN_FORMAT( flags ) ) {
1949                                 case LDAP_DN_FORMAT_LDAPV3:
1950                                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1951                                                 goto end_of_value;
1952                                         }
1953                                         break;
1954
1955                                 case LDAP_DN_FORMAT_LDAP:
1956                                 case LDAP_DN_FORMAT_LDAPV2:
1957                                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1958                                                 goto end_of_value;
1959                                         }
1960                                         break;
1961
1962                                 case LDAP_DN_FORMAT_DCE:
1963                                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1964                                                 goto end_of_value;
1965                                         }
1966                                         break;
1967                                 }
1968                         }
1969                         break;
1970                 }
1971                 
1972                 if ( !LDAP_DN_HEXPAIR( p ) ) {
1973                         return( 1 );
1974                 }
1975         }
1976
1977 end_of_value:;
1978
1979         *next = p;
1980         if ( flags & LDAP_DN_SKIP ) {
1981                 return( 0 );
1982         }
1983
1984         len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1985         /* must be even! */
1986         assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1987
1988         val->bv_len = len;
1989         val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1990         if ( val->bv_val == NULL ) {
1991                 return( LDAP_NO_MEMORY );
1992         }
1993
1994         for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1995                 char    c;
1996
1997                 hexstr2bin( &startPos[ s ], &c );
1998
1999                 val->bv_val[ d ] = c;
2000         }
2001
2002         val->bv_val[ d ] = '\0';
2003
2004         return( 0 );
2005 }
2006
2007 /*
2008  * convert a byte in a hexadecimal pair
2009  */
2010 static int
2011 byte2hexpair( const char *val, char *pair )
2012 {
2013         static const char       hexdig[] = "0123456789ABCDEF";
2014
2015         assert( val );
2016         assert( pair );
2017
2018         /* 
2019          * we assume the string has enough room for the hex encoding
2020          * of the value
2021          */
2022
2023         pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
2024         pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
2025         
2026         return( 0 );
2027 }
2028
2029 /*
2030  * convert a binary value in hexadecimal pairs
2031  */
2032 static int
2033 binval2hexstr( struct berval *val, char *str )
2034 {
2035         ber_len_t       s, d;
2036
2037         assert( val );
2038         assert( str );
2039
2040         if ( val->bv_len == 0 ) {
2041                 return( 0 );
2042         }
2043
2044         /* 
2045          * we assume the string has enough room for the hex encoding
2046          * of the value
2047          */
2048
2049         for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
2050                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2051         }
2052         
2053         return( 0 );
2054 }
2055
2056 /*
2057  * Length of the string representation, accounting for escaped hex
2058  * of UTF-8 chars
2059  */
2060 static int
2061 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
2062 {
2063         ber_len_t       l, cl = 1;
2064         char            *p;
2065         int             escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
2066 #ifdef PRETTY_ESCAPE
2067         int             escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
2068 #endif /* PRETTY_ESCAPE */
2069         
2070         assert( val );
2071         assert( len );
2072
2073         *len = 0;
2074         if ( val->bv_len == 0 ) {
2075                 return( 0 );
2076         }
2077
2078         for ( l = 0, p = val->bv_val; p < val->bv_val + val->bv_len; p += cl ) {
2079
2080                 /* 
2081                  * escape '%x00' 
2082                  */
2083                 if ( p[ 0 ] == '\0' ) {
2084                         cl = 1;
2085                         l += 3;
2086                         continue;
2087                 }
2088
2089                 cl = LDAP_UTF8_CHARLEN2( p, cl );
2090                 if ( cl == 0 ) {
2091                         /* illegal utf-8 char! */
2092                         return( -1 );
2093
2094                 } else if ( cl > 1 ) {
2095                         ber_len_t cnt;
2096
2097                         for ( cnt = 1; cnt < cl; cnt++ ) {
2098                                 if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
2099                                         return( -1 );
2100                                 }
2101                         }
2102                         l += escaped_byte_len * cl;
2103
2104                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2105                                 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2106                                 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2107 #ifdef PRETTY_ESCAPE
2108 #if 0
2109                         if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
2110 #else
2111                         if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
2112 #endif
2113
2114                                 /* 
2115                                  * there might be some chars we want 
2116                                  * to escape in form of a couple 
2117                                  * of hexdigits for optimization purposes
2118                                  */
2119                                 l += 3;
2120
2121                         } else {
2122                                 l += escaped_ascii_len;
2123                         }
2124 #else /* ! PRETTY_ESCAPE */
2125                         l += 3;
2126 #endif /* ! PRETTY_ESCAPE */
2127
2128                 } else {
2129                         l++;
2130                 }
2131         }
2132
2133         *len = l;
2134
2135         return( 0 );
2136 }
2137
2138 /*
2139  * convert to string representation, escaping with hex the UTF-8 stuff;
2140  * assume the destination has enough room for escaping
2141  */
2142 static int
2143 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2144 {
2145         ber_len_t       s, d, end;
2146
2147         assert( val );
2148         assert( str );
2149         assert( len );
2150
2151         if ( val->bv_len == 0 ) {
2152                 *len = 0;
2153                 return( 0 );
2154         }
2155
2156         /* 
2157          * we assume the string has enough room for the hex encoding
2158          * of the value
2159          */
2160         for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2161                 ber_len_t       cl;
2162
2163                 /* 
2164                  * escape '%x00' 
2165                  */
2166                 if ( val->bv_val[ s ] == '\0' ) {
2167                         cl = 1;
2168                         str[ d++ ] = '\\';
2169                         str[ d++ ] = '0';
2170                         str[ d++ ] = '0';
2171                         s++;
2172                         continue;
2173                 }
2174                 
2175                 /*
2176                  * The length was checked in strval2strlen();
2177                  * LDAP_UTF8_CHARLEN() should suffice
2178                  */
2179                 cl = LDAP_UTF8_CHARLEN2( &val->bv_val[ s ], cl );
2180                 assert( cl > 0 );
2181                 
2182                 /* 
2183                  * there might be some chars we want to escape in form
2184                  * of a couple of hexdigits for optimization purposes
2185                  */
2186                 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) 
2187 #ifdef PRETTY_ESCAPE
2188 #if 0
2189                                 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] ) 
2190 #else
2191                                 || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] ) 
2192 #endif
2193 #else /* ! PRETTY_ESCAPE */
2194                                 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2195                                 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2196                                 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
2197
2198 #endif /* ! PRETTY_ESCAPE */
2199                                 ) {
2200                         for ( ; cl--; ) {
2201                                 str[ d++ ] = '\\';
2202                                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2203                                 s++;
2204                                 d += 2;
2205                         }
2206
2207                 } else if ( cl > 1 ) {
2208                         for ( ; cl--; ) {
2209                                 str[ d++ ] = val->bv_val[ s++ ];
2210                         }
2211
2212                 } else {
2213 #ifdef PRETTY_ESCAPE
2214                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2215                                         || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2216                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2217                                 str[ d++ ] = '\\';
2218                                 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2219                                         byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2220                                         s++;
2221                                         d += 2;
2222                                         continue;
2223                                 }
2224                         }
2225 #endif /* PRETTY_ESCAPE */
2226                         str[ d++ ] = val->bv_val[ s++ ];
2227                 }
2228         }
2229
2230         *len = d;
2231         
2232         return( 0 );
2233 }
2234
2235 /*
2236  * Length of the IA5 string representation (no UTF-8 allowed)
2237  */
2238 static int
2239 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2240 {
2241         ber_len_t       l;
2242         char            *p;
2243
2244         assert( val );
2245         assert( len );
2246
2247         *len = 0;
2248         if ( val->bv_len == 0 ) {
2249                 return( 0 );
2250         }
2251
2252         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2253                 /*
2254                  * Turn value into a binary encoded BER
2255                  */
2256                 return( -1 );
2257
2258         } else {
2259                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2260                         if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2261                                         || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2262                                         || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2263                                 l += 2;
2264
2265                         } else {
2266                                 l++;
2267                         }
2268                 }
2269         }
2270
2271         *len = l;
2272         
2273         return( 0 );
2274 }
2275
2276 /*
2277  * convert to string representation (np UTF-8)
2278  * assume the destination has enough room for escaping
2279  */
2280 static int
2281 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2282 {
2283         ber_len_t       s, d, end;
2284
2285         assert( val );
2286         assert( str );
2287         assert( len );
2288
2289         if ( val->bv_len == 0 ) {
2290                 *len = 0;
2291                 return( 0 );
2292         }
2293
2294         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2295                 /*
2296                  * Turn value into a binary encoded BER
2297                  */
2298                 *len = 0;
2299                 return( -1 );
2300
2301         } else {
2302                 /* 
2303                  * we assume the string has enough room for the hex encoding
2304                  * of the value
2305                  */
2306
2307                 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2308                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2309                                         || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2310                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2311                                 str[ d++ ] = '\\';
2312                         }
2313                         str[ d++ ] = val->bv_val[ s++ ];
2314                 }
2315         }
2316
2317         *len = d;
2318         
2319         return( 0 );
2320 }
2321
2322 /*
2323  * Length of the (supposedly) DCE string representation, 
2324  * accounting for escaped hex of UTF-8 chars
2325  */
2326 static int
2327 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2328 {
2329         ber_len_t       l;
2330         char            *p;
2331
2332         assert( val );
2333         assert( len );
2334
2335         *len = 0;
2336         if ( val->bv_len == 0 ) {
2337                 return( 0 );
2338         }
2339
2340         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2341                 /* 
2342                  * FIXME: Turn the value into a binary encoded BER?
2343                  */
2344                 return( -1 );
2345                 
2346         } else {
2347                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2348                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2349                                 l += 2;
2350
2351                         } else {
2352                                 l++;
2353                         }
2354                 }
2355         }
2356
2357         *len = l;
2358
2359         return( 0 );
2360 }
2361
2362 /*
2363  * convert to (supposedly) DCE string representation, 
2364  * escaping with hex the UTF-8 stuff;
2365  * assume the destination has enough room for escaping
2366  */
2367 static int
2368 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2369 {
2370         ber_len_t       s, d;
2371
2372         assert( val );
2373         assert( str );
2374         assert( len );
2375
2376         if ( val->bv_len == 0 ) {
2377                 *len = 0;
2378                 return( 0 );
2379         }
2380
2381         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2382                 /*
2383                  * FIXME: Turn the value into a binary encoded BER?
2384                  */
2385                 *len = 0;
2386                 return( -1 );
2387                 
2388         } else {
2389
2390                 /* 
2391                  * we assume the string has enough room for the hex encoding
2392                  * of the value
2393                  */
2394
2395                 for ( s = 0, d = 0; s < val->bv_len; ) {
2396                         if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2397                                 str[ d++ ] = '\\';
2398                         }
2399                         str[ d++ ] = val->bv_val[ s++ ];
2400                 }
2401         }
2402
2403         *len = d;
2404         
2405         return( 0 );
2406 }
2407
2408 /*
2409  * Length of the (supposedly) AD canonical string representation, 
2410  * accounting for escaped hex of UTF-8 chars
2411  */
2412 static int
2413 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2414 {
2415         ber_len_t       l;
2416         char            *p;
2417
2418         assert( val );
2419         assert( len );
2420
2421         *len = 0;
2422         if ( val->bv_len == 0 ) {
2423                 return( 0 );
2424         }
2425
2426         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2427                 /* 
2428                  * FIXME: Turn the value into a binary encoded BER?
2429                  */
2430                 return( -1 );
2431                 
2432         } else {
2433                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2434                         if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2435                                 l += 2;
2436
2437                         } else {
2438                                 l++;
2439                         }
2440                 }
2441         }
2442
2443         *len = l;
2444         
2445         return( 0 );
2446 }
2447
2448 /*
2449  * convert to (supposedly) AD string representation, 
2450  * escaping with hex the UTF-8 stuff;
2451  * assume the destination has enough room for escaping
2452  */
2453 static int
2454 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2455 {
2456         ber_len_t       s, d;
2457
2458         assert( val );
2459         assert( str );
2460         assert( len );
2461
2462         if ( val->bv_len == 0 ) {
2463                 *len = 0;
2464                 return( 0 );
2465         }
2466
2467         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2468                 /*
2469                  * FIXME: Turn the value into a binary encoded BER?
2470                  */
2471                 *len = 0;
2472                 return( -1 );
2473                 
2474         } else {
2475
2476                 /* 
2477                  * we assume the string has enough room for the hex encoding
2478                  * of the value
2479                  */
2480
2481                 for ( s = 0, d = 0; s < val->bv_len; ) {
2482                         if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2483                                 str[ d++ ] = '\\';
2484                         }
2485                         str[ d++ ] = val->bv_val[ s++ ];
2486                 }
2487         }
2488
2489         *len = d;
2490         
2491         return( 0 );
2492 }
2493
2494 /*
2495  * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2496  * the first part of the AD representation of the DN is written in DNS
2497  * form, i.e. dot separated domain name components (as suggested 
2498  * by Luke Howard, http://www.padl.com/~lukeh)
2499  */
2500 static int
2501 dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN )
2502 {
2503         int             i;
2504         int             domain = 0, first = 1;
2505         ber_len_t       l = 1; /* we move the null also */
2506         char            *str;
2507
2508         /* we are guaranteed there's enough memory in str */
2509
2510         /* sanity */
2511         assert( dn );
2512         assert( bv );
2513         assert( iRDN );
2514         assert( *iRDN >= 0 );
2515
2516         str = bv->bv_val + pos;
2517
2518         for ( i = *iRDN; i >= 0; i-- ) {
2519                 LDAPRDN         rdn;
2520                 LDAPAVA         *ava;
2521
2522                 assert( dn[ i ] );
2523                 rdn = dn[ i ];
2524
2525                 assert( rdn[ 0 ] );
2526                 ava = rdn[ 0 ];
2527
2528                 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2529                         break;
2530                 }
2531
2532                 domain = 1;
2533                 
2534                 if ( first ) {
2535                         first = 0;
2536                         AC_MEMCPY( str, ava->la_value.bv_val, 
2537                                         ava->la_value.bv_len + 1);
2538                         l += ava->la_value.bv_len;
2539
2540                 } else {
2541                         AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l);
2542                         AC_MEMCPY( str, ava->la_value.bv_val, 
2543                                         ava->la_value.bv_len );
2544                         str[ ava->la_value.bv_len ] = '.';
2545                         l += ava->la_value.bv_len + 1;
2546                 }
2547         }
2548
2549         *iRDN = i;
2550         bv->bv_len = pos + l - 1;
2551
2552         return( domain );
2553 }
2554
2555 static int
2556 rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
2557          int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2558 {
2559         int             iAVA;
2560         ber_len_t       l = 0;
2561
2562         *len = 0;
2563
2564         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2565                 LDAPAVA         *ava = rdn[ iAVA ];
2566
2567                 /* len(type) + '=' + '+' | ',' */
2568                 l += ava->la_attr.bv_len + 2;
2569
2570                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2571                         /* octothorpe + twice the length */
2572                         l += 1 + 2 * ava->la_value.bv_len;
2573
2574                 } else {
2575                         ber_len_t       vl;
2576                         unsigned        f = flags | ava->la_flags;
2577                         
2578                         if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2579                                 return( -1 );
2580                         }
2581                         l += vl;
2582                 }
2583         }
2584         
2585         *len = l;
2586         
2587         return( 0 );
2588 }
2589
2590 static int
2591 rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
2592         int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2593 {
2594         int             iAVA;
2595         ber_len_t       l = 0;
2596
2597         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2598                 LDAPAVA         *ava = rdn[ iAVA ];
2599
2600                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2601                                 ava->la_attr.bv_len );
2602                 l += ava->la_attr.bv_len;
2603
2604                 str[ l++ ] = '=';
2605
2606                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2607                         str[ l++ ] = '#';
2608                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2609                                 return( -1 );
2610                         }
2611                         l += 2 * ava->la_value.bv_len;
2612
2613                 } else {
2614                         ber_len_t       vl;
2615                         unsigned        f = flags | ava->la_flags;
2616
2617                         if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2618                                 return( -1 );
2619                         }
2620                         l += vl;
2621                 }
2622                 str[ l++ ] = ( rdn[ iAVA + 1] ? '+' : ',' );
2623         }
2624
2625         *len = l;
2626
2627         return( 0 );
2628 }
2629
2630 static int
2631 rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2632 {
2633         int             iAVA;
2634         ber_len_t       l = 0;
2635
2636         *len = 0;
2637
2638         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2639                 LDAPAVA         *ava = rdn[ iAVA ];
2640
2641                 /* len(type) + '=' + ',' | '/' */
2642                 l += ava->la_attr.bv_len + 2;
2643
2644                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2645                         /* octothorpe + twice the length */
2646                         l += 1 + 2 * ava->la_value.bv_len;
2647                 } else {
2648                         ber_len_t       vl;
2649                         unsigned        f = flags | ava->la_flags;
2650                         
2651                         if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2652                                 return( -1 );
2653                         }
2654                         l += vl;
2655                 }
2656         }
2657         
2658         *len = l;
2659         
2660         return( 0 );
2661 }
2662
2663 static int
2664 rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
2665 {
2666         int             iAVA;
2667         ber_len_t       l = 0;
2668
2669         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2670                 LDAPAVA         *ava = rdn[ iAVA ];
2671
2672                 if ( first ) {
2673                         first = 0;
2674                 } else {
2675                         str[ l++ ] = ( iAVA ? ',' : '/' );
2676                 }
2677
2678                 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, 
2679                                 ava->la_attr.bv_len );
2680                 l += ava->la_attr.bv_len;
2681
2682                 str[ l++ ] = '=';
2683
2684                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2685                         str[ l++ ] = '#';
2686                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2687                                 return( -1 );
2688                         }
2689                         l += 2 * ava->la_value.bv_len;
2690                 } else {
2691                         ber_len_t       vl;
2692                         unsigned        f = flags | ava->la_flags;
2693
2694                         if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2695                                 return( -1 );
2696                         }
2697                         l += vl;
2698                 }
2699         }
2700
2701         *len = l;
2702
2703         return( 0 );
2704 }
2705
2706 static int
2707 rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2708 {
2709         int             iAVA;
2710         ber_len_t       l = 0;
2711
2712         assert( rdn );
2713         assert( len );
2714
2715         *len = 0;
2716
2717         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2718                 LDAPAVA         *ava = rdn[ iAVA ];
2719
2720                 /* ' + ' | ', ' */
2721                 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2722
2723                 /* FIXME: are binary values allowed in UFN? */
2724                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2725                         /* octothorpe + twice the value */
2726                         l += 1 + 2 * ava->la_value.bv_len;
2727
2728                 } else {
2729                         ber_len_t       vl;
2730                         unsigned        f = flags | ava->la_flags;
2731
2732                         if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2733                                 return( -1 );
2734                         }
2735                         l += vl;
2736                 }
2737         }
2738         
2739         *len = l;
2740         
2741         return( 0 );
2742 }
2743
2744 static int
2745 rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len )
2746 {
2747         int             iAVA;
2748         ber_len_t       l = 0;
2749
2750         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2751                 LDAPAVA         *ava = rdn[ iAVA ];
2752
2753                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2754                         str[ l++ ] = '#';
2755                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2756                                 return( -1 );
2757                         }
2758                         l += 2 * ava->la_value.bv_len;
2759                         
2760                 } else {
2761                         ber_len_t       vl;
2762                         unsigned        f = flags | ava->la_flags;
2763                         
2764                         if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2765                                 return( -1 );
2766                         }
2767                         l += vl;
2768                 }
2769
2770                 if ( rdn[ iAVA + 1 ] ) {
2771                         AC_MEMCPY( &str[ l ], " + ", 3 );
2772                         l += 3;
2773
2774                 } else {
2775                         AC_MEMCPY( &str[ l ], ", ", 2 );
2776                         l += 2;
2777                 }
2778         }
2779
2780         *len = l;
2781
2782         return( 0 );
2783 }
2784
2785 static int
2786 rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2787 {
2788         int             iAVA;
2789         ber_len_t       l = 0;
2790
2791         assert( rdn );
2792         assert( len );
2793
2794         *len = 0;
2795
2796         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2797                 LDAPAVA         *ava = rdn[ iAVA ];
2798
2799                 /* ',' | '/' */
2800                 l++;
2801
2802                 /* FIXME: are binary values allowed in UFN? */
2803                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2804                         /* octothorpe + twice the value */
2805                         l += 1 + 2 * ava->la_value.bv_len;
2806                 } else {
2807                         ber_len_t       vl;
2808                         unsigned        f = flags | ava->la_flags;
2809
2810                         if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2811                                 return( -1 );
2812                         }
2813                         l += vl;
2814                 }
2815         }
2816         
2817         *len = l;
2818         
2819         return( 0 );
2820 }
2821
2822 static int
2823 rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
2824 {
2825         int             iAVA;
2826         ber_len_t       l = 0;
2827
2828         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2829                 LDAPAVA         *ava = rdn[ iAVA ];
2830
2831                 if ( first ) {
2832                         first = 0;
2833                 } else {
2834                         str[ l++ ] = ( iAVA ? ',' : '/' );
2835                 }
2836
2837                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2838                         str[ l++ ] = '#';
2839                         if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2840                                 return( -1 );
2841                         }
2842                         l += 2 * ava->la_value.bv_len;
2843                 } else {
2844                         ber_len_t       vl;
2845                         unsigned        f = flags | ava->la_flags;
2846                         
2847                         if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2848                                 return( -1 );
2849                         }
2850                         l += vl;
2851                 }
2852         }
2853
2854         *len = l;
2855
2856         return( 0 );
2857 }
2858
2859 /*
2860  * ldap_rdn2str
2861  *
2862  * Returns in str a string representation of rdn based on flags.
2863  * There is some duplication of code between this and ldap_dn2str;
2864  * this is wanted to reduce the allocation of temporary buffers.
2865  */
2866 int
2867 ldap_rdn2str( LDAPRDN rdn, char **str, unsigned flags )
2868 {
2869         struct berval bv;
2870         int rc;
2871
2872         assert( str );
2873
2874         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2875                 return LDAP_PARAM_ERROR;
2876         }
2877
2878         rc = ldap_rdn2bv_x( rdn, &bv, flags, NULL );
2879         *str = bv.bv_val;
2880         return rc;
2881 }
2882
2883 int
2884 ldap_rdn2bv( LDAPRDN rdn, struct berval *bv, unsigned flags )
2885 {
2886         return ldap_rdn2bv_x( rdn, bv, flags, NULL );
2887 }
2888
2889 int
2890 ldap_rdn2bv_x( LDAPRDN rdn, struct berval *bv, unsigned flags, void *ctx )
2891 {
2892         int             rc, back;
2893         ber_len_t       l;
2894         
2895         assert( bv );
2896
2897         bv->bv_len = 0;
2898         bv->bv_val = NULL;
2899
2900         if ( rdn == NULL ) {
2901                 bv->bv_val = LDAP_STRDUPX( "", ctx );
2902                 return( LDAP_SUCCESS );
2903         }
2904
2905         /*
2906          * This routine wastes "back" bytes at the end of the string
2907          */
2908
2909         switch ( LDAP_DN_FORMAT( flags ) ) {
2910         case LDAP_DN_FORMAT_LDAPV3:
2911                 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2912                         return LDAP_DECODING_ERROR;
2913                 }
2914                 break;
2915
2916         case LDAP_DN_FORMAT_LDAPV2:
2917                 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2918                         return LDAP_DECODING_ERROR;
2919                 }
2920                 break;
2921
2922         case LDAP_DN_FORMAT_UFN:
2923                 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2924                         return LDAP_DECODING_ERROR;
2925                 }
2926                 break;
2927
2928         case LDAP_DN_FORMAT_DCE:
2929                 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2930                         return LDAP_DECODING_ERROR;
2931                 }
2932                 break;
2933
2934         case LDAP_DN_FORMAT_AD_CANONICAL:
2935                 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2936                         return LDAP_DECODING_ERROR;
2937                 }
2938                 break;
2939
2940         default:
2941                 return LDAP_PARAM_ERROR;
2942         }
2943
2944         bv->bv_val = LDAP_MALLOCX( l + 1, ctx );
2945
2946         switch ( LDAP_DN_FORMAT( flags ) ) {
2947         case LDAP_DN_FORMAT_LDAPV3:
2948                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2949                 back = 1;
2950                 break;
2951
2952         case LDAP_DN_FORMAT_LDAPV2:
2953                 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2954                 back = 1;
2955                 break;
2956
2957         case LDAP_DN_FORMAT_UFN:
2958                 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2959                 back = 2;
2960                 break;
2961
2962         case LDAP_DN_FORMAT_DCE:
2963                 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2964                 back = 0;
2965                 break;
2966
2967         case LDAP_DN_FORMAT_AD_CANONICAL:
2968                 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2969                 back = 0;
2970                 break;
2971
2972         default:
2973                 /* need at least one of the previous */
2974                 return LDAP_PARAM_ERROR;
2975         }
2976
2977         if ( rc ) {
2978                 LDAP_FREEX( bv->bv_val, ctx );
2979                 return rc;
2980         }
2981
2982         bv->bv_len = l - back;
2983         bv->bv_val[ bv->bv_len ] = '\0';
2984
2985         return LDAP_SUCCESS;
2986 }
2987
2988 /*
2989  * Very bulk implementation; many optimizations can be performed
2990  *   - a NULL dn results in an empty string ""
2991  * 
2992  * FIXME: doubts
2993  *   a) what do we do if a UTF-8 string must be converted in LDAPv2?
2994  *      we must encode it in binary form ('#' + HEXPAIRs)
2995  *   b) does DCE/AD support UTF-8?
2996  *      no clue; don't think so.
2997  *   c) what do we do when binary values must be converted in UTF/DCE/AD?
2998  *      use binary encoded BER
2999  */ 
3000 int ldap_dn2str( LDAPDN dn, char **str, unsigned flags )
3001 {
3002         struct berval bv;
3003         int rc;
3004
3005         assert( str );
3006
3007         if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
3008                 return LDAP_PARAM_ERROR;
3009         }
3010         
3011         rc = ldap_dn2bv_x( dn, &bv, flags, NULL );
3012         *str = bv.bv_val;
3013         return rc;
3014 }
3015
3016 int ldap_dn2bv( LDAPDN dn, struct berval *bv, unsigned flags )
3017 {
3018         return ldap_dn2bv_x( dn, bv, flags, NULL );
3019 }
3020
3021 int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx )
3022 {
3023         int             iRDN;
3024         int             rc = LDAP_ENCODING_ERROR;
3025         ber_len_t       len, l;
3026
3027         /* stringifying helpers for LDAPv3/LDAPv2 */
3028         int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
3029         int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
3030
3031         assert( bv );
3032         bv->bv_len = 0;
3033         bv->bv_val = NULL;
3034
3035 #ifdef NEW_LOGGING
3036         LDAP_LOG ( OPERATION, ARGS, "=> ldap_dn2bv(%u)\n", flags, 0, 0 );
3037 #else
3038         Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n", flags, 0, 0 );
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)=%d %s\n", 
3350                 bv->bv_val, rc, ldap_err2string( rc ) );
3351 #else
3352         Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s)=%d %s\n",
3353                 bv->bv_val, rc, ldap_err2string( 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