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