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