]> git.sur5r.net Git - openldap/blob - servers/slapd/dn.c
use BER_BVNULL
[openldap] / servers / slapd / dn.c
1 /* dn.c - routines for dealing with distinguished names */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/ctype.h>
32 #include <ac/socket.h>
33 #include <ac/string.h>
34 #include <ac/time.h>
35
36 #include "slap.h"
37 #include "ldap_pvt.h" /* must be after slap.h, to get ldap_bv2dn_x() & co */
38 #include "lutil.h"
39
40 /*
41  * The DN syntax-related functions take advantage of the dn representation
42  * handling functions ldap_str2dn/ldap_dn2str.  The latter are not schema-
43  * aware, so the attributes and their values need be validated (and possibly
44  * normalized).  In the current implementation the required validation/nor-
45  * malization/"pretty"ing are done on newly created DN structural represen-
46  * tations; however the idea is to move towards DN handling in structural
47  * representation instead of the current string representation.  To this
48  * purpose, we need to do only the required operations and keep track of
49  * what has been done to minimize their impact on performances.
50  *
51  * Developers are strongly encouraged to use this feature, to speed-up
52  * its stabilization.
53  */
54
55 #define AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private )
56
57 /*
58  * In-place, schema-aware validation of the
59  * structural representation of a distinguished name.
60  */
61 static int
62 LDAPDN_validate( LDAPDN dn )
63 {
64         int             iRDN;
65         int             rc;
66
67         assert( dn );
68
69         for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
70                 LDAPRDN         rdn = dn[ iRDN ];
71                 int             iAVA;
72
73                 assert( rdn );
74
75                 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
76                         LDAPAVA                 *ava = rdn[ iAVA ];
77                         AttributeDescription    *ad;
78                         slap_syntax_validate_func *validate = NULL;
79
80                         assert( ava );
81                         
82                         if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
83                                 const char      *text = NULL;
84
85                                 rc = slap_bv2ad( &ava->la_attr, &ad, &text );
86                                 if ( rc != LDAP_SUCCESS ) {
87                                         return LDAP_INVALID_SYNTAX;
88                                 }
89
90                                 ava->la_private = ( void * )ad;
91                         }
92
93                         /* 
94                          * Replace attr oid/name with the canonical name
95                          */
96                         ava->la_attr = ad->ad_cname;
97
98                         validate = ad->ad_type->sat_syntax->ssyn_validate;
99
100                         if ( validate ) {
101                                 /*
102                                  * validate value by validate function
103                                  */
104                                 rc = ( *validate )( ad->ad_type->sat_syntax,
105                                         &ava->la_value );
106                         
107                                 if ( rc != LDAP_SUCCESS ) {
108                                         return LDAP_INVALID_SYNTAX;
109                                 }
110                         }
111                 }
112         }
113
114         return LDAP_SUCCESS;
115 }
116
117 /*
118  * dn validate routine
119  */
120 int
121 dnValidate(
122         Syntax *syntax,
123         struct berval *in )
124 {
125         int             rc;
126         LDAPDN          dn = NULL;
127
128         assert( in );
129
130         if ( in->bv_len == 0 ) {
131                 return LDAP_SUCCESS;
132
133         } else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) {
134                 return LDAP_INVALID_SYNTAX;
135         }
136
137         rc = ldap_bv2dn( in, &dn, LDAP_DN_FORMAT_LDAP );
138         if ( rc != LDAP_SUCCESS ) {
139                 return LDAP_INVALID_SYNTAX;
140         }
141
142         assert( strlen( in->bv_val ) == in->bv_len );
143
144         /*
145          * Schema-aware validate
146          */
147         rc = LDAPDN_validate( dn );
148         ldap_dnfree( dn );
149
150         if ( rc != LDAP_SUCCESS ) {
151                 return LDAP_INVALID_SYNTAX;
152         }
153
154         return LDAP_SUCCESS;
155 }
156
157 /*
158  * AVA sorting inside a RDN
159  *
160  * rule: sort attributeTypes in alphabetical order; in case of multiple
161  * occurrences of the same attributeType, sort values in byte order
162  * (use memcmp, which implies alphabetical order in case of IA5 value;
163  * this should guarantee the repeatability of the operation).
164  *
165  * Note: the sorting can be slightly improved by sorting first
166  * by attribute type length, then by alphabetical order.
167  *
168  * uses a linear search; should be fine since the number of AVAs in
169  * a RDN should be limited.
170  */
171 static void
172 AVA_Sort( LDAPRDN rdn, int iAVA )
173 {
174         int             i;
175         LDAPAVA         *ava_in = rdn[ iAVA ];
176
177         assert( rdn );
178         assert( ava_in );
179         
180         for ( i = 0; i < iAVA; i++ ) {
181                 LDAPAVA         *ava = rdn[ i ];
182                 int             a, j;
183
184                 assert( ava );
185
186                 a = strcmp( ava_in->la_attr.bv_val, ava->la_attr.bv_val );
187
188                 if ( a > 0 ) {
189                         break;
190                 }
191
192                 while ( a == 0 ) {
193                         int             v, d;
194
195                         d = ava_in->la_value.bv_len - ava->la_value.bv_len;
196
197                         v = memcmp( ava_in->la_value.bv_val, 
198                                         ava->la_value.bv_val,
199                                         d <= 0 ? ava_in->la_value.bv_len 
200                                                 : ava->la_value.bv_len );
201
202                         if ( v == 0 && d != 0 ) {
203                                 v = d;
204                         }
205
206                         if ( v <= 0 ) {
207                                 /* 
208                                  * got it!
209                                  */
210                                 break;
211                         }
212
213                         if ( ++i == iAVA ) {
214                                 /*
215                                  * already sorted
216                                  */
217                                 return;
218                         }
219
220                         ava = rdn[ i ];
221                         a = strcmp( ava_in->la_attr.bv_val, 
222                                         ava->la_attr.bv_val );
223                 }
224
225                 /*
226                  * move ahead
227                  */
228                 for ( j = iAVA; j > i; j-- ) {
229                         rdn[ j ] = rdn[ j - 1 ];
230                 }
231                 rdn[ i ] = ava_in;
232
233                 return;
234         }
235 }
236
237 /*
238  * In-place, schema-aware normalization / "pretty"ing of the
239  * structural representation of a distinguished name.
240  */
241 static int
242 LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
243 {
244         int             iRDN;
245         int             rc;
246
247         assert( dn );
248
249         for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
250                 LDAPRDN         rdn = dn[ iRDN ];
251                 int             iAVA;
252
253                 assert( rdn );
254
255                 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
256                         LDAPAVA                 *ava = rdn[ iAVA ];
257                         AttributeDescription    *ad;
258                         slap_syntax_validate_func *validf = NULL;
259                         slap_mr_normalize_func *normf = NULL;
260                         slap_syntax_transform_func *transf = NULL;
261                         MatchingRule *mr = NULL;
262                         struct berval           bv = BER_BVNULL;
263                         int                     do_sort = 0;
264
265                         assert( ava );
266
267                         if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
268                                 const char      *text = NULL;
269
270                                 rc = slap_bv2ad( &ava->la_attr, &ad, &text );
271                                 if ( rc != LDAP_SUCCESS ) {
272                                         return LDAP_INVALID_SYNTAX;
273                                 }
274                                 
275                                 ava->la_private = ( void * )ad;
276                                 do_sort = 1;
277                         }
278
279                         /* 
280                          * Replace attr oid/name with the canonical name
281                          */
282                         ava->la_attr = ad->ad_cname;
283
284                         if( ava->la_flags & LDAP_AVA_BINARY ) {
285                                 if( ava->la_value.bv_len == 0 ) {
286                                         /* BER encoding is empty */
287                                         return LDAP_INVALID_SYNTAX;
288                                 }
289
290                                 /* AVA is binary encoded, don't muck with it */
291                         } else if( flags & SLAP_LDAPDN_PRETTY ) {
292                                 transf = ad->ad_type->sat_syntax->ssyn_pretty;
293                                 if( !transf ) {
294                                         validf = ad->ad_type->sat_syntax->ssyn_validate;
295                                 }
296                         } else { /* normalization */
297                                 validf = ad->ad_type->sat_syntax->ssyn_validate;
298                                 mr = ad->ad_type->sat_equality;
299                                 if( mr ) normf = mr->smr_normalize;
300                         }
301
302                         if ( validf ) {
303                                 /* validate value before normalization */
304                                 rc = ( *validf )( ad->ad_type->sat_syntax,
305                                         ava->la_value.bv_len
306                                                 ? &ava->la_value
307                                                 : (struct berval *) &slap_empty_bv );
308
309                                 if ( rc != LDAP_SUCCESS ) {
310                                         return LDAP_INVALID_SYNTAX;
311                                 }
312                         }
313
314                         if ( transf ) {
315                                 /*
316                                  * transform value by pretty function
317                                  *      if value is empty, use empty_bv
318                                  */
319                                 rc = ( *transf )( ad->ad_type->sat_syntax,
320                                         ava->la_value.bv_len
321                                                 ? &ava->la_value
322                                                 : (struct berval *) &slap_empty_bv,
323                                         &bv, ctx );
324                         
325                                 if ( rc != LDAP_SUCCESS ) {
326                                         return LDAP_INVALID_SYNTAX;
327                                 }
328                         }
329
330                         if ( normf ) {
331                                 /*
332                                  * normalize value
333                                  *      if value is empty, use empty_bv
334                                  */
335                                 rc = ( *normf )(
336                                         SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
337                                         ad->ad_type->sat_syntax,
338                                         mr,
339                                         ava->la_value.bv_len
340                                                 ? &ava->la_value
341                                                 : (struct berval *) &slap_empty_bv,
342                                         &bv, ctx );
343                         
344                                 if ( rc != LDAP_SUCCESS ) {
345                                         return LDAP_INVALID_SYNTAX;
346                                 }
347                         }
348
349
350                         if( bv.bv_val ) {
351                                 if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
352                                         ber_memfree_x( ava->la_value.bv_val, ctx );
353                                 ava->la_value = bv;
354                                 ava->la_flags |= LDAP_AVA_FREE_VALUE;
355                         }
356
357                         if( do_sort ) AVA_Sort( rdn, iAVA );
358                 }
359         }
360
361         return LDAP_SUCCESS;
362 }
363
364 int
365 dnNormalize(
366     slap_mask_t use,
367     Syntax *syntax,
368     MatchingRule *mr,
369     struct berval *val,
370     struct berval *out,
371     void *ctx)
372 {
373         assert( val );
374         assert( out );
375
376         Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
377
378         if ( val->bv_len != 0 ) {
379                 LDAPDN          dn = NULL;
380                 int             rc;
381
382                 /*
383                  * Go to structural representation
384                  */
385                 rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
386                 if ( rc != LDAP_SUCCESS ) {
387                         return LDAP_INVALID_SYNTAX;
388                 }
389
390                 assert( strlen( val->bv_val ) == val->bv_len );
391
392                 /*
393                  * Schema-aware rewrite
394                  */
395                 if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
396                         ldap_dnfree_x( dn, ctx );
397                         return LDAP_INVALID_SYNTAX;
398                 }
399
400                 /*
401                  * Back to string representation
402                  */
403                 rc = ldap_dn2bv_x( dn, out,
404                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
405
406                 ldap_dnfree_x( dn, ctx );
407
408                 if ( rc != LDAP_SUCCESS ) {
409                         return LDAP_INVALID_SYNTAX;
410                 }
411         } else {
412                 ber_dupbv_x( out, val, ctx );
413         }
414
415         Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
416
417         return LDAP_SUCCESS;
418 }
419
420 int
421 dnPretty(
422         Syntax *syntax,
423         struct berval *val,
424         struct berval *out,
425         void *ctx)
426 {
427         assert( val );
428         assert( out );
429
430 #ifdef NEW_LOGGING
431         LDAP_LOG( OPERATION, ARGS, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
432 #else
433         Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
434 #endif
435
436         if ( val->bv_len == 0 ) {
437                 ber_dupbv_x( out, val, ctx );
438
439         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
440                 return LDAP_INVALID_SYNTAX;
441
442         } else {
443                 LDAPDN          dn = NULL;
444                 int             rc;
445
446                 /* FIXME: should be liberal in what we accept */
447                 rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
448                 if ( rc != LDAP_SUCCESS ) {
449                         return LDAP_INVALID_SYNTAX;
450                 }
451
452                 assert( strlen( val->bv_val ) == val->bv_len );
453
454                 /*
455                  * Schema-aware rewrite
456                  */
457                 if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
458                         ldap_dnfree_x( dn, ctx );
459                         return LDAP_INVALID_SYNTAX;
460                 }
461
462                 /* FIXME: not sure why the default isn't pretty */
463                 /* RE: the default is the form that is used as
464                  * an internal representation; the pretty form
465                  * is a variant */
466                 rc = ldap_dn2bv_x( dn, out,
467                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
468
469                 ldap_dnfree_x( dn, ctx );
470
471                 if ( rc != LDAP_SUCCESS ) {
472                         return LDAP_INVALID_SYNTAX;
473                 }
474         }
475
476 #ifdef NEW_LOGGING
477         LDAP_LOG( OPERATION, ARGS, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
478 #else
479         Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
480 #endif
481
482         return LDAP_SUCCESS;
483 }
484
485 int
486 dnPrettyNormalDN(
487         Syntax *syntax,
488         struct berval *val,
489         LDAPDN *dn,
490         int flags,
491         void *ctx )
492 {
493         assert( val );
494         assert( dn );
495
496 #ifdef NEW_LOGGING
497         LDAP_LOG( OPERATION, ARGS, ">>> dn%sDN: <%s>\n", 
498                         flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
499                         val->bv_val, 0 );
500 #else
501         Debug( LDAP_DEBUG_TRACE, ">>> dn%sDN: <%s>\n", 
502                         flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
503                         val->bv_val, 0 );
504 #endif
505
506         if ( val->bv_len == 0 ) {
507                 return LDAP_SUCCESS;
508
509         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
510                 return LDAP_INVALID_SYNTAX;
511
512         } else {
513                 int             rc;
514
515                 /* FIXME: should be liberal in what we accept */
516                 rc = ldap_bv2dn_x( val, dn, LDAP_DN_FORMAT_LDAP, ctx );
517                 if ( rc != LDAP_SUCCESS ) {
518                         return LDAP_INVALID_SYNTAX;
519                 }
520
521                 assert( strlen( val->bv_val ) == val->bv_len );
522
523                 /*
524                  * Schema-aware rewrite
525                  */
526                 if ( LDAPDN_rewrite( *dn, flags, ctx ) != LDAP_SUCCESS ) {
527                         ldap_dnfree_x( *dn, ctx );
528                         *dn = NULL;
529                         return LDAP_INVALID_SYNTAX;
530                 }
531         }
532
533         Debug( LDAP_DEBUG_TRACE, "<<< dn%sDN\n", 
534                         flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal",
535                         0, 0 );
536
537         return LDAP_SUCCESS;
538 }
539
540 /*
541  * Combination of both dnPretty and dnNormalize
542  */
543 int
544 dnPrettyNormal(
545         Syntax *syntax,
546         struct berval *val,
547         struct berval *pretty,
548         struct berval *normal,
549         void *ctx)
550 {
551 #ifdef NEW_LOGGING
552         LDAP_LOG ( OPERATION, ENTRY, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 );
553 #else
554         Debug( LDAP_DEBUG_TRACE, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 );
555 #endif
556
557         assert( val );
558         assert( pretty );
559         assert( normal );
560
561         if ( val->bv_len == 0 ) {
562                 ber_dupbv_x( pretty, val, ctx );
563                 ber_dupbv_x( normal, val, ctx );
564
565         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
566                 /* too big */
567                 return LDAP_INVALID_SYNTAX;
568
569         } else {
570                 LDAPDN          dn = NULL;
571                 int             rc;
572
573                 pretty->bv_val = NULL;
574                 normal->bv_val = NULL;
575                 pretty->bv_len = 0;
576                 normal->bv_len = 0;
577
578                 /* FIXME: should be liberal in what we accept */
579                 rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
580                 if ( rc != LDAP_SUCCESS ) {
581                         return LDAP_INVALID_SYNTAX;
582                 }
583
584                 assert( strlen( val->bv_val ) == val->bv_len );
585
586                 /*
587                  * Schema-aware rewrite
588                  */
589                 if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
590                         ldap_dnfree_x( dn, ctx );
591                         return LDAP_INVALID_SYNTAX;
592                 }
593
594                 rc = ldap_dn2bv_x( dn, pretty,
595                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
596
597                 if ( rc != LDAP_SUCCESS ) {
598                         ldap_dnfree_x( dn, ctx );
599                         return LDAP_INVALID_SYNTAX;
600                 }
601
602                 if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
603                         ldap_dnfree_x( dn, ctx );
604                         ber_memfree_x( pretty->bv_val, ctx );
605                         pretty->bv_val = NULL;
606                         pretty->bv_len = 0;
607                         return LDAP_INVALID_SYNTAX;
608                 }
609
610                 rc = ldap_dn2bv_x( dn, normal,
611                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
612
613                 ldap_dnfree_x( dn, ctx );
614                 if ( rc != LDAP_SUCCESS ) {
615                         ber_memfree_x( pretty->bv_val, ctx );
616                         pretty->bv_val = NULL;
617                         pretty->bv_len = 0;
618                         return LDAP_INVALID_SYNTAX;
619                 }
620         }
621
622 #ifdef NEW_LOGGING
623         LDAP_LOG (OPERATION, RESULTS, "<<< dnPrettyNormal: <%s>, <%s>\n",
624                 pretty->bv_val, normal->bv_val, 0  );
625 #else
626         Debug( LDAP_DEBUG_TRACE, "<<< dnPrettyNormal: <%s>, <%s>\n",
627                 pretty->bv_val, normal->bv_val, 0 );
628 #endif
629
630         return LDAP_SUCCESS;
631 }
632
633 /*
634  * dnMatch routine
635  */
636 int
637 dnMatch(
638         int *matchp,
639         slap_mask_t flags,
640         Syntax *syntax,
641         MatchingRule *mr,
642         struct berval *value,
643         void *assertedValue )
644 {
645         int match;
646         struct berval *asserted = (struct berval *) assertedValue;
647
648         assert( matchp );
649         assert( value );
650         assert( assertedValue );
651         
652         match = value->bv_len - asserted->bv_len;
653
654         if ( match == 0 ) {
655                 match = memcmp( value->bv_val, asserted->bv_val, 
656                                 value->bv_len );
657         }
658
659 #ifdef NEW_LOGGING
660         LDAP_LOG( CONFIG, ENTRY, "dnMatch: %d\n    %s\n    %s\n", 
661                 match, value->bv_val, asserted->bv_val  );
662 #else
663         Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
664                 match, value->bv_val, asserted->bv_val );
665 #endif
666
667         *matchp = match;
668         return( LDAP_SUCCESS );
669 }
670
671 /*
672  * dnParent - dn's parent, in-place
673  *
674  * note: the incoming dn is assumed to be normalized/prettyfied,
675  * so that escaped rdn/ava separators are in '\'+hexpair form
676  */
677 void
678 dnParent( 
679         struct berval   *dn, 
680         struct berval   *pdn )
681 {
682         char    *p;
683
684         p = strchr( dn->bv_val, ',' );
685
686         /* one-level dn */
687         if ( p == NULL ) {
688                 pdn->bv_len = 0;
689                 pdn->bv_val = dn->bv_val + dn->bv_len;
690                 return;
691         }
692
693         assert( DN_SEPARATOR( p[ 0 ] ) );
694         p++;
695
696         assert( ATTR_LEADCHAR( p[ 0 ] ) );
697         pdn->bv_val = p;
698         pdn->bv_len = dn->bv_len - (p - dn->bv_val);
699
700         return;
701 }
702
703 int
704 dnExtractRdn( 
705         struct berval   *dn, 
706         struct berval   *rdn,
707         void *ctx )
708 {
709         LDAPRDN         tmpRDN;
710         const char      *p;
711         int             rc;
712
713         assert( dn );
714         assert( rdn );
715
716         if( dn->bv_len == 0 ) {
717                 return LDAP_OTHER;
718         }
719
720         rc = ldap_bv2rdn_x( dn, &tmpRDN, (char **)&p, LDAP_DN_FORMAT_LDAP, ctx );
721         if ( rc != LDAP_SUCCESS ) {
722                 return rc;
723         }
724
725         rc = ldap_rdn2bv_x( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
726
727         ldap_rdnfree_x( tmpRDN, ctx );
728         if ( rc != LDAP_SUCCESS ) {
729                 return rc;
730         }
731
732         return LDAP_SUCCESS;
733 }
734
735 /*
736  * We can assume the input is a prettied or normalized DN
737  */
738 int 
739 dn_rdnlen(
740         Backend         *be,
741         struct berval   *dn_in )
742 {
743         const char      *p;
744
745         assert( dn_in );
746
747         if ( dn_in == NULL ) {
748                 return 0;
749         }
750
751         if ( !dn_in->bv_len ) {
752                 return 0;
753         }
754
755         if ( be != NULL && be_issuffix( be, dn_in ) ) {
756                 return 0;
757         }
758
759         p = strchr( dn_in->bv_val, ',' );
760
761         return p ? p - dn_in->bv_val : dn_in->bv_len;
762 }
763
764
765 /* rdnValidate:
766  *
767  * LDAP_SUCCESS if rdn is a legal rdn;
768  * LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
769  */
770 int
771 rdnValidate( struct berval *rdn )
772 {
773 #if 1
774         /* Major cheat!
775          * input is a pretty or normalized DN
776          * hence, we can just search for ','
777          */
778         if( rdn == NULL || rdn->bv_len == 0 ||
779                 rdn->bv_len > SLAP_LDAPDN_MAXLEN )
780         {
781                 return LDAP_INVALID_SYNTAX;
782         }
783
784         return strchr( rdn->bv_val, ',' ) == NULL
785                 ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
786
787 #else
788         LDAPRDN         *RDN, **DN[ 2 ] = { &RDN, NULL };
789         const char      *p;
790         int             rc;
791
792         /*
793          * must be non-empty
794          */
795         if ( rdn == NULL || rdn == '\0' ) {
796                 return 0;
797         }
798
799         /*
800          * must be parsable
801          */
802         rc = ldap_bv2rdn( rdn, &RDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
803         if ( rc != LDAP_SUCCESS ) {
804                 return 0;
805         }
806
807         /*
808          * Must be one-level
809          */
810         if ( p[ 0 ] != '\0' ) {
811                 return 0;
812         }
813
814         /*
815          * Schema-aware validate
816          */
817         if ( rc == LDAP_SUCCESS ) {
818                 rc = LDAPDN_validate( DN );
819         }
820         ldap_rdnfree( RDN );
821
822         /*
823          * Must validate (there's a repeated parsing ...)
824          */
825         return ( rc == LDAP_SUCCESS );
826 #endif
827 }
828
829
830 /* build_new_dn:
831  *
832  * Used by ldbm/bdb2 back_modrdn to create the new dn of entries being
833  * renamed.
834  *
835  * new_dn = parent (p_dn) + separator + rdn (newrdn) + null.
836  */
837
838 void
839 build_new_dn( struct berval * new_dn,
840         struct berval * parent_dn,
841         struct berval * newrdn,
842         void *memctx )
843 {
844         char *ptr;
845
846         if ( parent_dn == NULL || parent_dn->bv_len == 0 ) {
847                 ber_dupbv( new_dn, newrdn );
848                 return;
849         }
850
851         new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
852         new_dn->bv_val = (char *) sl_malloc( new_dn->bv_len + 1, memctx );
853
854         ptr = lutil_strcopy( new_dn->bv_val, newrdn->bv_val );
855         *ptr++ = ',';
856         strcpy( ptr, parent_dn->bv_val );
857 }
858
859
860 /*
861  * dnIsSuffix - tells whether suffix is a suffix of dn.
862  * Both dn and suffix must be normalized.
863  */
864 int
865 dnIsSuffix(
866         const struct berval *dn,
867         const struct berval *suffix )
868 {
869         int     d = dn->bv_len - suffix->bv_len;
870
871         assert( dn );
872         assert( suffix );
873
874         /* empty suffix matches any dn */
875         if ( suffix->bv_len == 0 ) {
876                 return 1;
877         }
878
879         /* suffix longer than dn */
880         if ( d < 0 ) {
881                 return 0;
882         }
883
884         /* no rdn separator or escaped rdn separator */
885         if ( d > 1 && !DN_SEPARATOR( dn->bv_val[ d - 1 ] ) ) {
886                 return 0;
887         }
888
889         /* no possible match or malformed dn */
890         if ( d == 1 ) {
891                 return 0;
892         }
893
894         /* compare */
895         return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 );
896 }
897
898 #ifdef HAVE_TLS
899 /*
900  * Convert an X.509 DN into a normalized LDAP DN
901  */
902 int
903 dnX509normalize( void *x509_name, struct berval *out )
904 {
905         /* Invoke the LDAP library's converter with our schema-rewriter */
906         int rc = ldap_X509dn2bv( x509_name, out, LDAPDN_rewrite, 0 );
907
908         Debug( LDAP_DEBUG_TRACE,
909                 "dnX509Normalize: <%s>\n", out->bv_val, 0, 0 );
910
911         return rc;
912 }
913
914 /*
915  * Get the TLS session's peer's DN into a normalized LDAP DN
916  */
917 int
918 dnX509peerNormalize( void *ssl, struct berval *dn )
919 {
920
921         return ldap_pvt_tls_get_peer_dn( ssl, dn, (LDAPDN_rewrite_dummy *)LDAPDN_rewrite, 0 );
922 }
923 #endif