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