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