]> git.sur5r.net Git - openldap/blob - servers/slapd/dn.c
Support subtree rename, refuse subtree delete
[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-2005 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 "lutil.h"
38
39 /*
40  * The DN syntax-related functions take advantage of the dn representation
41  * handling functions ldap_str2dn/ldap_dn2str.  The latter are not schema-
42  * aware, so the attributes and their values need be validated (and possibly
43  * normalized).  In the current implementation the required validation/nor-
44  * malization/"pretty"ing are done on newly created DN structural represen-
45  * tations; however the idea is to move towards DN handling in structural
46  * representation instead of the current string representation.  To this
47  * purpose, we need to do only the required operations and keep track of
48  * what has been done to minimize their impact on performances.
49  *
50  * Developers are strongly encouraged to use this feature, to speed-up
51  * its stabilization.
52  */
53
54 #define AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private )
55
56 static int
57 LDAPRDN_validate( LDAPRDN rdn )
58 {
59         int             iAVA;
60         int             rc;
61
62         assert( rdn );
63
64         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
65                 LDAPAVA                 *ava = rdn[ iAVA ];
66                 AttributeDescription    *ad;
67                 slap_syntax_validate_func *validate = NULL;
68
69                 assert( ava );
70                 
71                 if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
72                         const char      *text = NULL;
73
74                         rc = slap_bv2ad( &ava->la_attr, &ad, &text );
75                         if ( rc != LDAP_SUCCESS ) {
76                                 return LDAP_INVALID_SYNTAX;
77                         }
78
79                         ava->la_private = ( void * )ad;
80                 }
81
82                 /* 
83                  * Replace attr oid/name with the canonical name
84                  */
85                 ava->la_attr = ad->ad_cname;
86
87                 validate = ad->ad_type->sat_syntax->ssyn_validate;
88
89                 if ( validate ) {
90                         /*
91                          * validate value by validate function
92                          */
93                         rc = ( *validate )( ad->ad_type->sat_syntax,
94                                 &ava->la_value );
95                         
96                         if ( rc != LDAP_SUCCESS ) {
97                                 return LDAP_INVALID_SYNTAX;
98                         }
99                 }
100         }
101
102         return LDAP_SUCCESS;
103 }
104
105 /*
106  * In-place, schema-aware validation of the
107  * structural representation of a distinguished name.
108  */
109 static int
110 LDAPDN_validate( LDAPDN dn )
111 {
112         int             iRDN;
113         int             rc;
114
115         assert( dn );
116
117         for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
118                 LDAPRDN         rdn = dn[ iRDN ];
119                 int             iAVA;
120
121                 assert( rdn );
122
123                 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
124                         LDAPAVA                 *ava = rdn[ iAVA ];
125                         AttributeDescription    *ad;
126                         slap_syntax_validate_func *validate = NULL;
127
128                         assert( ava );
129                         
130                         if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
131                                 const char      *text = NULL;
132
133                                 rc = slap_bv2ad( &ava->la_attr, &ad, &text );
134                                 if ( rc != LDAP_SUCCESS ) {
135                                         return LDAP_INVALID_SYNTAX;
136                                 }
137
138                                 ava->la_private = ( void * )ad;
139                         }
140
141                         /* 
142                          * Replace attr oid/name with the canonical name
143                          */
144                         ava->la_attr = ad->ad_cname;
145
146                         validate = ad->ad_type->sat_syntax->ssyn_validate;
147
148                         if ( validate ) {
149                                 /*
150                                  * validate value by validate function
151                                  */
152                                 rc = ( *validate )( ad->ad_type->sat_syntax,
153                                         &ava->la_value );
154                         
155                                 if ( rc != LDAP_SUCCESS ) {
156                                         return LDAP_INVALID_SYNTAX;
157                                 }
158                         }
159                 }
160         }
161
162         return LDAP_SUCCESS;
163 }
164
165 /*
166  * dn validate routine
167  */
168 int
169 dnValidate(
170         Syntax *syntax,
171         struct berval *in )
172 {
173         int             rc;
174         LDAPDN          dn = NULL;
175
176         assert( in );
177
178         if ( in->bv_len == 0 ) {
179                 return LDAP_SUCCESS;
180
181         } else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) {
182                 return LDAP_INVALID_SYNTAX;
183         }
184
185         rc = ldap_bv2dn( in, &dn, LDAP_DN_FORMAT_LDAP );
186         if ( rc != LDAP_SUCCESS ) {
187                 return LDAP_INVALID_SYNTAX;
188         }
189
190         assert( strlen( in->bv_val ) == in->bv_len );
191
192         /*
193          * Schema-aware validate
194          */
195         rc = LDAPDN_validate( dn );
196         ldap_dnfree( dn );
197
198         if ( rc != LDAP_SUCCESS ) {
199                 return LDAP_INVALID_SYNTAX;
200         }
201
202         return LDAP_SUCCESS;
203 }
204
205 int
206 rdnValidate(
207         Syntax *syntax,
208         struct berval *in )
209 {
210         int             rc;
211         LDAPRDN         rdn;
212         char*           p;
213
214         assert( in );
215         if ( in->bv_len == 0 ) {
216                 return LDAP_SUCCESS;
217
218         } else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) {
219                 return LDAP_INVALID_SYNTAX;
220         }
221
222         rc = ldap_bv2rdn_x( in , &rdn, (char **) &p,
223                                 LDAP_DN_FORMAT_LDAP, NULL);
224         if ( rc != LDAP_SUCCESS ) {
225                 return LDAP_INVALID_SYNTAX;
226         }
227
228         assert( strlen( in->bv_val ) == in->bv_len );
229
230         /*
231          * Schema-aware validate
232          */
233         rc = LDAPRDN_validate( rdn );
234         ldap_rdnfree( rdn );
235
236         if ( rc != LDAP_SUCCESS ) {
237                 return LDAP_INVALID_SYNTAX;
238         }
239
240         return LDAP_SUCCESS;
241 }
242
243
244 /*
245  * AVA sorting inside a RDN
246  *
247  * rule: sort attributeTypes in alphabetical order; in case of multiple
248  * occurrences of the same attributeType, sort values in byte order
249  * (use memcmp, which implies alphabetical order in case of IA5 value;
250  * this should guarantee the repeatability of the operation).
251  *
252  * Note: the sorting can be slightly improved by sorting first
253  * by attribute type length, then by alphabetical order.
254  *
255  * uses a linear search; should be fine since the number of AVAs in
256  * a RDN should be limited.
257  */
258 static void
259 AVA_Sort( LDAPRDN rdn, int iAVA )
260 {
261         int             i;
262         LDAPAVA         *ava_in = rdn[ iAVA ];
263
264         assert( rdn );
265         assert( ava_in );
266         
267         for ( i = 0; i < iAVA; i++ ) {
268                 LDAPAVA         *ava = rdn[ i ];
269                 int             a, j;
270
271                 assert( ava );
272
273                 a = strcmp( ava_in->la_attr.bv_val, ava->la_attr.bv_val );
274
275                 if ( a > 0 ) {
276                         break;
277                 }
278
279                 while ( a == 0 ) {
280                         int             v, d;
281
282                         d = ava_in->la_value.bv_len - ava->la_value.bv_len;
283
284                         v = memcmp( ava_in->la_value.bv_val, 
285                                         ava->la_value.bv_val,
286                                         d <= 0 ? ava_in->la_value.bv_len 
287                                                 : ava->la_value.bv_len );
288
289                         if ( v == 0 && d != 0 ) {
290                                 v = d;
291                         }
292
293                         if ( v <= 0 ) {
294                                 /* 
295                                  * got it!
296                                  */
297                                 break;
298                         }
299
300                         if ( ++i == iAVA ) {
301                                 /*
302                                  * already sorted
303                                  */
304                                 return;
305                         }
306
307                         ava = rdn[ i ];
308                         a = strcmp( ava_in->la_attr.bv_val, 
309                                         ava->la_attr.bv_val );
310                 }
311
312                 /*
313                  * move ahead
314                  */
315                 for ( j = iAVA; j > i; j-- ) {
316                         rdn[ j ] = rdn[ j - 1 ];
317                 }
318                 rdn[ i ] = ava_in;
319
320                 return;
321         }
322 }
323
324 static int
325 LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
326 {
327
328         int rc;
329         int             iAVA;
330         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
331                 LDAPAVA                 *ava = rdn[ iAVA ];
332                 AttributeDescription    *ad;
333                 slap_syntax_validate_func *validf = NULL;
334                 slap_mr_normalize_func *normf = NULL;
335                 slap_syntax_transform_func *transf = NULL;
336                 MatchingRule *mr = NULL;
337                 struct berval           bv = BER_BVNULL;
338                 int                     do_sort = 0;
339
340                 assert( ava );
341
342                 if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
343                         const char      *text = NULL;
344
345                         rc = slap_bv2ad( &ava->la_attr, &ad, &text );
346                         if ( rc != LDAP_SUCCESS ) {
347                                 return LDAP_INVALID_SYNTAX;
348                         }
349                         
350                         ava->la_private = ( void * )ad;
351                         do_sort = 1;
352                 }
353
354                 /* 
355                  * Replace attr oid/name with the canonical name
356                  */
357                 ava->la_attr = ad->ad_cname;
358
359                 if( ava->la_flags & LDAP_AVA_BINARY ) {
360                         if( ava->la_value.bv_len == 0 ) {
361                                 /* BER encoding is empty */
362                                 return LDAP_INVALID_SYNTAX;
363                         }
364
365                         /* AVA is binary encoded, don't muck with it */
366                 } else if( flags & SLAP_LDAPDN_PRETTY ) {
367                         transf = ad->ad_type->sat_syntax->ssyn_pretty;
368                         if( !transf ) {
369                                 validf = ad->ad_type->sat_syntax->ssyn_validate;
370                         }
371                 } else { /* normalization */
372                         validf = ad->ad_type->sat_syntax->ssyn_validate;
373                         mr = ad->ad_type->sat_equality;
374                         if( mr ) normf = mr->smr_normalize;
375                 }
376
377                 if ( validf ) {
378                         /* validate value before normalization */
379                         rc = ( *validf )( ad->ad_type->sat_syntax,
380                                 ava->la_value.bv_len
381                                         ? &ava->la_value
382                                         : (struct berval *) &slap_empty_bv );
383
384                         if ( rc != LDAP_SUCCESS ) {
385                                 return LDAP_INVALID_SYNTAX;
386                         }
387                 }
388
389                 if ( transf ) {
390                         /*
391                          * transform value by pretty function
392                          *      if value is empty, use empty_bv
393                          */
394                         rc = ( *transf )( ad->ad_type->sat_syntax,
395                                 ava->la_value.bv_len
396                                         ? &ava->la_value
397                                         : (struct berval *) &slap_empty_bv,
398                                 &bv, ctx );
399                 
400                         if ( rc != LDAP_SUCCESS ) {
401                                 return LDAP_INVALID_SYNTAX;
402                         }
403                 }
404
405                 if ( normf ) {
406                         /*
407                          * normalize value
408                          *      if value is empty, use empty_bv
409                          */
410                         rc = ( *normf )(
411                                 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
412                                 ad->ad_type->sat_syntax,
413                                 mr,
414                                 ava->la_value.bv_len
415                                         ? &ava->la_value
416                                         : (struct berval *) &slap_empty_bv,
417                                 &bv, ctx );
418                 
419                         if ( rc != LDAP_SUCCESS ) {
420                                 return LDAP_INVALID_SYNTAX;
421                         }
422                 }
423
424
425                 if( bv.bv_val ) {
426                         if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
427                                 ber_memfree_x( ava->la_value.bv_val, ctx );
428                         ava->la_value = bv;
429                         ava->la_flags |= LDAP_AVA_FREE_VALUE;
430                 }
431
432                 if( do_sort ) AVA_Sort( rdn, iAVA );
433         }
434         return LDAP_SUCCESS;
435 }
436
437 /*
438  * In-place, schema-aware normalization / "pretty"ing of the
439  * structural representation of a distinguished name.
440  */
441 static int
442 LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
443 {
444         int             iRDN;
445         int             rc;
446
447         assert( dn );
448
449         for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
450                 LDAPRDN         rdn = dn[ iRDN ];
451                 int             iAVA;
452
453                 assert( rdn );
454
455                 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
456                         LDAPAVA                 *ava = rdn[ iAVA ];
457                         AttributeDescription    *ad;
458                         slap_syntax_validate_func *validf = NULL;
459                         slap_mr_normalize_func *normf = NULL;
460                         slap_syntax_transform_func *transf = NULL;
461                         MatchingRule *mr = NULL;
462                         struct berval           bv = BER_BVNULL;
463                         int                     do_sort = 0;
464
465                         assert( ava );
466
467                         if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
468                                 const char      *text = NULL;
469
470                                 rc = slap_bv2ad( &ava->la_attr, &ad, &text );
471                                 if ( rc != LDAP_SUCCESS ) {
472                                         return LDAP_INVALID_SYNTAX;
473                                 }
474                                 
475                                 ava->la_private = ( void * )ad;
476                                 do_sort = 1;
477                         }
478
479                         /* 
480                          * Replace attr oid/name with the canonical name
481                          */
482                         ava->la_attr = ad->ad_cname;
483
484                         if( ava->la_flags & LDAP_AVA_BINARY ) {
485                                 if( ava->la_value.bv_len == 0 ) {
486                                         /* BER encoding is empty */
487                                         return LDAP_INVALID_SYNTAX;
488                                 }
489
490                                 /* AVA is binary encoded, don't muck with it */
491                         } else if( flags & SLAP_LDAPDN_PRETTY ) {
492                                 transf = ad->ad_type->sat_syntax->ssyn_pretty;
493                                 if( !transf ) {
494                                         validf = ad->ad_type->sat_syntax->ssyn_validate;
495                                 }
496                         } else { /* normalization */
497                                 validf = ad->ad_type->sat_syntax->ssyn_validate;
498                                 mr = ad->ad_type->sat_equality;
499                                 if( mr ) normf = mr->smr_normalize;
500                         }
501
502                         if ( validf ) {
503                                 /* validate value before normalization */
504                                 rc = ( *validf )( ad->ad_type->sat_syntax,
505                                         ava->la_value.bv_len
506                                                 ? &ava->la_value
507                                                 : (struct berval *) &slap_empty_bv );
508
509                                 if ( rc != LDAP_SUCCESS ) {
510                                         return LDAP_INVALID_SYNTAX;
511                                 }
512                         }
513
514                         if ( transf ) {
515                                 /*
516                                  * transform value by pretty function
517                                  *      if value is empty, use empty_bv
518                                  */
519                                 rc = ( *transf )( ad->ad_type->sat_syntax,
520                                         ava->la_value.bv_len
521                                                 ? &ava->la_value
522                                                 : (struct berval *) &slap_empty_bv,
523                                         &bv, ctx );
524                         
525                                 if ( rc != LDAP_SUCCESS ) {
526                                         return LDAP_INVALID_SYNTAX;
527                                 }
528                         }
529
530                         if ( normf ) {
531                                 /*
532                                  * normalize value
533                                  *      if value is empty, use empty_bv
534                                  */
535                                 rc = ( *normf )(
536                                         SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
537                                         ad->ad_type->sat_syntax,
538                                         mr,
539                                         ava->la_value.bv_len
540                                                 ? &ava->la_value
541                                                 : (struct berval *) &slap_empty_bv,
542                                         &bv, ctx );
543                         
544                                 if ( rc != LDAP_SUCCESS ) {
545                                         return LDAP_INVALID_SYNTAX;
546                                 }
547                         }
548
549
550                         if( bv.bv_val ) {
551                                 if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
552                                         ber_memfree_x( ava->la_value.bv_val, ctx );
553                                 ava->la_value = bv;
554                                 ava->la_flags |= LDAP_AVA_FREE_VALUE;
555                         }
556
557                         if( do_sort ) AVA_Sort( rdn, iAVA );
558                 }
559         }
560
561         return LDAP_SUCCESS;
562 }
563
564 int
565 dnNormalize(
566     slap_mask_t use,
567     Syntax *syntax,
568     MatchingRule *mr,
569     struct berval *val,
570     struct berval *out,
571     void *ctx)
572 {
573         assert( val );
574         assert( out );
575
576         Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
577
578         if ( val->bv_len != 0 ) {
579                 LDAPDN          dn = NULL;
580                 int             rc;
581
582                 /*
583                  * Go to structural representation
584                  */
585                 rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
586                 if ( rc != LDAP_SUCCESS ) {
587                         return LDAP_INVALID_SYNTAX;
588                 }
589
590                 assert( strlen( val->bv_val ) == val->bv_len );
591
592                 /*
593                  * Schema-aware rewrite
594                  */
595                 if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
596                         ldap_dnfree_x( dn, ctx );
597                         return LDAP_INVALID_SYNTAX;
598                 }
599
600                 /*
601                  * Back to string representation
602                  */
603                 rc = ldap_dn2bv_x( dn, out,
604                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
605
606                 ldap_dnfree_x( dn, ctx );
607
608                 if ( rc != LDAP_SUCCESS ) {
609                         return LDAP_INVALID_SYNTAX;
610                 }
611         } else {
612                 ber_dupbv_x( out, val, ctx );
613         }
614
615         Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
616
617         return LDAP_SUCCESS;
618 }
619
620 int
621 rdnNormalize(
622     slap_mask_t use,
623     Syntax *syntax,
624     MatchingRule *mr,
625     struct berval *val,
626     struct berval *out,
627     void *ctx)
628 {
629         assert( val );
630         assert( out );
631
632         Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
633         if ( val->bv_len != 0 ) {
634                 LDAPRDN         rdn = NULL;
635                 int             rc;
636                 char*           p;
637
638                 /*
639                  * Go to structural representation
640                  */
641                 rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
642                                         LDAP_DN_FORMAT_LDAP, ctx);
643
644                 if ( rc != LDAP_SUCCESS ) {
645                         return LDAP_INVALID_SYNTAX;
646                 }
647
648                 assert( strlen( val->bv_val ) == val->bv_len );
649
650                 /*
651                  * Schema-aware rewrite
652                  */
653                 if ( LDAPRDN_rewrite( rdn, 0, ctx ) != LDAP_SUCCESS ) {
654                         ldap_rdnfree_x( rdn, ctx );
655                         return LDAP_INVALID_SYNTAX;
656                 }
657
658                 /*
659                  * Back to string representation
660                  */
661                 rc = ldap_rdn2bv_x( rdn, out,
662                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
663
664                 ldap_rdnfree_x( rdn, ctx );
665
666                 if ( rc != LDAP_SUCCESS ) {
667                         return LDAP_INVALID_SYNTAX;
668                 }
669         } else {
670                 ber_dupbv_x( out, val, ctx );
671         }
672
673         Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
674
675         return LDAP_SUCCESS;
676 }
677
678 int
679 dnPretty(
680         Syntax *syntax,
681         struct berval *val,
682         struct berval *out,
683         void *ctx)
684 {
685         assert( val );
686         assert( out );
687
688         Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
689
690         if ( val->bv_len == 0 ) {
691                 ber_dupbv_x( out, val, ctx );
692
693         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
694                 return LDAP_INVALID_SYNTAX;
695
696         } else {
697                 LDAPDN          dn = NULL;
698                 int             rc;
699
700                 /* FIXME: should be liberal in what we accept */
701                 rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
702                 if ( rc != LDAP_SUCCESS ) {
703                         return LDAP_INVALID_SYNTAX;
704                 }
705
706                 assert( strlen( val->bv_val ) == val->bv_len );
707
708                 /*
709                  * Schema-aware rewrite
710                  */
711                 if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
712                         ldap_dnfree_x( dn, ctx );
713                         return LDAP_INVALID_SYNTAX;
714                 }
715
716                 /* FIXME: not sure why the default isn't pretty */
717                 /* RE: the default is the form that is used as
718                  * an internal representation; the pretty form
719                  * is a variant */
720                 rc = ldap_dn2bv_x( dn, out,
721                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
722
723                 ldap_dnfree_x( dn, ctx );
724
725                 if ( rc != LDAP_SUCCESS ) {
726                         return LDAP_INVALID_SYNTAX;
727                 }
728         }
729
730         Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
731
732         return LDAP_SUCCESS;
733 }
734
735 int
736 rdnPretty(
737         Syntax *syntax,
738         struct berval *val,
739         struct berval *out,
740         void *ctx)
741 {
742         assert( val );
743         assert( out );
744
745         Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
746
747         if ( val->bv_len == 0 ) {
748                 ber_dupbv_x( out, val, ctx );
749
750         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
751                 return LDAP_INVALID_SYNTAX;
752
753         } else {
754                 LDAPRDN         rdn = NULL;
755                 int             rc;
756                 char*           p;
757
758                 /* FIXME: should be liberal in what we accept */
759                 rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
760                                         LDAP_DN_FORMAT_LDAP, ctx);
761                 if ( rc != LDAP_SUCCESS ) {
762                         return LDAP_INVALID_SYNTAX;
763                 }
764
765                 assert( strlen( val->bv_val ) == val->bv_len );
766
767                 /*
768                  * Schema-aware rewrite
769                  */
770                 if ( LDAPRDN_rewrite( rdn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
771                         ldap_rdnfree_x( rdn, ctx );
772                         return LDAP_INVALID_SYNTAX;
773                 }
774
775                 /* FIXME: not sure why the default isn't pretty */
776                 /* RE: the default is the form that is used as
777                  * an internal representation; the pretty form
778                  * is a variant */
779                 rc = ldap_rdn2bv_x( rdn, out,
780                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
781
782                 ldap_rdnfree_x( rdn, ctx );
783
784                 if ( rc != LDAP_SUCCESS ) {
785                         return LDAP_INVALID_SYNTAX;
786                 }
787         }
788
789         Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
790
791         return LDAP_SUCCESS;
792 }
793
794
795 int
796 dnPrettyNormalDN(
797         Syntax *syntax,
798         struct berval *val,
799         LDAPDN *dn,
800         int flags,
801         void *ctx )
802 {
803         assert( val );
804         assert( dn );
805
806         Debug( LDAP_DEBUG_TRACE, ">>> dn%sDN: <%s>\n", 
807                         flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
808                         val->bv_val, 0 );
809
810         if ( val->bv_len == 0 ) {
811                 return LDAP_SUCCESS;
812
813         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
814                 return LDAP_INVALID_SYNTAX;
815
816         } else {
817                 int             rc;
818
819                 /* FIXME: should be liberal in what we accept */
820                 rc = ldap_bv2dn_x( val, dn, LDAP_DN_FORMAT_LDAP, ctx );
821                 if ( rc != LDAP_SUCCESS ) {
822                         return LDAP_INVALID_SYNTAX;
823                 }
824
825                 assert( strlen( val->bv_val ) == val->bv_len );
826
827                 /*
828                  * Schema-aware rewrite
829                  */
830                 if ( LDAPDN_rewrite( *dn, flags, ctx ) != LDAP_SUCCESS ) {
831                         ldap_dnfree_x( *dn, ctx );
832                         *dn = NULL;
833                         return LDAP_INVALID_SYNTAX;
834                 }
835         }
836
837         Debug( LDAP_DEBUG_TRACE, "<<< dn%sDN\n", 
838                         flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal",
839                         0, 0 );
840
841         return LDAP_SUCCESS;
842 }
843
844 /*
845  * Combination of both dnPretty and dnNormalize
846  */
847 int
848 dnPrettyNormal(
849         Syntax *syntax,
850         struct berval *val,
851         struct berval *pretty,
852         struct berval *normal,
853         void *ctx)
854 {
855         Debug( LDAP_DEBUG_TRACE, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 );
856
857         assert( val );
858         assert( pretty );
859         assert( normal );
860
861         if ( val->bv_len == 0 ) {
862                 ber_dupbv_x( pretty, val, ctx );
863                 ber_dupbv_x( normal, val, ctx );
864
865         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
866                 /* too big */
867                 return LDAP_INVALID_SYNTAX;
868
869         } else {
870                 LDAPDN          dn = NULL;
871                 int             rc;
872
873                 pretty->bv_val = NULL;
874                 normal->bv_val = NULL;
875                 pretty->bv_len = 0;
876                 normal->bv_len = 0;
877
878                 /* FIXME: should be liberal in what we accept */
879                 rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
880                 if ( rc != LDAP_SUCCESS ) {
881                         return LDAP_INVALID_SYNTAX;
882                 }
883
884                 assert( strlen( val->bv_val ) == val->bv_len );
885
886                 /*
887                  * Schema-aware rewrite
888                  */
889                 if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
890                         ldap_dnfree_x( dn, ctx );
891                         return LDAP_INVALID_SYNTAX;
892                 }
893
894                 rc = ldap_dn2bv_x( dn, pretty,
895                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
896
897                 if ( rc != LDAP_SUCCESS ) {
898                         ldap_dnfree_x( dn, ctx );
899                         return LDAP_INVALID_SYNTAX;
900                 }
901
902                 if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
903                         ldap_dnfree_x( dn, ctx );
904                         ber_memfree_x( pretty->bv_val, ctx );
905                         pretty->bv_val = NULL;
906                         pretty->bv_len = 0;
907                         return LDAP_INVALID_SYNTAX;
908                 }
909
910                 rc = ldap_dn2bv_x( dn, normal,
911                         LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
912
913                 ldap_dnfree_x( dn, ctx );
914                 if ( rc != LDAP_SUCCESS ) {
915                         ber_memfree_x( pretty->bv_val, ctx );
916                         pretty->bv_val = NULL;
917                         pretty->bv_len = 0;
918                         return LDAP_INVALID_SYNTAX;
919                 }
920         }
921
922         Debug( LDAP_DEBUG_TRACE, "<<< dnPrettyNormal: <%s>, <%s>\n",
923                 pretty->bv_val, normal->bv_val, 0 );
924
925         return LDAP_SUCCESS;
926 }
927
928 /*
929  * dnMatch routine
930  */
931 int
932 dnMatch(
933         int *matchp,
934         slap_mask_t flags,
935         Syntax *syntax,
936         MatchingRule *mr,
937         struct berval *value,
938         void *assertedValue )
939 {
940         int match;
941         struct berval *asserted = (struct berval *) assertedValue;
942
943         assert( matchp );
944         assert( value );
945         assert( assertedValue );
946         assert( !BER_BVISNULL( value ) );
947         assert( !BER_BVISNULL( asserted ) );
948         
949         match = value->bv_len - asserted->bv_len;
950
951         if ( match == 0 ) {
952                 match = memcmp( value->bv_val, asserted->bv_val, 
953                                 value->bv_len );
954         }
955
956         Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
957                 match, value->bv_val, asserted->bv_val );
958
959         *matchp = match;
960         return LDAP_SUCCESS;
961 }
962
963 /*
964  * dnRelativeMatch routine
965  */
966 int
967 dnRelativeMatch(
968         int *matchp,
969         slap_mask_t flags,
970         Syntax *syntax,
971         MatchingRule *mr,
972         struct berval *value,
973         void *assertedValue )
974 {
975         int match;
976         struct berval *asserted = (struct berval *) assertedValue;
977
978         assert( matchp );
979         assert( value );
980         assert( assertedValue );
981         assert( !BER_BVISNULL( value ) );
982         assert( !BER_BVISNULL( asserted ) );
983
984         if( mr == slap_schema.si_mr_dnSubtreeMatch ) {
985                 if( asserted->bv_len > value->bv_len ) {
986                         match = -1;
987                 } else if ( asserted->bv_len == value->bv_len ) {
988                         match = memcmp( value->bv_val, asserted->bv_val, 
989                                 value->bv_len );
990                 } else {
991                         if( DN_SEPARATOR(
992                                 value->bv_val[value->bv_len - asserted->bv_len - 1] ))
993                         {
994                                 match = memcmp(
995                                         &value->bv_val[value->bv_len - asserted->bv_len],
996                                         asserted->bv_val, 
997                                         asserted->bv_len );
998                         } else {
999                                 return 1;
1000                         }
1001                 }
1002
1003                 *matchp = match;
1004                 return LDAP_SUCCESS;
1005
1006         }
1007
1008         if( mr == slap_schema.si_mr_dnSuperiorMatch ) {
1009                 asserted = value;
1010                 value = (struct berval *) assertedValue;
1011                 mr = slap_schema.si_mr_dnSubordinateMatch;
1012         }
1013
1014         if( mr == slap_schema.si_mr_dnSubordinateMatch ) {
1015                 if( asserted->bv_len >= value->bv_len ) {
1016                         match = -1;
1017                 } else {
1018                         if( DN_SEPARATOR(
1019                                 value->bv_val[value->bv_len - asserted->bv_len - 1] ))
1020                         {
1021                                 match = memcmp(
1022                                         &value->bv_val[value->bv_len - asserted->bv_len],
1023                                         asserted->bv_val, 
1024                                         asserted->bv_len );
1025                         } else {
1026                                 return 1;
1027                         }
1028                 }
1029
1030                 *matchp = match;
1031                 return LDAP_SUCCESS;
1032         }
1033
1034         if( mr == slap_schema.si_mr_dnOneLevelMatch ) {
1035                 if( asserted->bv_len >= value->bv_len ) {
1036                         match = -1;
1037                 } else {
1038                         if( DN_SEPARATOR(
1039                                 value->bv_val[value->bv_len - asserted->bv_len - 1] ))
1040                         {
1041                                 match = memcmp(
1042                                         &value->bv_val[value->bv_len - asserted->bv_len],
1043                                         asserted->bv_val, 
1044                                         asserted->bv_len );
1045
1046                                 if( !match ) {
1047                                         struct berval rdn;
1048                                         rdn.bv_val = value->bv_val;
1049                                         rdn.bv_len = value->bv_len - asserted->bv_len - 1;
1050                                         match = dnIsOneLevelRDN( &rdn ) ? 0 : 1;
1051                                 }
1052                         } else {
1053                                 return 1;
1054                         }
1055                 }
1056
1057                 *matchp = match;
1058                 return LDAP_SUCCESS;
1059         }
1060
1061         /* should not be reachable */
1062         assert( 0 );
1063         return LDAP_OTHER;
1064 }
1065
1066 int
1067 rdnMatch(
1068         int *matchp,
1069         slap_mask_t flags,
1070         Syntax *syntax,
1071         MatchingRule *mr,
1072         struct berval *value,
1073         void *assertedValue )
1074 {
1075         int match;
1076         struct berval *asserted = (struct berval *) assertedValue;
1077
1078         assert( matchp );
1079         assert( value );
1080         assert( assertedValue );
1081         
1082         match = value->bv_len - asserted->bv_len;
1083
1084         if ( match == 0 ) {
1085                 match = memcmp( value->bv_val, asserted->bv_val, 
1086                                 value->bv_len );
1087         }
1088
1089         Debug( LDAP_DEBUG_ARGS, "rdnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
1090                 match, value->bv_val, asserted->bv_val );
1091
1092         *matchp = match;
1093         return LDAP_SUCCESS;
1094 }
1095
1096
1097 /*
1098  * dnParent - dn's parent, in-place
1099  * note: the incoming dn is assumed to be normalized/prettyfied,
1100  * so that escaped rdn/ava separators are in '\'+hexpair form
1101  */
1102 void
1103 dnParent( 
1104         struct berval   *dn, 
1105         struct berval   *pdn )
1106 {
1107         char    *p;
1108
1109         p = strchr( dn->bv_val, ',' );
1110
1111         /* one-level dn */
1112         if ( p == NULL ) {
1113                 pdn->bv_len = 0;
1114                 pdn->bv_val = dn->bv_val + dn->bv_len;
1115                 return;
1116         }
1117
1118         assert( DN_SEPARATOR( p[ 0 ] ) );
1119         p++;
1120
1121         assert( ATTR_LEADCHAR( p[ 0 ] ) );
1122         pdn->bv_val = p;
1123         pdn->bv_len = dn->bv_len - (p - dn->bv_val);
1124
1125         return;
1126 }
1127
1128 /*
1129  * dnRdn - dn's rdn, in-place
1130  * note: the incoming dn is assumed to be normalized/prettyfied,
1131  * so that escaped rdn/ava separators are in '\'+hexpair form
1132  */
1133 void
1134 dnRdn( 
1135         struct berval   *dn, 
1136         struct berval   *rdn )
1137 {
1138         char    *p;
1139
1140         *rdn = *dn;
1141         p = strchr( dn->bv_val, ',' );
1142
1143         /* one-level dn */
1144         if ( p == NULL ) {
1145                 return;
1146         }
1147
1148         assert( DN_SEPARATOR( p[ 0 ] ) );
1149         assert( ATTR_LEADCHAR( p[ 1 ] ) );
1150         rdn->bv_len = p - dn->bv_val;
1151
1152         return;
1153 }
1154
1155 int
1156 dnExtractRdn( 
1157         struct berval   *dn, 
1158         struct berval   *rdn,
1159         void *ctx )
1160 {
1161         LDAPRDN         tmpRDN;
1162         const char      *p;
1163         int             rc;
1164
1165         assert( dn );
1166         assert( rdn );
1167
1168         if( dn->bv_len == 0 ) {
1169                 return LDAP_OTHER;
1170         }
1171
1172         rc = ldap_bv2rdn_x( dn, &tmpRDN, (char **)&p, LDAP_DN_FORMAT_LDAP, ctx );
1173         if ( rc != LDAP_SUCCESS ) {
1174                 return rc;
1175         }
1176
1177         rc = ldap_rdn2bv_x( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY,
1178                 ctx );
1179
1180         ldap_rdnfree_x( tmpRDN, ctx );
1181         return rc;
1182 }
1183
1184 /*
1185  * We can assume the input is a prettied or normalized DN
1186  */
1187 int 
1188 dn_rdnlen(
1189         Backend         *be,
1190         struct berval   *dn_in )
1191 {
1192         const char      *p;
1193
1194         assert( dn_in );
1195
1196         if ( dn_in == NULL ) {
1197                 return 0;
1198         }
1199
1200         if ( !dn_in->bv_len ) {
1201                 return 0;
1202         }
1203
1204         if ( be != NULL && be_issuffix( be, dn_in ) ) {
1205                 return 0;
1206         }
1207
1208         p = strchr( dn_in->bv_val, ',' );
1209
1210         return p ? p - dn_in->bv_val : dn_in->bv_len;
1211 }
1212
1213
1214 /* rdnValidate:
1215  *
1216  * LDAP_SUCCESS if rdn is a legal rdn;
1217  * LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
1218  */
1219 int
1220 rdn_validate( struct berval *rdn )
1221 {
1222 #if 1
1223         /* Major cheat!
1224          * input is a pretty or normalized DN
1225          * hence, we can just search for ','
1226          */
1227         if( rdn == NULL || rdn->bv_len == 0 ||
1228                 rdn->bv_len > SLAP_LDAPDN_MAXLEN )
1229         {
1230                 return LDAP_INVALID_SYNTAX;
1231         }
1232         return strchr( rdn->bv_val, ',' ) == NULL
1233                 ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
1234
1235 #else
1236         LDAPRDN         *RDN, **DN[ 2 ] = { &RDN, NULL };
1237         const char      *p;
1238         int             rc;
1239
1240         /*
1241          * must be non-empty
1242          */
1243         if ( rdn == NULL || rdn == '\0' ) {
1244                 return 0;
1245         }
1246
1247         /*
1248          * must be parsable
1249          */
1250         rc = ldap_bv2rdn( rdn, &RDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
1251         if ( rc != LDAP_SUCCESS ) {
1252                 return 0;
1253         }
1254
1255         /*
1256          * Must be one-level
1257          */
1258         if ( p[ 0 ] != '\0' ) {
1259                 return 0;
1260         }
1261
1262         /*
1263          * Schema-aware validate
1264          */
1265         if ( rc == LDAP_SUCCESS ) {
1266                 rc = LDAPDN_validate( DN );
1267         }
1268         ldap_rdnfree( RDN );
1269
1270         /*
1271          * Must validate (there's a repeated parsing ...)
1272          */
1273         return ( rc == LDAP_SUCCESS );
1274 #endif
1275 }
1276
1277
1278 /* build_new_dn:
1279  *
1280  * Used by ldbm/bdb2 back_modrdn to create the new dn of entries being
1281  * renamed.
1282  *
1283  * new_dn = parent (p_dn) + separator + rdn (newrdn) + null.
1284  */
1285
1286 void
1287 build_new_dn( struct berval * new_dn,
1288         struct berval * parent_dn,
1289         struct berval * newrdn,
1290         void *memctx )
1291 {
1292         char *ptr;
1293
1294         if ( parent_dn == NULL || parent_dn->bv_len == 0 ) {
1295                 ber_dupbv( new_dn, newrdn );
1296                 return;
1297         }
1298
1299         new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
1300         new_dn->bv_val = (char *) slap_sl_malloc( new_dn->bv_len + 1, memctx );
1301
1302         ptr = lutil_strncopy( new_dn->bv_val, newrdn->bv_val, newrdn->bv_len );
1303         *ptr++ = ',';
1304         strcpy( ptr, parent_dn->bv_val );
1305 }
1306
1307
1308 /*
1309  * dnIsSuffix - tells whether suffix is a suffix of dn.
1310  * Both dn and suffix must be normalized.
1311  */
1312 int
1313 dnIsSuffix(
1314         const struct berval *dn,
1315         const struct berval *suffix )
1316 {
1317         int     d = dn->bv_len - suffix->bv_len;
1318
1319         assert( dn );
1320         assert( suffix );
1321
1322         /* empty suffix matches any dn */
1323         if ( suffix->bv_len == 0 ) {
1324                 return 1;
1325         }
1326
1327         /* suffix longer than dn */
1328         if ( d < 0 ) {
1329                 return 0;
1330         }
1331
1332         /* no rdn separator or escaped rdn separator */
1333         if ( d > 1 && !DN_SEPARATOR( dn->bv_val[ d - 1 ] ) ) {
1334                 return 0;
1335         }
1336
1337         /* no possible match or malformed dn */
1338         if ( d == 1 ) {
1339                 return 0;
1340         }
1341
1342         /* compare */
1343         return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 );
1344 }
1345
1346 int
1347 dnIsOneLevelRDN( struct berval *rdn )
1348 {
1349         ber_len_t       len = rdn->bv_len;
1350         for ( ; len--; ) {
1351                 if ( DN_SEPARATOR( rdn->bv_val[ len ] ) ) {
1352                         return 0;
1353                 }
1354         }
1355
1356         return 1;
1357 }
1358
1359 #ifdef HAVE_TLS
1360 static SLAP_CERT_MAP_FN *DNX509PeerNormalizeCertMap = NULL;
1361 #endif
1362
1363 int register_certificate_map_function(SLAP_CERT_MAP_FN *fn)
1364 {
1365 #ifdef HAVE_TLS
1366         if ( DNX509PeerNormalizeCertMap == NULL ) {
1367                 DNX509PeerNormalizeCertMap = fn;
1368                 return 0;
1369         }
1370 #endif
1371
1372         return -1;
1373 }
1374
1375 #ifdef HAVE_TLS
1376 /*
1377  * Convert an X.509 DN into a normalized LDAP DN
1378  */
1379 int
1380 dnX509normalize( void *x509_name, struct berval *out )
1381 {
1382         /* Invoke the LDAP library's converter with our schema-rewriter */
1383         int rc = ldap_X509dn2bv( x509_name, out, LDAPDN_rewrite, 0 );
1384
1385         Debug( LDAP_DEBUG_TRACE,
1386                 "dnX509Normalize: <%s>\n", out->bv_val, 0, 0 );
1387
1388         return rc;
1389 }
1390
1391 /*
1392  * Get the TLS session's peer's DN into a normalized LDAP DN
1393  */
1394 int
1395 dnX509peerNormalize( void *ssl, struct berval *dn )
1396 {
1397         int rc = LDAP_INVALID_CREDENTIALS;
1398
1399         if ( DNX509PeerNormalizeCertMap != NULL )
1400                 rc = (*DNX509PeerNormalizeCertMap)( ssl, dn );
1401
1402         if ( rc != LDAP_SUCCESS ) {
1403                 rc = ldap_pvt_tls_get_peer_dn( ssl, dn,
1404                         (LDAPDN_rewrite_dummy *)LDAPDN_rewrite, 0 );
1405         }
1406
1407         return rc;
1408 }
1409 #endif