if (!prototype) {
prototype = new Dictionary();
- prototype->Set("len", new Function(WrapFunction(ArrayLen)));
+ prototype->Set("len", new Function(WrapFunction(ArrayLen), true));
prototype->Set("set", new Function(WrapFunction(ArraySet)));
prototype->Set("add", new Function(WrapFunction(ArrayAdd)));
prototype->Set("remove", new Function(WrapFunction(ArrayRemove)));
- prototype->Set("contains", new Function(WrapFunction(ArrayContains)));
+ prototype->Set("contains", new Function(WrapFunction(ArrayContains), true));
prototype->Set("clear", new Function(WrapFunction(ArrayClear)));
- prototype->Set("sort", new Function(WrapFunction(ArraySort)));
- prototype->Set("clone", new Function(WrapFunction(ArrayClone)));
- prototype->Set("join", new Function(WrapFunction(ArrayJoin)));
+ prototype->Set("sort", new Function(WrapFunction(ArraySort), true));
+ prototype->Set("clone", new Function(WrapFunction(ArrayClone), true));
+ prototype->Set("join", new Function(WrapFunction(ArrayJoin), true));
}
return prototype;
if (!prototype) {
prototype = new Dictionary();
- prototype->Set("to_string", new Function(WrapFunction(BooleanToString)));
+ prototype->Set("to_string", new Function(WrapFunction(BooleanToString), true));
}
return prototype;
if (!prototype) {
prototype = new Dictionary();
- prototype->Set("len", new Function(WrapFunction(DictionaryLen)));
+ prototype->Set("len", new Function(WrapFunction(DictionaryLen), true));
prototype->Set("set", new Function(WrapFunction(DictionarySet)));
prototype->Set("remove", new Function(WrapFunction(DictionaryRemove)));
- prototype->Set("contains", new Function(WrapFunction(DictionaryContains)));
- prototype->Set("clone", new Function(WrapFunction(DictionaryClone)));
+ prototype->Set("contains", new Function(WrapFunction(DictionaryContains), true));
+ prototype->Set("clone", new Function(WrapFunction(DictionaryClone), true));
}
return prototype;
REGISTER_PRIMITIVE_TYPE_NOINST(Function, Function::GetPrototype());
-Function::Function(const Callback& function)
- : m_Callback(function)
+Function::Function(const Callback& function, bool side_effect_free)
+ : m_Callback(function), m_SideEffectFree(side_effect_free)
{ }
Value Function::Invoke(const std::vector<Value>& arguments)
return m_Callback(arguments);
}
+bool Function::IsSideEffectFree(void) const
+{
+ return m_SideEffectFree;
+}
+
typedef boost::function<Value (const std::vector<Value>& arguments)> Callback;
- Function(const Callback& function);
+ Function(const Callback& function, bool side_effect_free = false);
Value Invoke(const std::vector<Value>& arguments = std::vector<Value>());
+ bool IsSideEffectFree(void) const;
static Object::Ptr GetPrototype(void);
private:
Callback m_Callback;
+ bool m_SideEffectFree;
};
#define REGISTER_SCRIPTFUNCTION(name, callback) \
INITIALIZE_ONCE(RegisterFunction); \
} } }
+#define REGISTER_SAFE_SCRIPTFUNCTION(name, callback) \
+ namespace { namespace UNIQUE_NAME(sf) { namespace sf ## name { \
+ void RegisterFunction(void) { \
+ Function::Ptr sf = new icinga::Function(WrapFunction(callback), true); \
+ ScriptGlobal::Set(#name, sf); \
+ } \
+ INITIALIZE_ONCE(RegisterFunction); \
+ } } }
+
}
#endif /* SCRIPTFUNCTION_H */
Dictionary::Ptr jsonObj = new Dictionary();
/* Methods */
- jsonObj->Set("encode", new Function(WrapFunction(JsonEncodeShim)));
- jsonObj->Set("decode", new Function(WrapFunction(JsonDecode)));
+ jsonObj->Set("encode", new Function(WrapFunction(JsonEncodeShim), true));
+ jsonObj->Set("decode", new Function(WrapFunction(JsonDecode), true));
ScriptGlobal::Set("Json", jsonObj);
}
mathObj->Set("SQRT2", 1.41421356237309504880);
/* Methods */
- mathObj->Set("abs", new Function(WrapFunction(MathAbs)));
- mathObj->Set("acos", new Function(WrapFunction(MathAcos)));
- mathObj->Set("asin", new Function(WrapFunction(MathAsin)));
- mathObj->Set("atan", new Function(WrapFunction(MathAtan)));
- mathObj->Set("atan2", new Function(WrapFunction(MathAtan2)));
- mathObj->Set("ceil", new Function(WrapFunction(MathCeil)));
- mathObj->Set("cos", new Function(WrapFunction(MathCos)));
- mathObj->Set("exp", new Function(WrapFunction(MathExp)));
- mathObj->Set("floor", new Function(WrapFunction(MathFloor)));
- mathObj->Set("log", new Function(WrapFunction(MathLog)));
- mathObj->Set("max", new Function(WrapFunction(MathMax)));
- mathObj->Set("min", new Function(WrapFunction(MathMin)));
- mathObj->Set("pow", new Function(WrapFunction(MathPow)));
- mathObj->Set("random", new Function(WrapFunction(MathRandom)));
- mathObj->Set("round", new Function(WrapFunction(MathRound)));
- mathObj->Set("sin", new Function(WrapFunction(MathSin)));
- mathObj->Set("sqrt", new Function(WrapFunction(MathSqrt)));
- mathObj->Set("tan", new Function(WrapFunction(MathTan)));
- mathObj->Set("isnan", new Function(WrapFunction(MathIsnan)));
- mathObj->Set("isinf", new Function(WrapFunction(MathIsinf)));
- mathObj->Set("sign", new Function(WrapFunction(MathSign)));
+ mathObj->Set("abs", new Function(WrapFunction(MathAbs), true));
+ mathObj->Set("acos", new Function(WrapFunction(MathAcos), true));
+ mathObj->Set("asin", new Function(WrapFunction(MathAsin), true));
+ mathObj->Set("atan", new Function(WrapFunction(MathAtan), true));
+ mathObj->Set("atan2", new Function(WrapFunction(MathAtan2), true));
+ mathObj->Set("ceil", new Function(WrapFunction(MathCeil), true));
+ mathObj->Set("cos", new Function(WrapFunction(MathCos), true));
+ mathObj->Set("exp", new Function(WrapFunction(MathExp), true));
+ mathObj->Set("floor", new Function(WrapFunction(MathFloor), true));
+ mathObj->Set("log", new Function(WrapFunction(MathLog), true));
+ mathObj->Set("max", new Function(WrapFunction(MathMax), true));
+ mathObj->Set("min", new Function(WrapFunction(MathMin), true));
+ mathObj->Set("pow", new Function(WrapFunction(MathPow), true));
+ mathObj->Set("random", new Function(WrapFunction(MathRandom), true));
+ mathObj->Set("round", new Function(WrapFunction(MathRound), true));
+ mathObj->Set("sin", new Function(WrapFunction(MathSin), true));
+ mathObj->Set("sqrt", new Function(WrapFunction(MathSqrt), true));
+ mathObj->Set("tan", new Function(WrapFunction(MathTan), true));
+ mathObj->Set("isnan", new Function(WrapFunction(MathIsnan), true));
+ mathObj->Set("isinf", new Function(WrapFunction(MathIsinf), true));
+ mathObj->Set("sign", new Function(WrapFunction(MathSign), true));
ScriptGlobal::Set("Math", mathObj);
}
if (!prototype) {
prototype = new Dictionary();
- prototype->Set("to_string", new Function(WrapFunction(NumberToString)));
+ prototype->Set("to_string", new Function(WrapFunction(NumberToString), true));
}
return prototype;
if (!prototype) {
prototype = new Dictionary();
- prototype->Set("to_string", new Function(WrapFunction(ObjectToString)));
+ prototype->Set("to_string", new Function(WrapFunction(ObjectToString), true));
}
return prototype;
boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames;
ScriptFrame::ScriptFrame(void)
- : Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals())
+ : Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false)
{
PushFrame(this);
}
ScriptFrame::ScriptFrame(const Value& self)
- : Locals(new Dictionary()), Self(self)
+ : Locals(new Dictionary()), Self(self), Sandboxed(false)
{
PushFrame(this);
}
{
Dictionary::Ptr Locals;
Value Self;
+ bool Sandboxed;
ScriptFrame(void);
ScriptFrame(const Value& self);
using namespace icinga;
-REGISTER_SCRIPTFUNCTION(regex, &ScriptUtils::Regex);
-REGISTER_SCRIPTFUNCTION(match, &Utility::Match);
-REGISTER_SCRIPTFUNCTION(len, &ScriptUtils::Len);
-REGISTER_SCRIPTFUNCTION(union, &ScriptUtils::Union);
-REGISTER_SCRIPTFUNCTION(intersection, &ScriptUtils::Intersection);
+REGISTER_SAFE_SCRIPTFUNCTION(regex, &ScriptUtils::Regex);
+REGISTER_SAFE_SCRIPTFUNCTION(match, &Utility::Match);
+REGISTER_SAFE_SCRIPTFUNCTION(len, &ScriptUtils::Len);
+REGISTER_SAFE_SCRIPTFUNCTION(union, &ScriptUtils::Union);
+REGISTER_SAFE_SCRIPTFUNCTION(intersection, &ScriptUtils::Intersection);
REGISTER_SCRIPTFUNCTION(log, &ScriptUtils::Log);
REGISTER_SCRIPTFUNCTION(range, &ScriptUtils::Range);
REGISTER_SCRIPTFUNCTION(exit, &Application::Exit);
-REGISTER_SCRIPTFUNCTION(typeof, &ScriptUtils::TypeOf);
-REGISTER_SCRIPTFUNCTION(keys, &ScriptUtils::Keys);
-REGISTER_SCRIPTFUNCTION(random, &Utility::Random);
-REGISTER_SCRIPTFUNCTION(get_object, &ScriptUtils::GetObject);
-REGISTER_SCRIPTFUNCTION(get_objects, &ScriptUtils::GetObjects);
+REGISTER_SAFE_SCRIPTFUNCTION(typeof, &ScriptUtils::TypeOf);
+REGISTER_SAFE_SCRIPTFUNCTION(keys, &ScriptUtils::Keys);
+REGISTER_SAFE_SCRIPTFUNCTION(random, &Utility::Random);
+REGISTER_SAFE_SCRIPTFUNCTION(get_object, &ScriptUtils::GetObject);
+REGISTER_SAFE_SCRIPTFUNCTION(get_objects, &ScriptUtils::GetObjects);
REGISTER_SCRIPTFUNCTION(assert, &ScriptUtils::Assert);
-REGISTER_SCRIPTFUNCTION(string, &ScriptUtils::CastString);
-REGISTER_SCRIPTFUNCTION(number, &ScriptUtils::CastNumber);
-REGISTER_SCRIPTFUNCTION(bool, &ScriptUtils::CastBool);
-REGISTER_SCRIPTFUNCTION(get_time, &Utility::GetTime);
+REGISTER_SAFE_SCRIPTFUNCTION(string, &ScriptUtils::CastString);
+REGISTER_SAFE_SCRIPTFUNCTION(number, &ScriptUtils::CastNumber);
+REGISTER_SAFE_SCRIPTFUNCTION(bool, &ScriptUtils::CastBool);
+REGISTER_SAFE_SCRIPTFUNCTION(get_time, &Utility::GetTime);
String ScriptUtils::CastString(const Value& value)
{
if (!prototype) {
prototype = new Dictionary();
- prototype->Set("len", new Function(WrapFunction(StringLen)));
- prototype->Set("to_string", new Function(WrapFunction(StringToString)));
- prototype->Set("substr", new Function(WrapFunction(StringSubstr)));
- prototype->Set("upper", new Function(WrapFunction(StringUpper)));
- prototype->Set("lower", new Function(WrapFunction(StringLower)));
- prototype->Set("split", new Function(WrapFunction(StringSplit)));
- prototype->Set("find", new Function(WrapFunction(StringFind)));
- prototype->Set("contains", new Function(WrapFunction(StringContains)));
- prototype->Set("replace", new Function(WrapFunction(StringReplace)));
+ prototype->Set("len", new Function(WrapFunction(StringLen), true));
+ prototype->Set("to_string", new Function(WrapFunction(StringToString), true));
+ prototype->Set("substr", new Function(WrapFunction(StringSubstr), true));
+ prototype->Set("upper", new Function(WrapFunction(StringUpper), true));
+ prototype->Set("lower", new Function(WrapFunction(StringLower), true));
+ prototype->Set("split", new Function(WrapFunction(StringSplit), true));
+ prototype->Set("find", new Function(WrapFunction(StringFind), true));
+ prototype->Set("contains", new Function(WrapFunction(StringContains), true));
+ prototype->Set("replace", new Function(WrapFunction(StringReplace), true));
}
return prototype;
{
visibleDesc.add_options()
("connect,c", po::value<std::string>(), "connect to an Icinga 2 instance")
+ ("sandbox", "enable sandbox mode")
;
}
session = Utility::NewUniqueID();
}
+ if (vm.count("sandbox")) {
+ if (vm.count("connect")) {
+ Log(LogCritical, "ConsoleCommand", "Sandbox mode cannot be used together with --connect.");
+ return EXIT_FAILURE;
+ }
+
+ l_ScriptFrame.Sandboxed = true;
+ }
+
std::cout << "Icinga (version: " << Application::GetVersion() << ")\n";
while (std::cin.good()) {
Function::Ptr func = vfunc;
+ if (!func->IsSideEffectFree() && frame.Sandboxed)
+ BOOST_THROW_EXCEPTION(ScriptError("Function is not marked as safe for sandbox mode.", m_DebugInfo));
+
std::vector<Value> arguments;
BOOST_FOREACH(Expression *arg, m_Args) {
ExpressionResult argres = arg->Evaluate(frame);
ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
+ if (frame.Sandboxed)
+ BOOST_THROW_EXCEPTION(ScriptError("Assignments are not allowed in sandbox mode.", m_DebugInfo));
+
DebugHint *psdhint = dhint;
Value parent;
ExpressionResult WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
+ if (frame.Sandboxed)
+ BOOST_THROW_EXCEPTION(ScriptError("While loops are not allowed in sandbox mode.", m_DebugInfo));
+
for (;;) {
ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
CHECK_RESULT(condition);
if (dhint)
psdhint = *dhint;
+ if (frame.Sandboxed)
+ init_dict = false;
+
if (m_Operand1->GetReference(frame, init_dict, &vparent, &vindex, &psdhint)) {
if (init_dict && VMOps::GetField(vparent, vindex, m_Operand1->GetDebugInfo()).IsEmpty())
VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo());
ExpressionResult ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
+ if (frame.Sandboxed)
+ BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo));
+
String type = VMOps::GetField(frame.Self, "type", m_DebugInfo);
ExpressionResult nameres = m_Name->Evaluate(frame);
CHECK_RESULT(nameres);
ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
+ if (frame.Sandboxed)
+ BOOST_THROW_EXCEPTION(ScriptError("Apply rules are not allowed in sandbox mode.", m_DebugInfo));
+
ExpressionResult nameres = m_Name->Evaluate(frame);
CHECK_RESULT(nameres);
ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
+ if (frame.Sandboxed)
+ BOOST_THROW_EXCEPTION(ScriptError("Object definitions are not allowed in sandbox mode.", m_DebugInfo));
+
String name;
if (m_Name) {
ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
+ if (frame.Sandboxed)
+ BOOST_THROW_EXCEPTION(ScriptError("For loops are not allowed in sandbox mode.", m_DebugInfo));
+
ExpressionResult valueres = m_Value->Evaluate(frame, dhint);
CHECK_RESULT(valueres);