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