]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/schema_check.c
fix one-time leak
[openldap] / servers / slapd / schema_check.c
index e3b76090e7568c8aa72c1a080608bb1d032d857c..938fef34d55bab8b3f602022ef1377868b292694 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2007 The OpenLDAP Foundation.
+ * Copyright 1998-2012 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;
@@ -172,7 +174,7 @@ entry_schema_check(
                        e->e_dn, textbuf, 0 );
 
                rc = LDAP_OBJECT_CLASS_VIOLATION;
-               goto leave;
+               goto done;
        }
 
        if( sc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) {
@@ -185,7 +187,7 @@ entry_schema_check(
                        e->e_dn, textbuf, 0 );
 
                rc = LDAP_OTHER;
-               goto leave;
+               goto done;
        }
 
 got_soc:
@@ -199,7 +201,7 @@ got_soc:
                        e->e_dn, textbuf, 0 );
 
                rc = LDAP_OBJECT_CLASS_VIOLATION;
-               goto leave;
+               goto done;
        }
 
        *text = textbuf;
@@ -209,24 +211,37 @@ got_soc:
                        "unrecognized objectClass '%s'",
                        aoc->a_vals[0].bv_val );
                rc = LDAP_OBJECT_CLASS_VIOLATION;
-               goto leave;
+               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 leave;
-       } 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 leave;
+                       goto done;
                }
        } else {
                /* Glue Entry */
@@ -250,7 +265,7 @@ got_soc:
                                e->e_dn, textbuf, 0 );
 
                        rc = LDAP_OBJECT_CLASS_VIOLATION;
-                       goto leave;
+                       goto done;
                }
 
                if( cr->scr_required ) for( i=0; cr->scr_required[i]; i++ ) {
@@ -274,7 +289,7 @@ got_soc:
                                        e->e_dn, textbuf, 0 );
 
                                rc = LDAP_OBJECT_CLASS_VIOLATION;
-                               goto leave;
+                               goto done;
                        }
                }
 
@@ -299,7 +314,7 @@ got_soc:
                                        e->e_dn, textbuf, 0 );
 
                                rc = LDAP_OBJECT_CLASS_VIOLATION;
-                               goto leave;
+                               goto done;
                        }
                }
        }
@@ -318,14 +333,14 @@ got_soc:
                                e->e_dn, textbuf, 0 );
 
                        rc = LDAP_OBJECT_CLASS_VIOLATION;
-                       goto leave;
+                       goto done;
                }
 
                if ( oc->soc_check ) {
                        rc = (oc->soc_check)( op->o_bd, e, oc,
                                text, textbuf, textlen );
                        if( rc != LDAP_SUCCESS ) {
-                               goto leave;
+                               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 );
 
@@ -365,7 +380,7 @@ got_soc:
                                                e->e_dn, textbuf, 0 );
 
                                        rc = LDAP_OBJECT_CLASS_VIOLATION;
-                                       goto leave;
+                                       goto done;
                                }
                        }
 
@@ -408,7 +423,7 @@ got_soc:
                                                e->e_dn, textbuf, 0 );
 
                                        rc = LDAP_OBJECT_CLASS_VIOLATION;
-                                       goto leave;
+                                       goto done;
                                }
                        }
 
@@ -423,7 +438,7 @@ got_soc:
                                        e->e_dn, textbuf, 0 );
 
                                rc = LDAP_OBJECT_CLASS_VIOLATION;
-                               goto leave;
+                               goto done;
                        }
 
                        if( oc == slap_schema.si_oc_extensibleObject ) {
@@ -435,7 +450,7 @@ got_soc:
        if( extensible ) {
                *text = NULL;
                rc = LDAP_SUCCESS;
-               goto leave;
+               goto done;
        }
 
        /* check that each attr in the entry is allowed by some oc */
@@ -476,12 +491,12 @@ got_soc:
                            "Entry (%s), %s\n",
                            e->e_dn, textbuf, 0 );
 
-                       goto leave;
+                       goto done;
                }
        }
 
        *text = NULL;
-leave:
+done:
        slap_sl_free( socs, op->o_tmpmemctx );
        return rc;
 }
@@ -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 = value_find_ex( desc, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX|
-                       SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
-                       attr->a_nvals, &ava->la_value, 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;
                }
        }