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