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