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