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