diff --git a/0001-vcc.y-factor-out-hexdigit-conversion.patch b/0001-vcc.y-factor-out-hexdigit-conversion.patch new file mode 100644 index 0000000..9ea00da --- /dev/null +++ b/0001-vcc.y-factor-out-hexdigit-conversion.patch @@ -0,0 +1,84 @@ +From 6c167138a204cd2e0580036bad32a51dae05c80b Mon Sep 17 00:00:00 2001 +From: Jan Engelhardt +Date: Mon, 17 Sep 2018 16:47:16 +0200 +Subject: [PATCH 1/5] vcc.y - factor out hexdigit conversion +References: https://github.com/libical/libical/pull/354 + +--- + src/libicalvcal/vcc.c | 17 +++++++++++------ + src/libicalvcal/vcc.y | 17 +++++++++++------ + 2 files changed, 22 insertions(+), 12 deletions(-) + +diff --git a/src/libicalvcal/vcc.c b/src/libicalvcal/vcc.c +index d47bc099..c2a743c2 100644 +--- a/src/libicalvcal/vcc.c ++++ b/src/libicalvcal/vcc.c +@@ -1126,6 +1126,15 @@ static int match_begin_end_name(int end) { + return 0; + } + ++static int hexdigit_decode(char c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return -1; ++} ++ + static char* lexGetQuotedPrintable() + { + char cur; +@@ -1139,12 +1148,8 @@ static char* lexGetQuotedPrintable() + int next[2]; + int i; + for (i = 0; i < 2; i++) { +- next[i] = lexGetc(); +- if (next[i] >= '0' && next[i] <= '9') +- c = c * 16 + next[i] - '0'; +- else if (next[i] >= 'A' && next[i] <= 'F') +- c = c * 16 + next[i] - 'A' + 10; +- else ++ next[i] = hexdigit_decode(lexGetc()); ++ if (next[i] < 0) + break; + } + if (i == 0) { +diff --git a/src/libicalvcal/vcc.y b/src/libicalvcal/vcc.y +index d97ea83b..45243df6 100644 +--- a/src/libicalvcal/vcc.y ++++ b/src/libicalvcal/vcc.y +@@ -947,6 +947,15 @@ static int match_begin_end_name(int end) { + return 0; + } + ++static int hexdigit_decode(char c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return -1; ++} ++ + static char* lexGetQuotedPrintable() + { + char cur; +@@ -960,12 +969,8 @@ static char* lexGetQuotedPrintable() + int next[2]; + int i; + for (i = 0; i < 2; i++) { +- next[i] = lexGetc(); +- if (next[i] >= '0' && next[i] <= '9') +- c = c * 16 + next[i] - '0'; +- else if (next[i] >= 'A' && next[i] <= 'F') +- c = c * 16 + next[i] - 'A' + 10; +- else ++ next[i] = hexdigit_decode(lexGetc()); ++ if (next[i] < 0) + break; + } + if (i == 0) { +-- +2.19.1 + diff --git a/0002-vcc.y-fix-infinite-loop-with-lower-case-hex-digits.patch b/0002-vcc.y-fix-infinite-loop-with-lower-case-hex-digits.patch new file mode 100644 index 0000000..fa85fcd --- /dev/null +++ b/0002-vcc.y-fix-infinite-loop-with-lower-case-hex-digits.patch @@ -0,0 +1,46 @@ +From bf83a0d664f46229836852f5b41539c263c3b921 Mon Sep 17 00:00:00 2001 +From: Jan Engelhardt +Date: Mon, 17 Sep 2018 16:36:36 +0200 +Subject: [PATCH 2/5] vcc.y - fix infinite loop with lower-case hex digits +References: https://github.com/libical/libical/pull/354 + +When lower-case hex digits are used in a quoted-printable-encoded +character, an infinite loop would occur in the vcard parser. + +"N;ENCODING=QUOTED-PRINTABLE:=c3=a4=c3=b6;=c3=bC=c3=9f\n" + +References: #353 +--- + src/libicalvcal/vcc.c | 2 ++ + src/libicalvcal/vcc.y | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/src/libicalvcal/vcc.c b/src/libicalvcal/vcc.c +index c2a743c2..29354df4 100644 +--- a/src/libicalvcal/vcc.c ++++ b/src/libicalvcal/vcc.c +@@ -1132,6 +1132,8 @@ static int hexdigit_decode(char c) + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; + return -1; + } + +diff --git a/src/libicalvcal/vcc.y b/src/libicalvcal/vcc.y +index 45243df6..a052e9a2 100644 +--- a/src/libicalvcal/vcc.y ++++ b/src/libicalvcal/vcc.y +@@ -953,6 +953,8 @@ static int hexdigit_decode(char c) + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; + return -1; + } + +-- +2.19.1 + diff --git a/0003-vcc.y-fix-infinite-loop-with-non-hex-digits.patch b/0003-vcc.y-fix-infinite-loop-with-non-hex-digits.patch new file mode 100644 index 0000000..af2b5e6 --- /dev/null +++ b/0003-vcc.y-fix-infinite-loop-with-non-hex-digits.patch @@ -0,0 +1,124 @@ +From 5d937a51725609adcfba2c663ca4c1fe65974a55 Mon Sep 17 00:00:00 2001 +From: Jan Engelhardt +Date: Mon, 17 Sep 2018 17:15:28 +0200 +Subject: [PATCH 3/5] vcc.y - fix infinite loop with non-hex digits +References: https://github.com/libical/libical/pull/354 + +When nonsensical characters are used in a QP character, +an infinite loop would occur in the vcard parser. + +"N;ENCODING=QUOTED-PRINTABLE:=c3=g4\n" + +References: #353 +--- + src/libicalvcal/vcc.c | 38 ++++++++++++++++---------------------- + src/libicalvcal/vcc.y | 38 ++++++++++++++++---------------------- + 2 files changed, 32 insertions(+), 44 deletions(-) + +diff --git a/src/libicalvcal/vcc.c b/src/libicalvcal/vcc.c +index 29354df4..f723a4e1 100644 +--- a/src/libicalvcal/vcc.c ++++ b/src/libicalvcal/vcc.c +@@ -1146,31 +1146,25 @@ static char* lexGetQuotedPrintable() + cur = lexGetc(); + switch (cur) { + case '=': { +- int c = 0; +- int next[2]; +- int i; +- for (i = 0; i < 2; i++) { +- next[i] = hexdigit_decode(lexGetc()); +- if (next[i] < 0) +- break; ++ int c = 0, d; ++ cur = lexGetc(); ++ if (cur == '\n') { ++ ++mime_lineNum; ++ break; + } +- if (i == 0) { +- /* single '=' follow by LINESEP is continuation sign? */ +- if (next[0] == '\n') { +- ++mime_lineNum; +- } +- else { +- lexPushLookaheadc('='); +- goto EndString; +- } ++ d = hexdigit_decode(cur); ++ if (d < 0) { ++ lexAppendc(cur); ++ break; + } +- else if (i == 1) { +- lexPushLookaheadc(next[1]); +- lexPushLookaheadc(next[0]); +- lexAppendc('='); +- } else { +- lexAppendc(c); ++ c = d << 4; ++ cur = lexGetc(); ++ d = hexdigit_decode(cur); ++ if (d < 0) { ++ lexAppendc(cur); ++ break; + } ++ lexAppendc(c | d); + break; + } /* '=' */ + case '\n': { +diff --git a/src/libicalvcal/vcc.y b/src/libicalvcal/vcc.y +index a052e9a2..4f52fe35 100644 +--- a/src/libicalvcal/vcc.y ++++ b/src/libicalvcal/vcc.y +@@ -967,31 +967,25 @@ static char* lexGetQuotedPrintable() + cur = lexGetc(); + switch (cur) { + case '=': { +- int c = 0; +- int next[2]; +- int i; +- for (i = 0; i < 2; i++) { +- next[i] = hexdigit_decode(lexGetc()); +- if (next[i] < 0) +- break; ++ int c = 0, d; ++ cur = lexGetc(); ++ if (cur == '\n') { ++ ++mime_lineNum; ++ break; + } +- if (i == 0) { +- /* single '=' follow by LINESEP is continuation sign? */ +- if (next[0] == '\n') { +- ++mime_lineNum; +- } +- else { +- lexPushLookaheadc('='); +- goto EndString; +- } ++ d = hexdigit_decode(cur); ++ if (d < 0) { ++ lexAppendc(cur); ++ break; + } +- else if (i == 1) { +- lexPushLookaheadc(next[1]); +- lexPushLookaheadc(next[0]); +- lexAppendc('='); +- } else { +- lexAppendc(c); ++ c = d << 4; ++ cur = lexGetc(); ++ d = hexdigit_decode(cur); ++ if (d < 0) { ++ lexAppendc(cur); ++ break; + } ++ lexAppendc(c | d); + break; + } /* '=' */ + case '\n': { +-- +2.19.1 + diff --git a/0004-vobject.c-vCard-Unicode-reading-support.patch b/0004-vobject.c-vCard-Unicode-reading-support.patch new file mode 100644 index 0000000..ec2fbe8 --- /dev/null +++ b/0004-vobject.c-vCard-Unicode-reading-support.patch @@ -0,0 +1,140 @@ +From aacb3875a9a645880cbfe014fb0c4cb078ff4342 Mon Sep 17 00:00:00 2001 +From: Jan Engelhardt +Date: Mon, 17 Sep 2018 21:27:43 +0200 +Subject: [PATCH 4/5] vobject.c - vCard Unicode reading support +References: https://github.com/libical/libical/pull/354 + +RFC 6350 declares vCard to be UTF-8 throughout without exceptions. + +However, any non-ASCII vCard content is garbled because the +"fakeUnicode" botched the conversion to wchar_t: The conversion just +copies values from char to wchar_t, which is neither correct for +UTF-8 nor (a hypothetical) ISO-8859-1/-15 coded input. + +This patch fixes that. + +References: #353 +--- + src/libicalvcal/vobject.c | 94 ++++++++++++++++++++++++++++++++------- + 1 file changed, 78 insertions(+), 16 deletions(-) + +diff --git a/src/libicalvcal/vobject.c b/src/libicalvcal/vobject.c +index 10d0cf5a..b880716f 100644 +--- a/src/libicalvcal/vobject.c ++++ b/src/libicalvcal/vobject.c +@@ -45,6 +45,9 @@ DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + #ifdef HAVE_CONFIG_H + #include + #endif ++#include ++#include ++#include + + #include "vobject.h" + +@@ -1414,27 +1417,86 @@ char* writeMemVObjects(char *s, int *len, VObject *list) + /*---------------------------------------------------------------------- + APIs to do fake Unicode stuff. + ----------------------------------------------------------------------*/ ++/* ++ * Convert UTF-8 to wide chars. ++ * ++ * The only place where this spells Unicode is 1.) in "UTF-8", 2.) when it does ++ * the secondary pass to replace \n and \r with U+2028 and 2029, respectively. ++ * That step blindly pretends wchar_t shares the Unicode codepoints (happens to ++ * work for the important contemporary platforms, but otherwise is nonsense). ++ */ + wchar_t* fakeUnicode(const char *ps, size_t *bytes) + { +- wchar_t *r, *pw; +- size_t len = strlen(ps)+1; ++ /* ++ * Assuming the input were all ASCII, then ++ * ++ * method1_out_size = zs * sizeof(wchar_t) ++ * ++ * would make sense. But if the input were all 3-byte UTF-8 codepoints, ++ * then that would be a large wasteful allocation, and ++ * ++ * method2_out_size = zs * sizeof(wchar_t) / 3 ++ * ++ * would be more reasonable. Since there is no way of knowing in ++ * advance what is in @ps, method 1 will be chosen if that is a 1KB ++ * allocation (or less), and method 2 otherwise. From there, the ++ * standard exponential progression for realloc is applied. ++ */ ++ size_t zs = strlen(ps), out_size, out_rem; ++ char *out_block, *out_iter; ++ iconv_t conv = iconv_open("wchar_t", "utf-8"); + +- pw = r = (wchar_t*)malloc(sizeof(wchar_t)*len); +- if (bytes) +- *bytes = len * sizeof(wchar_t); ++ if (conv == (iconv_t)-1) ++ return NULL; ++ if (zs >= (SIZE_MAX - sizeof(wchar_t)) / sizeof(wchar_t)) ++ /* Input is larger than anything we want to handle */ ++ return NULL; ++ /* Initial allocation size as per above. */ ++ out_size = out_rem = zs * sizeof(wchar_t); ++ if (out_size >= 1024 - sizeof(wchar_t)) ++ out_size /= 3; ++ out_iter = out_block = malloc(out_size + sizeof(wchar_t)); ++ if (out_block == NULL) { ++ iconv_close(conv); ++ return NULL; ++ } + +- while (*ps) { +- if (*ps == '\n') +- *pw = (wchar_t)0x2028; +- else if (*ps == '\r') +- *pw = (wchar_t)0x2029; +- else +- *pw = (wchar_t)(unsigned char)*ps; +- ps++; pw++; +- } +- *pw = (wchar_t)0; ++ while (zs > 0) { ++ int ret; ++ errno = 0; ++ ret = iconv(conv, (char **)&ps, &zs, &out_iter, &out_rem); ++ if (ret >= 0) ++ continue; ++ if (errno == EILSEQ || errno == EINVAL) { ++ ++ps; ++ --zs; ++ continue; ++ } ++ if (errno != E2BIG) ++ break; ++ out_rem += out_size; ++ out_size *= 2; ++ char *new_block = realloc(out_block, out_size + sizeof(wchar_t)); ++ if (new_block == NULL) { ++ free(out_block); ++ iconv_close(conv); ++ return NULL; ++ } ++ out_iter = new_block + (out_iter - out_block); ++ out_block = new_block; ++ } + +- return r; ++ wchar_t *wide = (wchar_t *)out_block, *p = wide; ++ for (; p < (wchar_t *)(out_block + out_size - out_rem); ++p) { ++ if (*p == '\n') ++ *p = 0x2028; ++ else if (*p == '\r') ++ *p = 0x2029; ++ } ++ *p = L'\0'; ++ if (bytes != NULL) ++ *bytes = (char *)p - out_block; ++ return wide; + } + + int uStrLen(const wchar_t *u) +-- +2.19.1 + diff --git a/0005-vcc.y-do-not-ignore-field-separator-in-QUOTED-PRINTA.patch b/0005-vcc.y-do-not-ignore-field-separator-in-QUOTED-PRINTA.patch new file mode 100644 index 0000000..407cda9 --- /dev/null +++ b/0005-vcc.y-do-not-ignore-field-separator-in-QUOTED-PRINTA.patch @@ -0,0 +1,52 @@ +From 5fbba6b0db3e13bb42a6208c408497469e501a26 Mon Sep 17 00:00:00 2001 +From: Jan Engelhardt +Date: Mon, 17 Sep 2018 22:05:03 +0200 +Subject: [PATCH 5/5] vcc.y - do not ignore field separator in QUOTED-PRINTABLE + mode +References: https://github.com/libical/libical/pull/354 + +"N;ENCODING=QUOTED-PRINTABLE:=C3=A4=C3=B6;=C3=BC=C3=9F\n" + +was parsed as a single field, while in fact, it is two. + +References: #353 +--- + src/libicalvcal/vcc.c | 5 +++-- + src/libicalvcal/vcc.y | 5 +++-- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/libicalvcal/vcc.c b/src/libicalvcal/vcc.c +index f723a4e1..fd056992 100644 +--- a/src/libicalvcal/vcc.c ++++ b/src/libicalvcal/vcc.c +@@ -1167,8 +1167,9 @@ static char* lexGetQuotedPrintable() + lexAppendc(c | d); + break; + } /* '=' */ +- case '\n': { +- lexPushLookaheadc('\n'); ++ case '\n': ++ case ';': { ++ lexPushLookaheadc(cur); + goto EndString; + } + case (char)EOF: +diff --git a/src/libicalvcal/vcc.y b/src/libicalvcal/vcc.y +index 4f52fe35..df770df6 100644 +--- a/src/libicalvcal/vcc.y ++++ b/src/libicalvcal/vcc.y +@@ -988,8 +988,9 @@ static char* lexGetQuotedPrintable() + lexAppendc(c | d); + break; + } /* '=' */ +- case '\n': { +- lexPushLookaheadc('\n'); ++ case '\n': ++ case ';': { ++ lexPushLookaheadc(cur); + goto EndString; + } + case (char)EOF: +-- +2.19.1 + diff --git a/libical.changes b/libical.changes index 2174d92..c9fcfea 100644 --- a/libical.changes +++ b/libical.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Fri Nov 9 00:52:39 UTC 2018 - Jan Engelhardt + +- Add patches 0001-vcc.y-factor-out-hexdigit-conversion.patch, + 0002-vcc.y-fix-infinite-loop-with-lower-case-hex-digits.patch, + 0003-vcc.y-fix-infinite-loop-with-non-hex-digits.patch, + 0004-vobject.c-vCard-Unicode-reading-support.patch, + 0005-vcc.y-do-not-ignore-field-separator-in-QUOTED-PRINTA.patch + to support Unicode in VCF (and fix infinite loops). + [https://github.com/libical/libical/pull/354 ] + ------------------------------------------------------------------- Thu Aug 23 21:31:54 UTC 2018 - jengelh@inai.de diff --git a/libical.spec b/libical.spec index d3a9d76..680aee3 100644 --- a/libical.spec +++ b/libical.spec @@ -12,7 +12,7 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # @@ -27,6 +27,11 @@ Url: http://sourceforge.net/projects/freeassociation/ #Git-Clone: https://github.com/libical/libical Source: https://github.com/libical/libical/releases/download/v%{version}/%{name}-%{version}.tar.gz Source2: baselibs.conf +Patch1: 0001-vcc.y-factor-out-hexdigit-conversion.patch +Patch2: 0002-vcc.y-fix-infinite-loop-with-lower-case-hex-digits.patch +Patch3: 0003-vcc.y-fix-infinite-loop-with-non-hex-digits.patch +Patch4: 0004-vobject.c-vCard-Unicode-reading-support.patch +Patch5: 0005-vcc.y-do-not-ignore-field-separator-in-QUOTED-PRINTA.patch BuildRequires: cmake >= 3.1 BuildRequires: gcc-c++ BuildRequires: pkgconfig @@ -75,7 +80,7 @@ parses iCal components and provides a C API for manipulating the component properties, parameters, and subcomponents. %prep -%setup -q +%autosetup -p1 %build %cmake -DICAL_GLIB=false -DSHARED_ONLY=true