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