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