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