]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/dn.c
rework op/rs structures to deal with opeartional attributes
[openldap] / servers / slapd / dn.c
index b02680096c0d29389241160486b15be2ea8daff3..44528fa2f63271998e13026268bcd5bc3dc4fb24 100644 (file)
@@ -1,8 +1,27 @@
 /* dn.c - routines for dealing with distinguished names */
 /* $OpenLDAP$ */
-/*
- * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2004 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
  */
 
 #include "portable.h"
 #include <ac/string.h>
 #include <ac/time.h>
 
-#include "ldap_pvt.h"
-
 #include "slap.h"
-
+#include "ldap_pvt.h" /* must be after slap.h, to get ldap_bv2dn_x() & co */
 #include "lutil.h"
 
 /*
 
 #define        AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private )
 
+static int
+LDAPRDN_validate( LDAPRDN rdn )
+{
+       int             iAVA;
+       int             rc;
+
+       assert( rdn );
+
+       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+               LDAPAVA                 *ava = rdn[ iAVA ];
+               AttributeDescription    *ad;
+               slap_syntax_validate_func *validate = NULL;
+
+               assert( ava );
+               
+               if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
+                       const char      *text = NULL;
+
+                       rc = slap_bv2ad( &ava->la_attr, &ad, &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+                       ava->la_private = ( void * )ad;
+               }
+
+               /* 
+                * Replace attr oid/name with the canonical name
+                */
+               ava->la_attr = ad->ad_cname;
+
+               validate = ad->ad_type->sat_syntax->ssyn_validate;
+
+               if ( validate ) {
+                       /*
+                        * validate value by validate function
+                        */
+                       rc = ( *validate )( ad->ad_type->sat_syntax,
+                               &ava->la_value );
+                       
+                       if ( rc != LDAP_SUCCESS ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
 /*
  * In-place, schema-aware validation of the
  * structural representation of a distinguished name.
@@ -137,6 +203,45 @@ dnValidate(
        return LDAP_SUCCESS;
 }
 
+int
+rdnValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       int             rc;
+       LDAPRDN         rdn;
+       char*           p;
+
+       assert( in );
+       if ( in->bv_len == 0 ) {
+               return LDAP_SUCCESS;
+
+       } else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       rc = ldap_bv2rdn_x( in , &rdn, (char **) &p,
+                               LDAP_DN_FORMAT_LDAP, NULL);
+       if ( rc != LDAP_SUCCESS ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       assert( strlen( in->bv_val ) == in->bv_len );
+
+       /*
+        * Schema-aware validate
+        */
+       rc = LDAPRDN_validate( rdn );
+       ldap_rdnfree( rdn );
+
+       if ( rc != LDAP_SUCCESS ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+
 /*
  * AVA sorting inside a RDN
  *
@@ -217,6 +322,119 @@ AVA_Sort( LDAPRDN rdn, int iAVA )
        }
 }
 
+static int
+LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
+{
+
+       int rc;
+       int             iAVA;
+       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+               LDAPAVA                 *ava = rdn[ iAVA ];
+               AttributeDescription    *ad;
+               slap_syntax_validate_func *validf = NULL;
+               slap_mr_normalize_func *normf = NULL;
+               slap_syntax_transform_func *transf = NULL;
+               MatchingRule *mr = NULL;
+               struct berval           bv = BER_BVNULL;
+               int                     do_sort = 0;
+
+               assert( ava );
+
+               if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
+                       const char      *text = NULL;
+
+                       rc = slap_bv2ad( &ava->la_attr, &ad, &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+                       
+                       ava->la_private = ( void * )ad;
+                       do_sort = 1;
+               }
+
+               /* 
+                * Replace attr oid/name with the canonical name
+                */
+               ava->la_attr = ad->ad_cname;
+
+               if( ava->la_flags & LDAP_AVA_BINARY ) {
+                       if( ava->la_value.bv_len == 0 ) {
+                               /* BER encoding is empty */
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+                       /* AVA is binary encoded, don't muck with it */
+               } else if( flags & SLAP_LDAPDN_PRETTY ) {
+                       transf = ad->ad_type->sat_syntax->ssyn_pretty;
+                       if( !transf ) {
+                               validf = ad->ad_type->sat_syntax->ssyn_validate;
+                       }
+               } else { /* normalization */
+                       validf = ad->ad_type->sat_syntax->ssyn_validate;
+                       mr = ad->ad_type->sat_equality;
+                       if( mr ) normf = mr->smr_normalize;
+               }
+
+               if ( validf ) {
+                       /* validate value before normalization */
+                       rc = ( *validf )( ad->ad_type->sat_syntax,
+                               ava->la_value.bv_len
+                                       ? &ava->la_value
+                                       : (struct berval *) &slap_empty_bv );
+
+                       if ( rc != LDAP_SUCCESS ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+               }
+
+               if ( transf ) {
+                       /*
+                        * transform value by pretty function
+                        *      if value is empty, use empty_bv
+                        */
+                       rc = ( *transf )( ad->ad_type->sat_syntax,
+                               ava->la_value.bv_len
+                                       ? &ava->la_value
+                                       : (struct berval *) &slap_empty_bv,
+                               &bv, ctx );
+               
+                       if ( rc != LDAP_SUCCESS ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+               }
+
+               if ( normf ) {
+                       /*
+                        * normalize value
+                        *      if value is empty, use empty_bv
+                        */
+                       rc = ( *normf )(
+                               SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
+                               ad->ad_type->sat_syntax,
+                               mr,
+                               ava->la_value.bv_len
+                                       ? &ava->la_value
+                                       : (struct berval *) &slap_empty_bv,
+                               &bv, ctx );
+               
+                       if ( rc != LDAP_SUCCESS ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+               }
+
+
+               if( bv.bv_val ) {
+                       if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
+                               ber_memfree_x( ava->la_value.bv_val, ctx );
+                       ava->la_value = bv;
+                       ava->la_flags |= LDAP_AVA_FREE_VALUE;
+               }
+
+               if( do_sort ) AVA_Sort( rdn, iAVA );
+       }
+       return LDAP_SUCCESS;
+}
+
 /*
  * In-place, schema-aware normalization / "pretty"ing of the
  * structural representation of a distinguished name.
@@ -242,7 +460,7 @@ LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
                        slap_mr_normalize_func *normf = NULL;
                        slap_syntax_transform_func *transf = NULL;
                        MatchingRule *mr = NULL;
-                       struct berval           bv = { 0, NULL };
+                       struct berval           bv = BER_BVNULL;
                        int                     do_sort = 0;
 
                        assert( ava );
@@ -316,7 +534,7 @@ LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
                                 *      if value is empty, use empty_bv
                                 */
                                rc = ( *normf )(
-                                       0,
+                                       SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
                                        ad->ad_type->sat_syntax,
                                        mr,
                                        ava->la_value.bv_len
@@ -331,8 +549,10 @@ LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
 
 
                        if( bv.bv_val ) {
-                               ber_memfree_x( ava->la_value.bv_val, ctx );
+                               if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
+                                       ber_memfree_x( ava->la_value.bv_val, ctx );
                                ava->la_value = bv;
+                               ava->la_flags |= LDAP_AVA_FREE_VALUE;
                        }
 
                        if( do_sort ) AVA_Sort( rdn, iAVA );
@@ -374,7 +594,7 @@ dnNormalize(
                 * Schema-aware rewrite
                 */
                if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
-                       ldap_dnfree( dn );
+                       ldap_dnfree_x( dn, ctx );
                        return LDAP_INVALID_SYNTAX;
                }
 
@@ -398,33 +618,66 @@ dnNormalize(
        return LDAP_SUCCESS;
 }
 
-#if 0
-/*
- * dn "pretty"ing routine
- */
 int
-dnPretty(
-       Syntax *syntax,
-       struct berval *val,
-       struct berval **pretty)
+rdnNormalize(
+    slap_mask_t use,
+    Syntax *syntax,
+    MatchingRule *mr,
+    struct berval *val,
+    struct berval *out,
+    void *ctx)
 {
-       struct berval *out;
-       int rc;
+       assert( val );
+       assert( out );
+
+       Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
+       if ( val->bv_len != 0 ) {
+               LDAPRDN         rdn = NULL;
+               int             rc;
+               char*           p;
 
-       assert( pretty && *pretty == NULL );
+               /*
+                * Go to structural representation
+                */
+               rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
+                                       LDAP_DN_FORMAT_LDAP, ctx);
 
-       out = ch_malloc( sizeof( struct berval ) );
-       rc = dnPretty2( syntax, val, out );
-       if ( rc != LDAP_SUCCESS )
-               free( out );
-       else
-               *pretty = out;
-       return rc;
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               assert( strlen( val->bv_val ) == val->bv_len );
+
+               /*
+                * Schema-aware rewrite
+                */
+               if ( LDAPRDN_rewrite( rdn, 0, ctx ) != LDAP_SUCCESS ) {
+                       ldap_rdnfree_x( rdn, ctx );
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /*
+                * Back to string representation
+                */
+               rc = ldap_rdn2bv_x( rdn, out,
+                       LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
+
+               ldap_rdnfree_x( rdn, ctx );
+
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       } else {
+               ber_dupbv_x( out, val, ctx );
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
+
+       return LDAP_SUCCESS;
 }
-#endif
 
 int
-dnPretty2(
+dnPretty(
        Syntax *syntax,
        struct berval *val,
        struct berval *out,
@@ -479,11 +732,83 @@ dnPretty2(
                }
        }
 
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
+#else
        Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
+#endif
 
        return LDAP_SUCCESS;
 }
 
+int
+rdnPretty(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *out,
+       void *ctx)
+{
+       assert( val );
+       assert( out );
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
+#endif
+
+       if ( val->bv_len == 0 ) {
+               ber_dupbv_x( out, val, ctx );
+
+       } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
+               return LDAP_INVALID_SYNTAX;
+
+       } else {
+               LDAPRDN         rdn = NULL;
+               int             rc;
+               char*           p;
+
+               /* FIXME: should be liberal in what we accept */
+               rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
+                                       LDAP_DN_FORMAT_LDAP, ctx);
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               assert( strlen( val->bv_val ) == val->bv_len );
+
+               /*
+                * Schema-aware rewrite
+                */
+               if ( LDAPRDN_rewrite( rdn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
+                       ldap_rdnfree_x( rdn, ctx );
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /* FIXME: not sure why the default isn't pretty */
+               /* RE: the default is the form that is used as
+                * an internal representation; the pretty form
+                * is a variant */
+               rc = ldap_rdn2bv_x( rdn, out,
+                       LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
+
+               ldap_rdnfree_x( rdn, ctx );
+
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
+#endif
+
+       return LDAP_SUCCESS;
+}
+
+
 int
 dnPrettyNormalDN(
        Syntax *syntax,
@@ -650,6 +975,8 @@ dnMatch(
        assert( matchp );
        assert( value );
        assert( assertedValue );
+       assert( !BER_BVISNULL( value ) );
+       assert( !BER_BVISNULL( asserted ) );
        
        match = value->bv_len - asserted->bv_len;
 
@@ -670,9 +997,45 @@ dnMatch(
        return( LDAP_SUCCESS );
 }
 
+int
+rdnMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match;
+       struct berval *asserted = (struct berval *) assertedValue;
+
+       assert( matchp );
+       assert( value );
+       assert( assertedValue );
+       
+       match = value->bv_len - asserted->bv_len;
+
+       if ( match == 0 ) {
+               match = memcmp( value->bv_val, asserted->bv_val, 
+                               value->bv_len );
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( CONFIG, ENTRY, "rdnMatch: %d\n    %s\n    %s\n", 
+               match, value->bv_val, asserted->bv_val  );
+#else
+       Debug( LDAP_DEBUG_ARGS, "rdnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
+               match, value->bv_val, asserted->bv_val );
+#endif
+
+       *matchp = match;
+
+       return( LDAP_SUCCESS );
+}
+
+
 /*
  * dnParent - dn's parent, in-place
- *
  * note: the incoming dn is assumed to be normalized/prettyfied,
  * so that escaped rdn/ava separators are in '\'+hexpair form
  */
@@ -770,7 +1133,7 @@ dn_rdnlen(
  * LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
  */
 int
-rdnValidate( struct berval *rdn )
+rdn_validate( struct berval *rdn )
 {
 #if 1
        /* Major cheat!
@@ -782,7 +1145,6 @@ rdnValidate( struct berval *rdn )
        {
                return LDAP_INVALID_SYNTAX;
        }
-
        return strchr( rdn->bv_val, ',' ) == NULL
                ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
 
@@ -840,17 +1202,18 @@ rdnValidate( struct berval *rdn )
 void
 build_new_dn( struct berval * new_dn,
        struct berval * parent_dn,
-       struct berval * newrdn )
+       struct berval * newrdn,
+       void *memctx )
 {
        char *ptr;
 
-       if ( parent_dn == NULL ) {
+       if ( parent_dn == NULL || parent_dn->bv_len == 0 ) {
                ber_dupbv( new_dn, newrdn );
                return;
        }
 
        new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
-       new_dn->bv_val = (char *) ch_malloc( new_dn->bv_len + 1 );
+       new_dn->bv_val = (char *) slap_sl_malloc( new_dn->bv_len + 1, memctx );
 
        ptr = lutil_strcopy( new_dn->bv_val, newrdn->bv_val );
        *ptr++ = ',';
@@ -904,7 +1267,12 @@ int
 dnX509normalize( void *x509_name, struct berval *out )
 {
        /* Invoke the LDAP library's converter with our schema-rewriter */
-       return ldap_X509dn2bv( x509_name, out, LDAPDN_rewrite, 0 );
+       int rc = ldap_X509dn2bv( x509_name, out, LDAPDN_rewrite, 0 );
+
+       Debug( LDAP_DEBUG_TRACE,
+               "dnX509Normalize: <%s>\n", out->bv_val, 0, 0 );
+
+       return rc;
 }
 
 /*
@@ -914,6 +1282,7 @@ int
 dnX509peerNormalize( void *ssl, struct berval *dn )
 {
 
-       return ldap_pvt_tls_get_peer_dn( ssl, dn, (LDAPDN_rewrite_dummy *)LDAPDN_rewrite, 0 );
+       return ldap_pvt_tls_get_peer_dn( ssl, dn,
+               (LDAPDN_rewrite_dummy *)LDAPDN_rewrite, 0 );
 }
 #endif