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