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