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