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