]> granicus.if.org Git - icinga2/commitdiff
Improve validation for arrays
authorGunnar Beutner <gunnar@beutner.name>
Thu, 24 Mar 2016 08:15:09 +0000 (09:15 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Thu, 24 Mar 2016 08:15:39 +0000 (09:15 +0100)
fixes #11434

lib/config/configitem.cpp
lib/icinga/user.cpp
tools/mkclass/classcompiler.cpp

index 8a14de5aae79084813f2a7d1d14422348725299d..83d40810b744f203d71a6d5e98f3419f6571c8c3 100644 (file)
@@ -226,6 +226,23 @@ ConfigObject::Ptr ConfigItem::Commit(bool discard)
 
        dobj->SetName(name);
 
+       Dictionary::Ptr dhint = debugHints.ToDictionary();
+
+       try {
+               DefaultValidationUtils utils;
+               dobj->Validate(FAConfig, utils);
+       } catch (ValidationError& ex) {
+               if (m_IgnoreOnError) {
+                       Log(LogWarning, "ConfigObject")
+                           << "Ignoring config object '" << m_Name << "' of type '" << m_Type << "' due to errors: " << DiagnosticInformation(ex);
+
+                       return ConfigObject::Ptr();
+               }
+
+               ex.SetDebugHint(dhint);
+               throw;
+       }
+
        try {
                dobj->OnConfigLoaded();
        } catch (const std::exception& ex) {
@@ -244,8 +261,6 @@ ConfigObject::Ptr ConfigItem::Commit(bool discard)
        persistentItem->Set("type", GetType());
        persistentItem->Set("name", GetName());
        persistentItem->Set("properties", Serialize(dobj, FAConfig));
-
-       Dictionary::Ptr dhint = debugHints.ToDictionary();
        persistentItem->Set("debug_hints", dhint);
 
        Array::Ptr di = new Array();
@@ -256,21 +271,6 @@ ConfigObject::Ptr ConfigItem::Commit(bool discard)
        di->Add(m_DebugInfo.LastColumn);
        persistentItem->Set("debug_info", di);
 
-       try {
-               DefaultValidationUtils utils;
-               dobj->Validate(FAConfig, utils);
-       } catch (ValidationError& ex) {
-               if (m_IgnoreOnError) {
-                       Log(LogWarning, "ConfigObject")
-                           << "Ignoring config object '" << m_Name << "' of type '" << m_Type << "' due to errors: " << DiagnosticInformation(ex);
-
-                       return ConfigObject::Ptr();
-               }
-
-               ex.SetDebugHint(dhint);
-               throw;
-       }
-
        ConfigCompilerContext::GetInstance()->WriteObject(persistentItem);
        persistentItem.reset();
 
index f4e35d023fc1f1f5b4fc2cb883c810c935f02d96..eb232fc84561942e23a1b5d0de49bbda5ae70df8 100644 (file)
@@ -111,6 +111,8 @@ void User::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils)
 
 void User::ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils)
 {
+       ObjectImpl<User>::ValidateTypes(value, utils);
+
        int tfilter = FilterArrayToInt(value, 0);
 
        if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved |
index 9914f0d3e057c722fb809c45979a56337e97133c..d0aab97a9717128b5649642350aeffa553664539 100644 (file)
@@ -158,6 +158,33 @@ static bool FieldTypeCmp(const Field& a, const Field& b)
        return a.Type.GetRealType() < b.Type.GetRealType();
 }
 
+static std::string FieldTypeToIcingaName(const Field& field, bool inner)
+{
+       std::string ftype = field.Type.TypeName;
+
+       if (!inner && field.Type.ArrayRank > 0)
+               return "Array";
+
+       if (field.Type.IsName)
+               return "String";
+
+       if (field.Attributes & FAEnum)
+               return "Number";
+
+       if (ftype == "bool" || ftype == "int" || ftype == "double")
+               return "Number";
+
+       if (ftype == "int" || ftype == "double")
+               return "Number";
+       else if (ftype == "bool")
+               return "Boolean";
+
+       if (ftype.find("::Ptr") != std::string::npos)
+               return ftype.substr(0, ftype.size() - strlen("::Ptr"));
+
+       return ftype;
+}
+
 void ClassCompiler::OptimizeStructLayout(std::vector<Field>& fields)
 {
        std::sort(fields.begin(), fields.end(), FieldTypeCmp);
@@ -342,21 +369,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
 
                size_t num = 0;
                for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
-                       std::string ftype = it->Type.GetRealType();
-
-                       if (ftype == "bool" || ftype == "int" || ftype == "double")
-                               ftype = "Number";
-
-                       if (ftype == "int" || ftype == "double")
-                               ftype = "Number";
-                       else if (ftype == "bool")
-                               ftype = "Boolean";
-
-                       if (ftype.find("::Ptr") != std::string::npos)
-                               ftype = ftype.substr(0, ftype.size() - strlen("::Ptr"));
-
-                       if (it->Attributes & FAEnum)
-                               ftype = "Number";
+                       std::string ftype = FieldTypeToIcingaName(*it, false);
 
                        std::string nameref;
 
@@ -487,33 +500,39 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
 
                const Field& field = *it;
 
-               if ((field.Attributes & (FARequired)) || field.Type.IsName) {
-                       if (field.Attributes & FARequired) {
-                               if (field.Type.GetRealType().find("::Ptr") != std::string::npos)
-                                       m_Impl << "\t" << "if (!value)" << std::endl;
-                               else
-                                       m_Impl << "\t" << "if (value.IsEmpty())" << std::endl;
+               if (field.Attributes & FARequired) {
+                       if (field.Type.GetRealType().find("::Ptr") != std::string::npos)
+                               m_Impl << "\t" << "if (!value)" << std::endl;
+                       else
+                               m_Impl << "\t" << "if (value.IsEmpty())" << std::endl;
 
-                               m_Impl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Attribute must not be empty.\"));" << std::endl << std::endl;
-                       }
+                       m_Impl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Attribute must not be empty.\"));" << std::endl << std::endl;
+               }
 
-                       if (field.Type.IsName) {
-                               if (field.Type.ArrayRank > 0) {
-                                       m_Impl << "\t" << "if (value) {" << std::endl
-                                              << "\t\t" << "ObjectLock olock(value);" << std::endl
-                                              << "\t\t" << "BOOST_FOREACH(const String& ref, value) {" << std::endl;
-                               } else
-                                       m_Impl << "\t" << "String ref = value;" << std::endl;
-
-                               m_Impl << "\t" << "if (!ref.IsEmpty() && !utils.ValidateName(\"" << field.Type.TypeName << "\", ref))" << std::endl
-                                      << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Object '\" + ref + \"' of type '" << field.Type.TypeName
-                                      << "' does not exist.\"));" << std::endl;
-
-                               if (field.Type.ArrayRank > 0) {
-                                       m_Impl << "\t\t" << "}" << std::endl
-                                              << "\t" << "}" << std::endl;
-                               }
-                       }
+               if (field.Type.ArrayRank > 0) {
+                       m_Impl << "\t" << "if (value) {" << std::endl
+                              << "\t\t" << "ObjectLock olock(value);" << std::endl
+                              << "\t\t" << "BOOST_FOREACH(const Value& avalue, value) {" << std::endl;
+               } else
+                       m_Impl << "\t" << "Value avalue = value;" << std::endl;
+
+               std::string ftype = FieldTypeToIcingaName(field, true);
+
+               if (field.Type.IsName) {
+                       m_Impl << "\t" << "if (!avalue.IsEmpty() && !utils.ValidateName(\"" << field.Type.TypeName << "\", avalue))" << std::endl
+                              << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Object '\" + avalue + \"' of type '" << field.Type.TypeName
+                              << "' does not exist.\"));" << std::endl;
+               } else if (field.Type.ArrayRank > 0 && (ftype == "Number" || ftype == "Boolean")) {
+                       m_Impl << "\t" << "try {" << std::endl
+                              << "\t\t" << "Convert::ToDouble(avalue);" << std::endl
+                              << "\t" << "} catch (const std::invalid_argument&) {" << std::endl
+                              << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Array element '\" + avalue + \"' of type '\" + avalue.GetReflectionType()->GetName() + \"' is not valid here; expected type '" << ftype << "'.\"));" << std::endl
+                              << "\t" << "}" << std::endl;
+               }
+
+               if (field.Type.ArrayRank > 0) {
+                       m_Impl << "\t\t" << "}" << std::endl
+                              << "\t" << "}" << std::endl;
                }
 
                m_Impl << "}" << std::endl << std::endl;