CHECK_INCLUDE_FILES(sys/param.h HAVE_SYS_PARAM_H)
CHECK_INCLUDE_FILES(sys/cdefs.h HAVE_SYS_CDEFS_H)
CHECK_INCLUDE_FILES(sys/file.h HAVE_SYS_FILE_H)
+CHECK_INCLUDE_FILES(sys/utsname.h HAVE_SYS_UTSNAME_H)
CHECK_INCLUDE_FILES(sys/resource.h HAVE_SYS_RESOURCE_H)
CHECK_INCLUDE_FILES(netinet/in.h HAVE_NETINET_IN_H)
CHECK_INCLUDE_FILES(arpa/inet.h HAVE_ARPA_INET_H)
#cmakedefine HAVE_SYS_PARAM_H 1
#cmakedefine HAVE_SYS_FILE_H 1
#cmakedefine HAVE_SYS_RESOURCE_H 1
-#cmakedefine HAVE_SYS_TIMEB_H 1
+#cmakedefine HAVE_SYS_TIMEB_H 1
+#cmakedefine HAVE_SYS_UTSNAME_H 1
#cmakedefine HAVE_PIDFILE 1
/* Prepare xml parser */
ud.cfg = cfg;
ud.state = XML_READ_START;
+ ud.if_stack = g_queue_new ();
ctx = g_markup_parse_context_new (&xml_parser, G_MARKUP_TREAT_CDATA_AS_TEXT | G_MARKUP_PREFIX_ERROR_POSITION, &ud, NULL);
res = g_markup_parse_context_parse (ctx, data, st.st_size, &err);
+ if (g_queue_get_length (ud.if_stack) != 0) {
+ msg_err ("unexpected nesting for if arguments");
+ res = FALSE;
+ }
+
munmap (data, st.st_size);
return res;
return g_quark_from_static_string ("xml-error-quark");
}
+static inline const gchar *
+xml_state_to_string (struct rspamd_xml_userdata *ud)
+{
+ switch (ud->state) {
+ case XML_READ_START:
+ return "read start tag";
+ case XML_READ_PARAM:
+ return "read param";
+ case XML_READ_MODULE:
+ return "read module section";
+ case XML_READ_MODULES:
+ return "read modules section";
+ case XML_READ_CLASSIFIER:
+ return "read classifier section";
+ case XML_READ_STATFILE:
+ return "read statfile section";
+ case XML_READ_METRIC:
+ return "read metric section";
+ case XML_READ_WORKER:
+ return "read worker section";
+ case XML_READ_VIEW:
+ return "read view section";
+ case XML_READ_LOGGING:
+ return "read logging section";
+ case XML_READ_VALUE:
+ return "read value";
+ case XML_SKIP_ELEMENTS:
+ return "skip if block";
+ case XML_ERROR:
+ return "error occured";
+ case XML_END:
+ return "read final tag";
+ }
+ /* Unreached */
+ return "unknown state";
+}
static inline gboolean
extract_attr (const gchar *attr, const gchar **attribute_names, const gchar **attribute_values, gchar **res)
{
struct rspamd_xml_userdata *ud = user_data;
struct classifier_config *ccf;
- gchar *res;
-
+ gchar *res, *condition;
+
+ if (g_ascii_strcasecmp (element_name, "if") == 0) {
+ /* Push current state to queue */
+ g_queue_push_head (ud->if_stack, GSIZE_TO_POINTER ((gsize)ud->state));
+ /* Now get attributes */
+ ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values);
+ if ((condition = g_hash_table_lookup (ud->cur_attrs, "condition")) == NULL) {
+ msg_err ("unknown condition attribute for if tag");
+ *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'condition' is required for tag 'if'");
+ ud->state = XML_ERROR;
+ }
+ if (! lua_check_condition (ud->cfg, condition)) {
+ ud->state = XML_SKIP_ELEMENTS;
+ }
+ return;
+ }
switch (ud->state) {
case XML_READ_START:
if (g_ascii_strcasecmp (element_name, "rspamd") != 0) {
ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values);
}
break;
+ case XML_SKIP_ELEMENTS:
+ /* Do nothing */
+ return;
case XML_READ_MODULE:
case XML_READ_METRIC:
case XML_READ_MODULES:
ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values);
break;
default:
- *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is unexpected in this state", element_name);
+ if (*error == NULL) {
+ *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is unexpected in this state %s",
+ element_name, xml_state_to_string (ud));
+ }
break;
}
}
struct metric *m;
struct classifier_config *ccf;
struct statfile *st;
- gboolean res;
+ gboolean res;
+ gpointer tptr;
+ if (g_ascii_strcasecmp (element_name, "if") == 0) {
+ tptr = g_queue_pop_head (ud->if_stack);
+
+ if (tptr == NULL) {
+ *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is umatched", element_name);
+ ud->state = XML_ERROR;
+ }
+ /* Restore state */
+ if (ud->state == XML_SKIP_ELEMENTS) {
+ ud->state = GPOINTER_TO_SIZE (tptr);
+ }
+ /* Skip processing */
+
+ return;
+ }
+
switch (ud->state) {
case XML_READ_MODULE:
CHECK_TAG ("module", FALSE);
ud->state = XML_ERROR;
}
break;
+ case XML_SKIP_ELEMENTS:
+ return;
default:
ud->state = XML_ERROR;
break;
ud->state = XML_ERROR;
}
break;
+ case XML_SKIP_ELEMENTS:
+ /* Do nothing */
+ return;
default:
ud->state = XML_ERROR;
break;
}
-static inline const gchar *
-xml_state_to_string (struct rspamd_xml_userdata *ud)
-{
- switch (ud->state) {
- case XML_READ_START:
- return "read start tag";
- case XML_READ_PARAM:
- return "read param";
- case XML_READ_MODULE:
- return "read module section";
- case XML_READ_MODULES:
- return "read modules section";
- case XML_READ_CLASSIFIER:
- return "read classifier section";
- case XML_READ_STATFILE:
- return "read statfile section";
- case XML_READ_METRIC:
- return "read metric section";
- case XML_READ_WORKER:
- return "read worker section";
- case XML_READ_VIEW:
- return "read view section";
- case XML_READ_LOGGING:
- return "read logging section";
- case XML_READ_VALUE:
- return "read value";
- case XML_ERROR:
- return "error occured";
- case XML_END:
- return "read final tag";
- }
- /* Unreached */
- return "unknown state";
-}
-
void
rspamd_xml_error (GMarkupParseContext *context, GError *error, gpointer user_data)
{
XML_READ_VIEW,
XML_READ_LOGGING,
XML_READ_VALUE,
+ XML_SKIP_ELEMENTS,
XML_ERROR,
XML_END
};
MODULE_OPT_TYPE_ANY
};
+/**
+ * Structure that is used for semantic resolution of configuration
+ */
struct rspamd_xml_userdata {
- enum xml_read_state state;
- struct config_file *cfg;
- gchar section_name[MAX_NAME];
- gpointer section_pointer;
- gpointer parent_pointer;
- GHashTable *cur_attrs;
+ enum xml_read_state state; /*< state of parser */
+ struct config_file *cfg; /*< configuration object */
+ gchar section_name[MAX_NAME]; /*< current section */
+ gpointer section_pointer; /*< pointer to object related with section */
+ gpointer parent_pointer; /*< parent's section object */
+ GHashTable *cur_attrs; /*< attributes of current tag */
+ GQueue *if_stack; /*< stack of if elements */
};
/* Text is NULL terminated here */
*/
#include "lua_common.h"
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
/*
* This is implementation of lua routines to handle config file params
*res = NULL;
return FALSE;
}
+
+#define FAKE_RES_VAR "rspamd_res"
+gboolean
+lua_check_condition (struct config_file *cfg, const gchar *condition)
+{
+ lua_State *L = cfg->lua_state;
+ gchar *hostbuf, *condbuf;
+ gsize hostlen;
+ gboolean res;
+#ifdef HAVE_SYS_UTSNAME_H
+ struct utsname uts;
+#endif
+
+ /* Set some globals for condition */
+ /* XXX: think what other variables can be useful */
+ hostlen = sysconf (_SC_HOST_NAME_MAX) + 1;
+ hostbuf = alloca (hostlen);
+ gethostname (hostbuf, hostlen);
+ hostbuf[hostlen - 1] = '\0';
+
+ /* Hostname */
+ lua_pushstring (L, hostbuf);
+ lua_setglobal (L, "hostname");
+ /* Config file name */
+ lua_pushstring (L, cfg->cfg_name);
+ lua_setglobal (L, "cfg_name");
+ /* Check for uname */
+#ifdef HAVE_SYS_UTSNAME_H
+ uname (&uts);
+ lua_pushstring (L, uts.sysname);
+ lua_setglobal (L, "osname");
+ lua_pushstring (L, uts.release);
+ lua_setglobal (L, "osrelease");
+#else
+ lua_pushstring (L, "unknown");
+ lua_setglobal (L, "osname");
+ lua_pushstring (L, "");
+ lua_setglobal (L, "osrelease");
+#endif
+ /* Make fake string */
+ hostlen = sizeof (FAKE_RES_VAR "=") + strlen (condition);
+ condbuf = g_malloc (hostlen);
+ rspamd_strlcpy (condbuf, FAKE_RES_VAR "=", sizeof (FAKE_RES_VAR "="));
+ g_strlcat (condbuf, condition, hostlen);
+ /* Evaluate condition */
+ if (luaL_dostring (L, condbuf) != 0) {
+ msg_err ("eval of '%s' failed: '%s'", condition, lua_tostring (L, -1));
+ g_free (condbuf);
+ return FALSE;
+ }
+ /* Get global variable res to get result */
+ lua_getglobal (L, FAKE_RES_VAR);
+ if (! lua_isboolean (L, -1)) {
+ msg_err ("bad string evaluated: %s, type: %s", condbuf, lua_typename (L, lua_type (L, -1)));
+ g_free (condbuf);
+ return FALSE;
+ }
+
+ res = lua_toboolean (L, -1);
+ g_free (condbuf);
+
+ return res;
+}
void lua_process_element (struct config_file *cfg, const gchar *name, struct module_opt *opt, gint idx);
gboolean lua_handle_param (struct worker_task *task, gchar *mname, gchar *optname,
enum lua_var_type expected_type, gpointer *res);
+gboolean lua_check_condition (struct config_file *cfg, const gchar *condition);
#endif /* WITH_LUA */