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