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