Hello community, here is the log from the commit of package lynx for openSUSE:Factory checked in at 2017-02-11 01:31:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lynx (Old) and /work/SRC/openSUSE:Factory/.lynx.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lynx" Changes: -------- --- /work/SRC/openSUSE:Factory/lynx/lynx.changes 2014-12-03 22:52:17.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.lynx.new/lynx.changes 2017-02-11 01:31:31.830741195 +0100 @@ -1,0 +2,7 @@ +Mon Feb 6 16:27:18 UTC 2017 - [email protected] + +- security update: + * CVE-2016-9179 [bsc#1008642] + + lynx-CVE-2016-9179.patch + +------------------------------------------------------------------- New: ---- lynx-CVE-2016-9179.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lynx.spec ++++++ --- /var/tmp/diff_new_pack.3htS23/_old 2017-02-11 01:31:33.266538556 +0100 +++ /var/tmp/diff_new_pack.3htS23/_new 2017-02-11 01:31:33.270537991 +0100 @@ -1,7 +1,7 @@ # # spec file for package lynx # -# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -38,6 +38,7 @@ Patch102: lynx-2.8.7-enable_xli.patch Patch103: lynx-no-build-date.patch Patch104: lynx-2.8.8-expired-cookie-crash.patch +Patch105: lynx-CVE-2016-9179.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build Provides: lynxssl = %version Obsoletes: lynxssl < %version @@ -56,6 +57,7 @@ %patch102 -p1 %patch103 %patch104 +%patch105 -p1 # containing a few test msg's only: # rm -f po/{es,fr,it,ko,no,pl,pt}.po ++++++ lynx-CVE-2016-9179.patch ++++++ Index: lynx2-8-8/WWW/Library/Implementation/HTTP.c =================================================================== --- lynx2-8-8.orig/WWW/Library/Implementation/HTTP.c 2017-02-06 18:52:54.585749847 +0100 +++ lynx2-8-8/WWW/Library/Implementation/HTTP.c 2017-02-06 19:17:22.161941448 +0100 @@ -417,27 +417,151 @@ int ws_netread(int fd, char *buf, int le #endif /* _WINDOWS */ /* + * RFC-1738 says we can have user/password using these ASCII characters + * safe = "$" | "-" | "_" | "." | "+" + * extra = "!" | "*" | "'" | "(" | ")" | "," + * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | + * "a" | "b" | "c" | "d" | "e" | "f" + * escape = "%" hex hex + * unreserved = alpha | digit | safe | extra + * uchar = unreserved | escape + * user = *[ uchar | ";" | "?" | "&" | "=" ] + * password = *[ uchar | ";" | "?" | "&" | "=" ] + * and we cannot have a password without user, i.e., no leading ":" + * and ":", "@", "/" must be encoded, i.e., will not appear as such. + * + * However, in a URL + * //<user>:<password>@<host>:<port>/<url-path> + * valid characters in the host are different, not allowing most of those + * punctuation characters. + * + * RFC-3986 amends this, using + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * reserved = gen-delims / sub-delims + * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + * and + * host = IP-literal / IPv4address / reg-name + * reg-name = *( unreserved / pct-encoded / sub-delims ) + */ +#define RFC_3986_UNRESERVED(c) (isalnum(UCH(c)) || strchr("-._~", UCH(c)) != 0) +#define RFC_3986_GEN_DELIMS(c) ((c) != 0 && strchr(":/?#[]@", UCH(c)) != 0) +#define RFC_3986_SUB_DELIMS(c) ((c) != 0 && strchr("!$&'()*+,;=", UCH(c)) != 0) + +static char *skip_user_passwd(char *host) +{ + char *result = 0; + char *s = host; + int pass = 0; + int ch; + int last = -1; + + while ((ch = UCH(*s)) != '\0') { + if (ch == '\0') { + break; + } else if (ch == ':') { + if (pass++) + break; + } else if (ch == '@') { + if (s != host && last != ':') + result = s; + break; + } else if (RFC_3986_GEN_DELIMS(ch)) { + if (!RFC_3986_GEN_DELIMS(s[1])) + break; + } else if (ch == '%') { + if (!(isxdigit(UCH(s[1])) && isxdigit(UCH(s[2])))) + break; + } else if (!(RFC_3986_UNRESERVED(ch) || + RFC_3986_SUB_DELIMS(ch))) { + break; + } + ++s; + last = ch; + } + return result; +} + +static char *fake_hostname(char *auth) +{ + char *result = NULL; + char *colon = NULL; + + StrAllocCopy(result, auth); + if ((colon = strchr(result, ':')) != 0) + *colon = '\0'; + if (strchr(result, '.') == 0) + FREE(result); + return result; +} + +/* * Strip any username from the given string so we retain only the host. */ static void strip_userid(char *host) { char *p1 = host; - char *p2 = StrChr(host, '@'); - char *fake; + char *p2 = skip_user_passwd(host); if (p2 != 0) { + char *msg = NULL; + char *auth = NULL; + char *save = NULL; + char *fake = NULL; + char *p3 = p2; + int gen_delims = 0; + int sub_delims = 0; + int my_delimit = UCH(*p2); + int do_trimming = (my_delimit == '@'); + *p2++ = '\0'; - if ((fake = HTParse(host, "", PARSE_HOST)) != NULL) { - char *msg = NULL; + StrAllocCopy(auth, host); - CTRACE((tfp, "parsed:%s\n", fake)); - HTSprintf0(&msg, gettext("Address contains a username: %s"), host); - HTAlert(msg); - FREE(msg); + /* + * Trailing "gen-delims" demonstrates that there is no user/password. + */ + while ((p3 != host) && RFC_3986_GEN_DELIMS(p3[-1])) { + ++gen_delims; + *(--p3) = '\0'; } - while ((*p1++ = *p2++) != '\0') { - ; + /* + * While legal, punctuation-only user/password is questionable. + */ + while ((p3 != host) && RFC_3986_SUB_DELIMS(p3[-1])) { + ++sub_delims; + *(--p3) = '\0'; + } + CTRACE((tfp, "trimmed:%s\n", host)); + StrAllocCopy(save, host); + + if (gen_delims || strcmp(save, auth)) { + HTSprintf0(&msg, + gettext("User/password may appear to be a hostname: '%s' (e.g, '%s')"), + auth, save); + do_trimming = !gen_delims; + } else if (*host == '\0' && sub_delims) { + HTSprintf0(&msg, + gettext("User/password contains only punctuation: %s"), + auth); + } else if ((fake = fake_hostname(host)) != NULL) { + HTSprintf0(&msg, + gettext("User/password may be confused with hostname: '%s' (e.g, '%s')"), + auth, fake); + } + if (msg != 0) + HTAlert(msg); + if (do_trimming) { + while ((*p1++ = *p2++) != '\0') { + ; + } + } + FREE(fake); + FREE(save); + FREE(auth); + FREE(msg); } } Index: lynx2-8-8/WWW/Library/Implementation/HTTCP.c =================================================================== --- lynx2-8-8.orig/WWW/Library/Implementation/HTTCP.c 2013-12-18 02:56:13.000000000 +0100 +++ lynx2-8-8/WWW/Library/Implementation/HTTCP.c 2017-02-06 19:21:15.081092383 +0100 @@ -1792,7 +1792,6 @@ int HTDoConnect(const char *url, int status = 0; char *line = NULL; char *p1 = NULL; - char *at_sign = NULL; char *host = NULL; #ifdef INET6 @@ -1814,14 +1813,8 @@ int HTDoConnect(const char *url, * Get node name and optional port number. */ p1 = HTParse(url, "", PARSE_HOST); - if ((at_sign = StrChr(p1, '@')) != NULL) { - /* - * If there's an @ then use the stuff after it as a hostname. - */ - StrAllocCopy(host, (at_sign + 1)); - } else { - StrAllocCopy(host, p1); - } + StrAllocCopy(host, p1); + strip_userid(host, FALSE); FREE(p1); HTSprintf0(&line, "%s%s", WWW_FIND_MESSAGE, host); Index: lynx2-8-8/WWW/Library/Implementation/HTTP.c =================================================================== --- lynx2-8-8.orig/WWW/Library/Implementation/HTTP.c 2017-02-06 19:19:32.719706928 +0100 +++ lynx2-8-8/WWW/Library/Implementation/HTTP.c 2017-02-06 19:23:34.346979724 +0100 @@ -500,7 +500,7 @@ static char *fake_hostname(char *auth) /* * Strip any username from the given string so we retain only the host. */ -static void strip_userid(char *host) +void strip_userid(char *host, int parse_only) { char *p1 = host; char *p2 = skip_user_passwd(host); @@ -550,7 +550,7 @@ static void strip_userid(char *host) gettext("User/password may be confused with hostname: '%s' (e.g, '%s')"), auth, fake); } - if (msg != 0) + if (msg != 0 && !parse_only) HTAlert(msg); if (do_trimming) { while ((*p1++ = *p2++) != '\0') { @@ -1198,7 +1198,7 @@ static int HTLoadHTTP(const char *arg, char *host = NULL; if ((host = HTParse(anAnchor->address, "", PARSE_HOST)) != NULL) { - strip_userid(host); + strip_userid(host, TRUE); HTBprintf(&command, "Host: %s%c%c", host, CR, LF); FREE(host); } Index: lynx2-8-8/WWW/Library/Implementation/HTUtils.h =================================================================== --- lynx2-8-8.orig/WWW/Library/Implementation/HTUtils.h 2014-02-05 01:50:18.000000000 +0100 +++ lynx2-8-8/WWW/Library/Implementation/HTUtils.h 2017-02-06 19:19:32.727707036 +0100 @@ -801,6 +801,8 @@ extern "C" { extern FILE *TraceFP(void); + extern void strip_userid(char *host, int warn); + #ifdef USE_SSL extern SSL *HTGetSSLHandle(void); extern void HTSSLInitPRNG(void); Index: lynx2-8-8/src/LYUtils.c =================================================================== --- lynx2-8-8.orig/src/LYUtils.c 2014-03-09 22:43:10.000000000 +0100 +++ lynx2-8-8/src/LYUtils.c 2017-02-06 19:19:32.727707036 +0100 @@ -4693,6 +4693,7 @@ BOOLEAN LYExpandHostForURL(char **Alloca * Do a DNS test on the potential host field as presently trimmed. - FM */ StrAllocCopy(host, Str); + strip_userid(host, FALSE); HTUnEscape(host); if (LYCursesON) { StrAllocCopy(MsgStr, WWW_FIND_MESSAGE);
