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