]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/schema_check.c
ITS#7588 fix double-free for sorted paged search
[openldap] / servers / slapd / schema_check.c
index 750430bc38ba0211fe94800083e3aaca79a63648..3481ee7eb1ea56c0f8ed06cb99b55a62645a1607 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Copyright 1998-2013 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@ static char * oc_check_required(
 static int entry_naming_check(
        Entry *e,
        int manage,
+       int add_naming,
        const char** text,
        char *textbuf, size_t textlen );
 /*
@@ -47,7 +48,8 @@ entry_schema_check(
        Entry *e,
        Attribute *oldattrs,
        int manage,
-       int add_soc,
+       int add,
+       Attribute **socp,
        const char** text,
        char *textbuf, size_t textlen )
 {
@@ -135,7 +137,7 @@ entry_schema_check(
        assert( aoc->a_vals[0].bv_val != NULL );
 
        /* check the structural object class attribute */
-       if ( asc == NULL && !add_soc ) {
+       if ( asc == NULL && !add ) {
                Debug( LDAP_DEBUG_ANY,
                        "No structuralObjectClass for entry (%s)\n",
                    e->e_dn, 0, 0 );
@@ -150,7 +152,7 @@ entry_schema_check(
                return rc;
        }
 
-       if ( asc == NULL && add_soc ) {
+       if ( asc == NULL && add ) {
                attr_merge_one( e, ad_structuralObjectClass, &oc->soc_cname, NULL );
                asc = attr_find( e->e_attrs, ad_structuralObjectClass );
                sc = oc;
@@ -211,20 +213,33 @@ got_soc:
                rc = LDAP_OBJECT_CLASS_VIOLATION;
                goto done;
 
-       } else if ( sc != slap_schema.si_oc_glue && sc != oc ) {
-               snprintf( textbuf, textlen, 
-                       "structural object class modification "
-                       "from '%s' to '%s' not allowed",
-                       asc->a_vals[0].bv_val, oc->soc_cname.bv_val );
-               rc = LDAP_NO_OBJECT_CLASS_MODS;
-               goto done;
-       } else if ( sc == slap_schema.si_oc_glue ) {
+       } else if ( sc != oc ) {
+               if ( !manage && sc != slap_schema.si_oc_glue ) {
+                       snprintf( textbuf, textlen, 
+                               "structural object class modification "
+                               "from '%s' to '%s' not allowed",
+                               asc->a_vals[0].bv_val, oc->soc_cname.bv_val );
+                       rc = LDAP_NO_OBJECT_CLASS_MODS;
+                       goto done;
+               }
+
+               assert( asc->a_vals != NULL );
+               assert( !BER_BVISNULL( &asc->a_vals[0] ) );
+               assert( BER_BVISNULL( &asc->a_vals[1] ) );
+               assert( asc->a_nvals == asc->a_vals );
+
+               /* draft-zeilenga-ldap-relax: automatically modify
+                * structuralObjectClass if changed with relax */
                sc = oc;
+               ber_bvreplace( &asc->a_vals[ 0 ], &sc->soc_cname );
+               if ( socp ) {
+                       *socp = asc;
+               }
        }
 
        /* naming check */
        if ( !is_entry_glue ( e ) ) {
-               rc = entry_naming_check( e, manage, text, textbuf, textlen );
+               rc = entry_naming_check( e, manage, add, text, textbuf, textlen );
                if( rc != LDAP_SUCCESS ) {
                        goto done;
                }
@@ -355,8 +370,8 @@ got_soc:
                                        }
                                }
 
-                               if( xc == NULL ) {
-                                       snprintf( textbuf, textlen, "instanstantiation of "
+                               if( xc != NULL ) {
+                                       snprintf( textbuf, textlen, "instantiation of "
                                                "abstract objectClass '%s' not allowed",
                                                aoc->a_vals[i].bv_val );
 
@@ -762,6 +777,7 @@ static int
 entry_naming_check(
        Entry *e,
        int manage,
+       int add_naming,
        const char** text,
        char *textbuf, size_t textlen )
 {
@@ -781,7 +797,7 @@ entry_naming_check(
        if ( ldap_bv2rdn( &e->e_name, &rdn, (char **)&p,
                LDAP_DN_FORMAT_LDAP ) )
        {
-               *text = "unrecongized attribute type(s) in RDN";
+               *text = "unrecognized attribute type(s) in RDN";
                return LDAP_INVALID_DN_SYNTAX;
        }
 
@@ -792,6 +808,7 @@ entry_naming_check(
                AttributeDescription *desc = NULL;
                Attribute *attr;
                const char *errtext;
+               int add = 0;
 
                if( ava->la_flags & LDAP_AVA_BINARY ) {
                        snprintf( textbuf, textlen, 
@@ -852,37 +869,64 @@ entry_naming_check(
                        snprintf( textbuf, textlen, 
                                "naming attribute '%s' is not present in entry",
                                ava->la_attr.bv_val );
-                       rc = LDAP_NAMING_VIOLATION;
-                       break;
-               }
+                       if ( add_naming ) {
+                               add = 1;
 
-               rc = attr_valfind( attr, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX|
-                       SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
-                       &ava->la_value, NULL, NULL );
+                       } else {
+                               rc = LDAP_NAMING_VIOLATION;
+                       }
 
-               if( rc != 0 ) {
-                       switch( rc ) {
-                       case LDAP_INAPPROPRIATE_MATCHING:
-                               snprintf( textbuf, textlen, 
-                                       "inappropriate matching for naming attribute '%s'",
-                                       ava->la_attr.bv_val );
-                               break;
-                       case LDAP_INVALID_SYNTAX:
-                               snprintf( textbuf, textlen, 
-                                       "value of naming attribute '%s' is invalid",
-                                       ava->la_attr.bv_val );
-                               break;
-                       case LDAP_NO_SUCH_ATTRIBUTE:
-                               snprintf( textbuf, textlen, 
-                                       "value of naming attribute '%s' is not present in entry",
-                                       ava->la_attr.bv_val );
-                               break;
-                       default:
-                               snprintf( textbuf, textlen, 
-                                       "naming attribute '%s' is inappropriate",
-                                       ava->la_attr.bv_val );
+               } else {
+                       rc = attr_valfind( attr, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX|
+                               SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
+                               &ava->la_value, NULL, NULL );
+
+                       if ( rc != 0 ) {
+                               switch( rc ) {
+                               case LDAP_INAPPROPRIATE_MATCHING:
+                                       snprintf( textbuf, textlen, 
+                                               "inappropriate matching for naming attribute '%s'",
+                                               ava->la_attr.bv_val );
+                                       break;
+                               case LDAP_INVALID_SYNTAX:
+                                       snprintf( textbuf, textlen, 
+                                               "value of naming attribute '%s' is invalid",
+                                               ava->la_attr.bv_val );
+                                       break;
+                               case LDAP_NO_SUCH_ATTRIBUTE:
+                                       if ( add_naming ) {
+                                               if ( is_at_single_value( desc->ad_type ) ) {
+                                                       snprintf( textbuf, textlen, 
+                                                               "value of single-valued naming attribute '%s' conflicts with value present in entry",
+                                                               ava->la_attr.bv_val );
+
+                                               } else {
+                                                       add = 1;
+                                                       rc = LDAP_SUCCESS;
+                                               }
+
+                                       } else {
+                                               snprintf( textbuf, textlen, 
+                                                       "value of naming attribute '%s' is not present in entry",
+                                                       ava->la_attr.bv_val );
+                                       }
+                                       break;
+                               default:
+                                       snprintf( textbuf, textlen, 
+                                               "naming attribute '%s' is inappropriate",
+                                               ava->la_attr.bv_val );
+                               }
+
+                               if ( !add ) {
+                                       rc = LDAP_NAMING_VIOLATION;
+                               }
                        }
-                       rc = LDAP_NAMING_VIOLATION;
+               }
+
+               if ( add ) {
+                       attr_merge_normalize_one( e, desc, &ava->la_value, NULL );
+
+               } else if ( rc != LDAP_SUCCESS ) {
                        break;
                }
        }