From 12f7fddff6c0ab1990c3b49312d5ccf07752186a Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 20 Aug 2013 17:25:10 +0100 Subject: [PATCH] Implement include macro for rcl. --- src/rcl/rcl_internal.h | 2 + src/rcl/rcl_parser.c | 6 ++ src/rcl/rcl_util.c | 191 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 198 insertions(+), 1 deletion(-) diff --git a/src/rcl/rcl_internal.h b/src/rcl/rcl_internal.h index 114ff823d..dda08ddba 100644 --- a/src/rcl/rcl_internal.h +++ b/src/rcl/rcl_internal.h @@ -42,6 +42,8 @@ rcl_error_quark (void) return g_quark_from_static_string ("rcl-error-quark"); } +#define RCL_MAX_RECURSION 16 + enum rspamd_cl_parser_state { RSPAMD_RCL_STATE_INIT = 0, RSPAMD_RCL_STATE_OBJECT, diff --git a/src/rcl/rcl_parser.c b/src/rcl/rcl_parser.c index 76bd81232..3a5efb1a4 100644 --- a/src/rcl/rcl_parser.c +++ b/src/rcl/rcl_parser.c @@ -1205,6 +1205,12 @@ rspamd_cl_parser_add_chunk (struct rspamd_cl_parser *parser, const guchar *data, chunk->line = 1; chunk->column = 0; LL_PREPEND (parser->chunks, chunk); + parser->recursion ++; + if (parser->recursion > RCL_MAX_RECURSION) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_ERECURSION, "maximum include nesting limit is reached: %d", + parser->recursion); + return FALSE; + } return rspamd_cl_state_machine (parser, err); } diff --git a/src/rcl/rcl_util.c b/src/rcl/rcl_util.c index 2cb35a199..cd8e558e9 100644 --- a/src/rcl/rcl_util.c +++ b/src/rcl/rcl_util.c @@ -24,6 +24,7 @@ #include "config.h" #include "rcl.h" #include "rcl_internal.h" +#include "util.h" #ifdef HAVE_OPENSSL #include @@ -233,6 +234,189 @@ rspamd_cl_pubkey_add (struct rspamd_cl_parser *parser, const guchar *key, gsize return TRUE; } +#ifdef CURL_FOUND +struct rspamd_cl_curl_cbdata { + guchar *buf; + gsize buflen; +}; + +static gsize +rspamd_cl_curl_write_callback (gpointer contents, gsize size, gsize nmemb, gpointer ud) +{ + struct rspamd_cl_curl_cbdata *cbdata = ud; + gsize realsize = size * nmemb; + + cbdata->buf = g_realloc (cbdata->buf, cbdata->buflen + realsize + 1); + if (cbdata->buf == NULL) { + return 0; + } + + memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); + cbdata->buflen += realsize; + cbdata->buf[cbdata->buflen] = 0; + + return realsize; +} +#endif + +/** + * Include an url to configuration + * @param data + * @param len + * @param parser + * @param err + * @return + */ +static gboolean +rspamd_cl_include_url (const guchar *data, gsize len, struct rspamd_cl_parser *parser, GError **err) +{ + char urlbuf[PATH_MAX]; + gboolean res; + guchar *buf = NULL; + gsize buflen = 0; + struct rspamd_cl_chunk *chunk; + + rspamd_snprintf (urlbuf, sizeof (urlbuf), "%*s", len, data); + +#ifdef HAVE_FETCH_H + struct url *url; + struct url_stat us; + FILE *in; + guchar *buf; + + url = fetchParseURL (urlbuf); + if (url == NULL) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "invalid URL %s: %s", + urlbuf, strerror (errno)); + return FALSE; + } + if ((in = fetchXGet (url, &us, "")) == NULL) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "cannot fetch URL %s: %s", + urlbuf, strerror (errno)); + fetchFreeURL (url); + return FALSE; + } + + buflen = us.size; + buf = g_malloc (buflen); + if (buf == NULL) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "cannot allocate buffer for URL %s: %s", + urlbuf, strerror (errno)); + fclose (in); + fetchFreeURL (url); + return FALSE; + } + + if (fread (buf, buflen, 1, in) != 1) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "cannot read URL %s: %s", + urlbuf, strerror (errno)); + fclose (in); + fetchFreeURL (url); + return FALSE; + } + + fetchFreeURL (url); +#elif defined(CURL_FOUND) + CURL *curl; + gint r; + struct rspamd_cl_curl_cbdata cbdata; + + curl = curl_easy_init (); + if (curl == NULL) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EINTERNAL, "CURL interface is broken"); + return FALSE; + } + if ((r = curl_easy_setopt (curl, CURLOPT_URL, urlbuf)) != CURLE_OK) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "invalid URL %s: %s", + urlbuf, curl_easy_strerror (r)); + curl_easy_cleanup (curl); + return FALSE; + } + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, rspamd_cl_curl_write_callback); + cbdata.buf = buf; + cbdata.buflen = buflen; + curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); + + if ((r = curl_easy_perform (curl)) != CURLE_OK) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "error fetching URL %s: %s", + urlbuf, curl_easy_strerror (r)); + curl_easy_cleanup (curl); + if (buf != NULL) { + g_free (buf); + } + return FALSE; + } +#else + g_set_error (err, RCL_ERROR, RSPAMD_CL_EINTERNAL, "URL support is disabled"); + return FALSE; +#endif + + res = rspamd_cl_parser_add_chunk (parser, buf, buflen, err); + if (res == TRUE) { + /* Remove chunk from the stack */ + chunk = parser->chunks; + if (chunk != NULL) { + parser->chunks = chunk->next; + g_slice_free1 (sizeof (struct rspamd_cl_chunk), chunk); + } + } + g_free (buf); + + return res; +} + +/** + * Include a file to configuration + * @param data + * @param len + * @param parser + * @param err + * @return + */ +static gboolean +rspamd_cl_include_file (const guchar *data, gsize len, struct rspamd_cl_parser *parser, GError **err) +{ + gint fd; + struct stat st; + char filebuf[PATH_MAX]; + gpointer map; + gboolean res; + struct rspamd_cl_chunk *chunk; + + rspamd_snprintf (filebuf, sizeof (filebuf), "%*s", len, data); + if (stat (filebuf, &st) == -1) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "cannot stat file %s: %s", + filebuf, strerror (errno)); + return FALSE; + } + if ((fd = open (filebuf, O_RDONLY)) == -1) { + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "cannot open file %s: %s", + filebuf, strerror (errno)); + return FALSE; + } + if ((map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + close (fd); + g_set_error (err, RCL_ERROR, RSPAMD_CL_EIO, "cannot mmap file %s: %s", + filebuf, strerror (errno)); + return FALSE; + } + + close (fd); + + res = rspamd_cl_parser_add_chunk (parser, map, st.st_size, err); + if (res == TRUE) { + /* Remove chunk from the stack */ + chunk = parser->chunks; + if (chunk != NULL) { + parser->chunks = chunk->next; + g_slice_free1 (sizeof (struct rspamd_cl_chunk), chunk); + } + } + munmap (map, st.st_size); + + return res; +} + /** * Handle include macro * @param data include data @@ -246,7 +430,12 @@ rspamd_cl_include_handler (const guchar *data, gsize len, gpointer ud, GError ** { struct rspamd_cl_parser *parser = ud; - return TRUE; + if (*data == '/') { + /* Try to load a file */ + return rspamd_cl_include_file (data, len, parser, err); + } + + return rspamd_cl_include_url (data, len, parser, err); } /** -- 2.39.5