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