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