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