]> git.sur5r.net Git - openldap/blob - servers/slapd/dn.c
cleanup
[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         if( mr == slap_schema.si_mr_dnSuperiorMatch ) {
1008                 asserted = value;
1009                 value = (struct berval *) assertedValue;
1010                 mr = slap_schema.si_mr_dnSubordinateMatch;
1011         }
1012
1013         if( mr == slap_schema.si_mr_dnSubordinateMatch ) {
1014                 if( asserted->bv_len >= value->bv_len ) {
1015                         match = -1;
1016                 } else {
1017                         if( DN_SEPARATOR(
1018                                 value->bv_val[value->bv_len - asserted->bv_len - 1] ))
1019                         {
1020                                 match = memcmp(
1021                                         &value->bv_val[value->bv_len - asserted->bv_len],
1022                                         asserted->bv_val, 
1023                                         asserted->bv_len );
1024                         } else {
1025                                 return 1;
1026                         }
1027                 }
1028
1029                 *matchp = match;
1030                 return LDAP_SUCCESS;
1031         }
1032
1033         if( mr == slap_schema.si_mr_dnOneLevelMatch ) {
1034                 if( asserted->bv_len >= value->bv_len ) {
1035                         match = -1;
1036                 } else {
1037                         if( DN_SEPARATOR(
1038                                 value->bv_val[value->bv_len - asserted->bv_len - 1] ))
1039                         {
1040                                 match = memcmp(
1041                                         &value->bv_val[value->bv_len - asserted->bv_len],
1042                                         asserted->bv_val, 
1043                                         asserted->bv_len );
1044
1045                                 if( !match ) {
1046                                         struct berval rdn;
1047                                         rdn.bv_val = value->bv_val;
1048                                         rdn.bv_len = value->bv_len - asserted->bv_len - 1;
1049                                         match = dnIsOneLevelRDN( &rdn ) ? 0 : 1;
1050                                 }
1051                         } else {
1052                                 return 1;
1053                         }
1054                 }
1055
1056                 *matchp = match;
1057                 return LDAP_SUCCESS;
1058         }
1059
1060         /* should not be reachable */
1061         assert( 0 );
1062         return LDAP_OTHER;
1063 }
1064
1065 int
1066 rdnMatch(
1067         int *matchp,
1068         slap_mask_t flags,
1069         Syntax *syntax,
1070         MatchingRule *mr,
1071         struct berval *value,
1072         void *assertedValue )
1073 {
1074         int match;
1075         struct berval *asserted = (struct berval *) assertedValue;
1076
1077         assert( matchp );
1078         assert( value );
1079         assert( assertedValue );
1080         
1081         match = value->bv_len - asserted->bv_len;
1082
1083         if ( match == 0 ) {
1084                 match = memcmp( value->bv_val, asserted->bv_val, 
1085                                 value->bv_len );
1086         }
1087
1088         Debug( LDAP_DEBUG_ARGS, "rdnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
1089                 match, value->bv_val, asserted->bv_val );
1090
1091         *matchp = match;
1092         return LDAP_SUCCESS;
1093 }
1094
1095
1096 /*
1097  * dnParent - dn's parent, in-place
1098  * note: the incoming dn is assumed to be normalized/prettyfied,
1099  * so that escaped rdn/ava separators are in '\'+hexpair form
1100  */
1101 void
1102 dnParent( 
1103         struct berval   *dn, 
1104         struct berval   *pdn )
1105 {
1106         char    *p;
1107
1108         p = strchr( dn->bv_val, ',' );
1109
1110         /* one-level dn */
1111         if ( p == NULL ) {
1112                 pdn->bv_len = 0;
1113                 pdn->bv_val = dn->bv_val + dn->bv_len;
1114                 return;
1115         }
1116
1117         assert( DN_SEPARATOR( p[ 0 ] ) );
1118         p++;
1119
1120         assert( ATTR_LEADCHAR( p[ 0 ] ) );
1121         pdn->bv_val = p;
1122         pdn->bv_len = dn->bv_len - (p - dn->bv_val);
1123
1124         return;
1125 }
1126
1127 /*
1128  * dnRdn - dn's rdn, in-place
1129  * note: the incoming dn is assumed to be normalized/prettyfied,
1130  * so that escaped rdn/ava separators are in '\'+hexpair form
1131  */
1132 void
1133 dnRdn( 
1134         struct berval   *dn, 
1135         struct berval   *rdn )
1136 {
1137         char    *p;
1138
1139         *rdn = *dn;
1140         p = strchr( dn->bv_val, ',' );
1141
1142         /* one-level dn */
1143         if ( p == NULL ) {
1144                 return;
1145         }
1146
1147         assert( DN_SEPARATOR( p[ 0 ] ) );
1148         assert( ATTR_LEADCHAR( p[ 1 ] ) );
1149         rdn->bv_len = p - dn->bv_val;
1150
1151         return;
1152 }
1153
1154 int
1155 dnExtractRdn( 
1156         struct berval   *dn, 
1157         struct berval   *rdn,
1158         void *ctx )
1159 {
1160         LDAPRDN         tmpRDN;
1161         const char      *p;
1162         int             rc;
1163
1164         assert( dn );
1165         assert( rdn );
1166
1167         if( dn->bv_len == 0 ) {
1168                 return LDAP_OTHER;
1169         }
1170
1171         rc = ldap_bv2rdn_x( dn, &tmpRDN, (char **)&p, LDAP_DN_FORMAT_LDAP, ctx );
1172         if ( rc != LDAP_SUCCESS ) {
1173                 return rc;
1174         }
1175
1176         rc = ldap_rdn2bv_x( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY,
1177                 ctx );
1178
1179         ldap_rdnfree_x( tmpRDN, ctx );
1180         return rc;
1181 }
1182
1183 /*
1184  * We can assume the input is a prettied or normalized DN
1185  */
1186 int 
1187 dn_rdnlen(
1188         Backend         *be,
1189         struct berval   *dn_in )
1190 {
1191         const char      *p;
1192
1193         assert( dn_in );
1194
1195         if ( dn_in == NULL ) {
1196                 return 0;
1197         }
1198
1199         if ( !dn_in->bv_len ) {
1200                 return 0;
1201         }
1202
1203         if ( be != NULL && be_issuffix( be, dn_in ) ) {
1204                 return 0;
1205         }
1206
1207         p = strchr( dn_in->bv_val, ',' );
1208
1209         return p ? p - dn_in->bv_val : dn_in->bv_len;
1210 }
1211
1212
1213 /* rdnValidate:
1214  *
1215  * LDAP_SUCCESS if rdn is a legal rdn;
1216  * LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
1217  */
1218 int
1219 rdn_validate( struct berval *rdn )
1220 {
1221 #if 1
1222         /* Major cheat!
1223          * input is a pretty or normalized DN
1224          * hence, we can just search for ','
1225          */
1226         if( rdn == NULL || rdn->bv_len == 0 ||
1227                 rdn->bv_len > SLAP_LDAPDN_MAXLEN )
1228         {
1229                 return LDAP_INVALID_SYNTAX;
1230         }
1231         return strchr( rdn->bv_val, ',' ) == NULL
1232                 ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
1233
1234 #else
1235         LDAPRDN         *RDN, **DN[ 2 ] = { &RDN, NULL };
1236         const char      *p;
1237         int             rc;
1238
1239         /*
1240          * must be non-empty
1241          */
1242         if ( rdn == NULL || rdn == '\0' ) {
1243                 return 0;
1244         }
1245
1246         /*
1247          * must be parsable
1248          */
1249         rc = ldap_bv2rdn( rdn, &RDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
1250         if ( rc != LDAP_SUCCESS ) {
1251                 return 0;
1252         }
1253
1254         /*
1255          * Must be one-level
1256          */
1257         if ( p[ 0 ] != '\0' ) {
1258                 return 0;
1259         }
1260
1261         /*
1262          * Schema-aware validate
1263          */
1264         if ( rc == LDAP_SUCCESS ) {
1265                 rc = LDAPDN_validate( DN );
1266         }
1267         ldap_rdnfree( RDN );
1268
1269         /*
1270          * Must validate (there's a repeated parsing ...)
1271          */
1272         return ( rc == LDAP_SUCCESS );
1273 #endif
1274 }
1275
1276
1277 /* build_new_dn:
1278  *
1279  * Used by ldbm/bdb2 back_modrdn to create the new dn of entries being
1280  * renamed.
1281  *
1282  * new_dn = parent (p_dn) + separator + rdn (newrdn) + null.
1283  */
1284
1285 void
1286 build_new_dn( struct berval * new_dn,
1287         struct berval * parent_dn,
1288         struct berval * newrdn,
1289         void *memctx )
1290 {
1291         char *ptr;
1292
1293         if ( parent_dn == NULL || parent_dn->bv_len == 0 ) {
1294                 ber_dupbv( new_dn, newrdn );
1295                 return;
1296         }
1297
1298         new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
1299         new_dn->bv_val = (char *) slap_sl_malloc( new_dn->bv_len + 1, memctx );
1300
1301         ptr = lutil_strncopy( new_dn->bv_val, newrdn->bv_val, newrdn->bv_len );
1302         *ptr++ = ',';
1303         strcpy( ptr, parent_dn->bv_val );
1304 }
1305
1306
1307 /*
1308  * dnIsSuffix - tells whether suffix is a suffix of dn.
1309  * Both dn and suffix must be normalized.
1310  */
1311 int
1312 dnIsSuffix(
1313         const struct berval *dn,
1314         const struct berval *suffix )
1315 {
1316         int     d = dn->bv_len - suffix->bv_len;
1317
1318         assert( dn );
1319         assert( suffix );
1320
1321         /* empty suffix matches any dn */
1322         if ( suffix->bv_len == 0 ) {
1323                 return 1;
1324         }
1325
1326         /* suffix longer than dn */
1327         if ( d < 0 ) {
1328                 return 0;
1329         }
1330
1331         /* no rdn separator or escaped rdn separator */
1332         if ( d > 1 && !DN_SEPARATOR( dn->bv_val[ d - 1 ] ) ) {
1333                 return 0;
1334         }
1335
1336         /* no possible match or malformed dn */
1337         if ( d == 1 ) {
1338                 return 0;
1339         }
1340
1341         /* compare */
1342         return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 );
1343 }
1344
1345 int
1346 dnIsOneLevelRDN( struct berval *rdn )
1347 {
1348         ber_len_t       len = rdn->bv_len;
1349         for ( ; len--; ) {
1350                 if ( DN_SEPARATOR( rdn->bv_val[ len ] ) ) {
1351                         return 0;
1352                 }
1353         }
1354
1355         return 1;
1356 }
1357
1358 #ifdef HAVE_TLS
1359 static SLAP_CERT_MAP_FN *DNX509PeerNormalizeCertMap = NULL;
1360 #endif
1361
1362 int register_certificate_map_function(SLAP_CERT_MAP_FN *fn)
1363 {
1364 #ifdef HAVE_TLS
1365         if ( DNX509PeerNormalizeCertMap == NULL ) {
1366                 DNX509PeerNormalizeCertMap = fn;
1367                 return 0;
1368         }
1369 #endif
1370
1371         return -1;
1372 }
1373
1374 #ifdef HAVE_TLS
1375 /*
1376  * Convert an X.509 DN into a normalized LDAP DN
1377  */
1378 int
1379 dnX509normalize( void *x509_name, struct berval *out )
1380 {
1381         /* Invoke the LDAP library's converter with our schema-rewriter */
1382         int rc = ldap_X509dn2bv( x509_name, out, LDAPDN_rewrite, 0 );
1383
1384         Debug( LDAP_DEBUG_TRACE,
1385                 "dnX509Normalize: <%s>\n", out->bv_val, 0, 0 );
1386
1387         return rc;
1388 }
1389
1390 /*
1391  * Get the TLS session's peer's DN into a normalized LDAP DN
1392  */
1393 int
1394 dnX509peerNormalize( void *ssl, struct berval *dn )
1395 {
1396         int rc = LDAP_INVALID_CREDENTIALS;
1397
1398         if ( DNX509PeerNormalizeCertMap != NULL )
1399                 rc = (*DNX509PeerNormalizeCertMap)( ssl, dn );
1400
1401         if ( rc != LDAP_SUCCESS ) {
1402                 rc = ldap_pvt_tls_get_peer_dn( ssl, dn,
1403                         (LDAPDN_rewrite_dummy *)LDAPDN_rewrite, 0 );
1404         }
1405
1406         return rc;
1407 }
1408 #endif