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