Complete 32-bit Trixie compatibility fixes
This commit is contained in:
@@ -20,15 +20,15 @@
|
||||
# ****************************************************************************/
|
||||
|
||||
find_path(GMime_INCLUDE_DIR NAMES gmime/gmime.h
|
||||
PATH_SUFFIXES gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
|
||||
find_library(GMime_LIBRARY NAMES gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
|
||||
PATH_SUFFIXES gmime-3.0 gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
|
||||
find_library(GMime_LIBRARY NAMES gmime-3.0 gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
|
||||
|
||||
if(GMime_INCLUDE_DIR AND EXISTS "${GMime_INCLUDE_DIR}/gmime/gmime-version.h")
|
||||
file(STRINGS "${GMime_INCLUDE_DIR}/gmime/gmime-version.h"
|
||||
_GMime_VERSION_LINES
|
||||
REGEX "^#define GMIME_(MAJOR|MINOR|MICRO)_VERSION[ \t]+\\([0-9]+\\)")
|
||||
REGEX "^#define GMIME_(MAJOR|MINOR|MICRO)_VERSION[ \t]+\\([0-9]+U?\\)")
|
||||
foreach(_component MAJOR MINOR MICRO)
|
||||
string(REGEX MATCH "GMIME_${_component}_VERSION[ \t]+\\(([0-9]+)\\)"
|
||||
string(REGEX MATCH "GMIME_${_component}_VERSION[ \t]+\\(([0-9]+)U?\\)"
|
||||
_GMime_VERSION_MATCH "${_GMime_VERSION_LINES}")
|
||||
set(_GMime_VERSION_${_component} "${CMAKE_MATCH_1}")
|
||||
endforeach()
|
||||
|
||||
+12
-8
@@ -240,14 +240,14 @@ SendRFC822Address(ImapSession *session, char *Address, char *Answer)
|
||||
return(STATUS_ABORT);
|
||||
}
|
||||
|
||||
static void
|
||||
MakeRFC822Header(char *Header, unsigned long *HSize)
|
||||
static size_t
|
||||
MakeRFC822Header(char *Header, size_t headerSize)
|
||||
{
|
||||
char *NL, *ptr, *ptr2, *start=Header;
|
||||
BOOL StripLine, KeepGoing=TRUE;
|
||||
|
||||
ptr=Header;
|
||||
Header[*HSize]='\0';
|
||||
Header[headerSize]='\0';
|
||||
while (KeepGoing) {
|
||||
StripLine=FALSE;
|
||||
NL=strchr(ptr,0x0a);
|
||||
@@ -286,7 +286,7 @@ MakeRFC822Header(char *Header, unsigned long *HSize)
|
||||
KeepGoing=FALSE;
|
||||
}
|
||||
}
|
||||
*HSize=strlen(Header);
|
||||
return strlen(Header);
|
||||
}
|
||||
|
||||
__inline static char *
|
||||
@@ -3328,16 +3328,20 @@ GetMessageHeader(ImapSession *session, FetchStruct *FetchRequest)
|
||||
size_t count;
|
||||
|
||||
/* Request the header */
|
||||
if (NMAPSendCommandF(session->store.conn, "READ %" PRIx64 " 0 %lu\r\n", FetchRequest->message->guid, FetchRequest->message->headerSize) != -1) {
|
||||
if (NMAPSendCommandF(session->store.conn, "READ %" PRIx64 " 0 %" PRIu64 "\r\n", FetchRequest->message->guid, FetchRequest->message->headerSize) != -1) {
|
||||
if ((ccode = NMAPReadPropertyValueLength(session->store.conn, "nmap.document", &count)) == 2001) {
|
||||
FetchRequest->message->headerSize = (long)count;
|
||||
if (count > INT_MAX) {
|
||||
return STATUS_FETCH_LIMIT;
|
||||
}
|
||||
FetchRequest->message->headerSize = count;
|
||||
FetchRequest->messageDetail.header = MemMalloc(FetchRequest->message->headerSize + 1);
|
||||
if (FetchRequest->messageDetail.header) {
|
||||
if ((ccode = NMAPReadCount(session->store.conn, FetchRequest->messageDetail.header, FetchRequest->message->headerSize)) > 0) {
|
||||
if ((unsigned long)ccode == FetchRequest->message->headerSize) {
|
||||
if ((size_t)ccode == count) {
|
||||
if (NMAPReadCrLf(session->store.conn) == 2) {
|
||||
FetchRequest->messageDetail.header[FetchRequest->message->headerSize] = '\0';
|
||||
MakeRFC822Header(FetchRequest->messageDetail.header, &FetchRequest->message->headerSize);
|
||||
FetchRequest->message->headerSize = MakeRFC822Header(
|
||||
FetchRequest->messageDetail.header, count);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -108,9 +108,17 @@ StoreProcessIncomingMail(StoreClient *client,
|
||||
|
||||
stream = g_mime_stream_fs_new(fd);
|
||||
parser = g_mime_parser_new_with_stream(stream);
|
||||
#if GMIME_MAJOR_VERSION >= 3
|
||||
g_mime_parser_set_format(parser, GMIME_FORMAT_MESSAGE);
|
||||
#else
|
||||
g_mime_parser_set_scan_from (parser, FALSE);
|
||||
#endif
|
||||
g_object_unref(stream);
|
||||
#if GMIME_MAJOR_VERSION >= 3
|
||||
message = g_mime_parser_construct_message(parser, NULL);
|
||||
#else
|
||||
message = g_mime_parser_construct_message(parser);
|
||||
#endif
|
||||
g_object_unref(parser);
|
||||
|
||||
if (message == NULL) {
|
||||
@@ -143,7 +151,7 @@ StoreProcessIncomingMail(StoreClient *client,
|
||||
|
||||
// treat message ID specially because we want to invent one if it
|
||||
// doesn't already exist.
|
||||
message_id = message->message_id;
|
||||
message_id = g_mime_message_get_message_id(message);
|
||||
if (!message_id) {
|
||||
snprintf(generated_message_id, sizeof(generated_message_id),
|
||||
"%u." GUID_FMT "@%s", document->time_created,
|
||||
@@ -154,7 +162,11 @@ StoreProcessIncomingMail(StoreClient *client,
|
||||
message_id);
|
||||
ConnWrite(cpipe, outstr, outstr_size);
|
||||
|
||||
#if GMIME_MAJOR_VERSION >= 3
|
||||
header_str = g_mime_object_get_headers(GMIME_OBJECT(message), NULL);
|
||||
#else
|
||||
header_str = g_mime_object_get_headers(GMIME_OBJECT(message));
|
||||
#endif
|
||||
|
||||
if (header_str != NULL) {
|
||||
snprintf(prop, XPL_MAX_PATH, FMT_UINT64_DEC, (uint64_t)strlen(header_str));
|
||||
|
||||
@@ -344,7 +344,11 @@ _XplServiceMain(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// initialize the mail parsing code
|
||||
#if GMIME_MAJOR_VERSION >= 3
|
||||
g_mime_init();
|
||||
#else
|
||||
g_mime_init(0);
|
||||
#endif
|
||||
|
||||
// create lock pool
|
||||
StoreInitializeFairLocks();
|
||||
|
||||
@@ -367,6 +367,8 @@ BongoSieveEvaluate(const char *script, size_t script_length,
|
||||
mu_static_memory_stream_create(&stream, message, message_length) != 0 ||
|
||||
mu_message_create(&mail, NULL) != 0 ||
|
||||
mu_message_set_stream(mail, stream, NULL) != 0) goto finish;
|
||||
/* mu_message_set_stream() transfers ownership of this reference. */
|
||||
stream = NULL;
|
||||
mu_sieve_set_data(machine, &context);
|
||||
if (!install_bongo_actions(machine) ||
|
||||
mu_sieve_compile_text(machine, normalized, normalized_length, &origin) != 0) goto finish;
|
||||
@@ -396,6 +398,7 @@ finish:
|
||||
mu_message_unref(mail);
|
||||
mail = NULL;
|
||||
}
|
||||
/* Only failures before mu_message_set_stream() leave stream owned here. */
|
||||
if (stream) mu_stream_unref(stream);
|
||||
if (machine) mu_sieve_machine_destroy(&machine);
|
||||
free(normalized);
|
||||
|
||||
@@ -50,6 +50,27 @@ DATA_IMAGE = re.compile(
|
||||
r"^data:image/(?:png|jpeg|gif|webp);base64,[A-Za-z0-9+/=\r\n]+$",
|
||||
re.IGNORECASE)
|
||||
MAX_DATA_IMAGE_URL = 350000
|
||||
SAFE_STYLE_VALUE = re.compile(r"^[A-Za-z0-9 #(),.%+/'\"_-]+$")
|
||||
|
||||
|
||||
def _sanitize_style(value):
|
||||
"""Keep a conservative subset of inline CSS on HTML mail."""
|
||||
declarations = []
|
||||
for declaration in value.split(";"):
|
||||
if not declaration.strip() or ":" not in declaration:
|
||||
continue
|
||||
name, css_value = declaration.split(":", 1)
|
||||
name = name.strip().casefold()
|
||||
css_value = css_value.strip()
|
||||
if name not in ALLOWED_STYLE_PROPERTIES:
|
||||
continue
|
||||
if not css_value or not SAFE_STYLE_VALUE.fullmatch(css_value):
|
||||
continue
|
||||
lowered = css_value.casefold()
|
||||
if "url(" in lowered or "expression(" in lowered:
|
||||
continue
|
||||
declarations.append("{}:{}".format(name, css_value))
|
||||
return ";".join(declarations) or None
|
||||
|
||||
|
||||
def sanitize_html(html, cleaner=None):
|
||||
@@ -59,6 +80,8 @@ def sanitize_html(html, cleaner=None):
|
||||
remote_images = []
|
||||
|
||||
def filter_attribute(tag, attribute, value):
|
||||
if attribute == "style":
|
||||
return _sanitize_style(value)
|
||||
if attribute == "src" and tag == "img":
|
||||
scheme = urlsplit(value).scheme.casefold()
|
||||
if scheme in ("http", "https"):
|
||||
@@ -87,6 +110,5 @@ def sanitize_html(html, cleaner=None):
|
||||
"embed", "form", "svg", "math", "meta", "link"},
|
||||
attributes=ALLOWED_ATTRIBUTES, attribute_filter=filter_attribute,
|
||||
link_rel="noopener noreferrer nofollow",
|
||||
url_schemes={"http", "https", "mailto", "cid", "data", "bongo-remote"},
|
||||
filter_style_properties=ALLOWED_STYLE_PROPERTIES)
|
||||
url_schemes={"http", "https", "mailto", "cid", "data", "bongo-remote"})
|
||||
return {"html": sanitized, "remote_images": remote_images}
|
||||
|
||||
@@ -60,11 +60,22 @@ class HtmlMailTests(unittest.TestCase):
|
||||
self.assertNotIn("alert", output)
|
||||
self.assertNotIn("position", output)
|
||||
self.assertNotIn("background-image", output)
|
||||
self.assertIn('style="color:red"', output)
|
||||
self.assertIn('src="cid:logo"', output)
|
||||
self.assertIn('src="bongo-remote:0"', output)
|
||||
self.assertEqual(result["remote_images"],
|
||||
["https://tracker.example/pixel"])
|
||||
|
||||
def test_style_filter_rejects_obfuscated_and_active_values(self):
|
||||
result = sanitize_html(
|
||||
'<p style="color:e\\78pression(alert(1));'
|
||||
'background-color:url(https://tracker.example/pixel);'
|
||||
'font-weight:bold">safe</p>')
|
||||
output = result["html"]
|
||||
self.assertNotIn("expression", output)
|
||||
self.assertNotIn("url", output)
|
||||
self.assertIn("font-weight:bold", output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user