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