elinks: replace with 0.12pre6 + Fedora patches

This commit is contained in:
Tom G. Christensen 2020-03-08 20:26:26 +01:00
parent 8948cceb99
commit 9bc0c578f6
14 changed files with 2365 additions and 6 deletions

View File

@ -6,13 +6,25 @@
########################################################### ###########################################################
# Check the following 4 variables before running the script # Check the following 4 variables before running the script
topdir=elinks topdir=elinks
version=0.13-0.1.4efea7e version=0.12pre6
pkgver=2 pkgver=3
source[0]=http://repo.or.cz/elinks.git/snapshot/4efea7e314b49df660799e71ede713dff0cd1230.tar.gz source[0]=http://elinks.or.cz/download/elinks-${version}.tar.bz2
# If there are no patches, simply comment this # If there are no patches, simply comment this
patch[0]=elinks-socklen_t.patch patch[0]=elinks-socklen_t.patch
patch[1]=elinks-inet_aton.patch patch[1]=elinks-inet_aton.patch
patch[2]=elinks-0.12pre6-libidn2.patch patch[2]=elinks-0.11.0-getaddrinfo.patch
patch[3]=elinks-0.11.0-ssl-noegd.patch
patch[4]=elinks-0.11.0-sysname.patch
patch[5]=elinks-0.11.3-macropen.patch
patch[6]=elinks-0.12pre5-ddg-search.patch
patch[7]=elinks-0.12pre6-autoconf.patch
patch[8]=elinks-0.12pre6-libidn2.patch
patch[9]=elinks-0.12pre6-list_is_singleton.patch
patch[10]=elinks-0.12pre6-openssl11.patch
patch[11]=elinks-0.12pre6-recent-gcc-versions.patch
patch[12]=elinks-0.12pre6-ssl-hostname.patch
patch[13]=elinks-0.12pre6-static-analysis.patch
patch[14]=elinks-scroll.patch
# Source function library # Source function library
. ${BUILDPKG_SCRIPTS}/buildpkg.functions . ${BUILDPKG_SCRIPTS}/buildpkg.functions
@ -23,14 +35,20 @@ export CPPFLAGS="-I$prefix/lib"
export LDFLAGS="-L$prefix/lib -R$prefix/lib" export LDFLAGS="-L$prefix/lib -R$prefix/lib"
ac_overrides="ac_cv_func_mmap_fixed_mapped=no" ac_overrides="ac_cv_func_mmap_fixed_mapped=no"
topsrcdir=${topdir}-4efea7e configure_args+=(--without-x --enable-256-colors)
configure_args+=(--without-x --with-lzma)
reg prep reg prep
prep() prep()
{ {
generic_prep generic_prep
setdir source setdir source
# rename the input file of autoconf to eliminate a warning
mv configure.in configure.ac
${__gsed} -e 's/configure\.in/configure.ac/' \
-i Makefile* acinclude.m4 doc/man/man1/Makefile
# remove bogus serial numbers
${__gsed} -i 's/^# *serial [AM0-9]*$//' acinclude.m4 config/m4/*.m4
bash autogen.sh bash autogen.sh
} }

View File

@ -1,5 +1,10 @@
CHANGELOG CHANGELOG
--------- ---------
* Sun Mar 08 2020 Tom G. Christensen <swpkg@jupiterrise.com> - 0.12pre6-3
- Downgrade to 0.12pre6 + Fedora patchset
Upstream is dead and the Fedora patches will not apply
cleanly to the git snapshot used previously
* Wed Dec 21 2016 Tom G. Christensen <swpkg@jupiterrise.com> - 0.13-0.1.4efea7e-2 * Wed Dec 21 2016 Tom G. Christensen <swpkg@jupiterrise.com> - 0.13-0.1.4efea7e-2
- Add support for libidn2 (via patch from fedora) - Add support for libidn2 (via patch from fedora)

View File

@ -0,0 +1,25 @@
--- elinks-0.11.0/src/network/dns.c.getaddrinfo 2006-01-01 17:39:36.000000000 +0100
+++ elinks-0.11.0/src/network/dns.c 2006-01-10 09:30:56.000000000 +0100
@@ -157,9 +157,21 @@ do_real_lookup(unsigned char *name, struct sockaddr_storage **addrs, int *addrno
* But we duplicate the code terribly here :|. */
/* hostent = getipnodebyname(name, AF_INET6, AI_ALL | AI_ADDRCONFIG, NULL); */
memset(&hint, 0, sizeof(hint));
+ hint.ai_flags = AI_ADDRCONFIG;
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
- if (getaddrinfo(name, NULL, &hint, &ai) != 0) return DNS_ERROR;
+ switch (getaddrinfo(name, NULL, &hint, &ai))
+ {
+ case 0:
+ break;
+ case EAI_BADFLAGS:
+ hint.ai_flags = 0;
+ if (getaddrinfo(name, NULL, &hint, &ai) == 0)
+ break;
+ /* fall through */
+ default:
+ return DNS_ERROR;
+ }
#else
/* Seems there are problems on Mac, so we first need to try

View File

@ -0,0 +1,21 @@
--- elinks-0.11.0/src/network/ssl/ssl.c.noegd 2006-01-10 09:24:50.000000000 +0100
+++ elinks-0.11.0/src/network/ssl/ssl.c 2006-01-10 09:25:01.000000000 +0100
@@ -44,18 +44,6 @@ SSL_CTX *context = NULL;
static void
init_openssl(struct module *module)
{
- unsigned char f_randfile[PATH_MAX];
-
- /* In a nutshell, on OS's without a /dev/urandom, the OpenSSL library
- * cannot initialize the PRNG and so every attempt to use SSL fails.
- * It's actually an OpenSSL FAQ, and according to them, it's up to the
- * application coders to seed the RNG. -- William Yodlowsky */
- if (RAND_egd(RAND_file_name(f_randfile, sizeof(f_randfile))) < 0) {
- /* Not an EGD, so read and write to it */
- if (RAND_load_file(f_randfile, -1))
- RAND_write_file(f_randfile);
- }
-
SSLeay_add_ssl_algorithms();
context = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_options(context, SSL_OP_ALL);

View File

@ -0,0 +1,20 @@
--- elinks-0.11.0/src/osdep/sysname.c.sysname 2006-01-01 17:39:36.000000000 +0100
+++ elinks-0.11.0/src/osdep/sysname.c 2006-01-10 09:34:14.000000000 +0100
@@ -26,7 +26,7 @@
FILE *f;
unsigned char *p;
- f = popen("uname -srm", "r");
+ f = popen("uname -s", "r");
if (!f) return 0;
if (fread(system_name, 1, sizeof(system_name) - 1, f) <= 0) {
@@ -58,7 +58,7 @@
if (!uname(&name)) {
snprintf(system_name, sizeof(system_name),
- "%s %s %s", name.sysname, name.release, name.machine);
+ "%s", name.sysname);
return;
}
#endif

View File

@ -0,0 +1,16 @@
src/encoding/encoding.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/encoding/encoding.c b/src/encoding/encoding.c
index d019dab..9648da3 100644
--- a/src/encoding/encoding.c
+++ b/src/encoding/encoding.c
@@ -124,7 +124,7 @@ open_encoded(int fd, enum stream_encoding encoding)
if (!stream) return NULL;
stream->encoding = encoding;
- if (decoding_backends[stream->encoding]->open(stream, fd) >= 0)
+ if ((decoding_backends[stream->encoding]->open)(stream, fd) >= 0)
return stream;
mem_free(stream);

View File

@ -0,0 +1,51 @@
From a96d8a17e57343ff29736a2f8d0c954f2c4ba02a Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Tue, 18 Sep 2012 15:32:31 +0200
Subject: [PATCH] rewrite: add default "ddg" dumb/smart prefixes for DuckDuckGo
... and mention that URI rewriting rules may leak ELinks' identity
in the documentation of protocol.http.user_agent.
Originally requested at <https://bugzilla.redhat.com/856348>.
---
src/protocol/http/http.c | 3 ++-
src/protocol/rewrite/rewrite.c | 2 ++
2 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/src/protocol/http/http.c b/src/protocol/http/http.c
index ce14031..98053c0 100644
--- a/src/protocol/http/http.c
+++ b/src/protocol/http/http.c
@@ -227,7 +227,8 @@ static union option_info http_options[] = {
"pushing some lite version to them automagically.\n"
"\n"
"Use \" \" if you don't want any User-Agent header to be sent "
- "at all.\n"
+ "at all. URI rewriting rules may still include parameters "
+ "that reveal you are using ELinks.\n"
"\n"
"%v in the string means ELinks version,\n"
"%s in the string means system identification,\n"
diff --git a/src/protocol/rewrite/rewrite.c b/src/protocol/rewrite/rewrite.c
index dd5c7ab..e01da74 100644
--- a/src/protocol/rewrite/rewrite.c
+++ b/src/protocol/rewrite/rewrite.c
@@ -121,6 +121,7 @@ static union option_info uri_rewrite_options[] = {
INIT_OPT_DUMB_PREFIX("cia", "http://cia.navi.cx/"),
INIT_OPT_DUMB_PREFIX("b", "http://babelfish.altavista.com/babelfish/tr"),
INIT_OPT_DUMB_PREFIX("d", "http://www.dict.org"),
+ INIT_OPT_DUMB_PREFIX("ddg", "http://duckduckgo.com/?t=elinks"),
INIT_OPT_DUMB_PREFIX("g", "http://www.google.com/"),
INIT_OPT_DUMB_PREFIX("gg", "http://www.google.com/"),
INIT_OPT_DUMB_PREFIX("go", "http://www.google.com/"),
@@ -158,6 +159,7 @@ static union option_info uri_rewrite_options[] = {
INIT_OPT_SMART_PREFIX("cambridge", "http://dictionary.cambridge.org/results.asp?searchword=%s"),
INIT_OPT_SMART_PREFIX("cliki", "http://www.cliki.net/admin/search?words=%s"),
INIT_OPT_SMART_PREFIX("d", "http://www.dict.org/bin/Dict?Query=%s&Form=Dict1&Strategy=*&Database=*&submit=Submit+query"),
+ INIT_OPT_SMART_PREFIX("ddg", "http://duckduckgo.com/?q=%s&t=elinks"),
INIT_OPT_SMART_PREFIX("dmoz", "http://search.dmoz.org/cgi-bin/search?search=%s"),
INIT_OPT_SMART_PREFIX("foldoc", "http://wombat.doc.ic.ac.uk/foldoc/foldoc.cgi?%s"),
INIT_OPT_SMART_PREFIX("g", "http://www.google.com/search?q=%s&btnG=Google+Search"),
--
1.7.1

View File

@ -0,0 +1,35 @@
From d7380abead73dc753023ef598b87944756c08d40 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Mon, 25 Feb 2013 15:31:07 +0100
Subject: [PATCH] configure.in: add missing AC_LANG_PROGRAM
... around the first argument of AC_COMPILE_IFELSE
---
configure.in | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure.in b/configure.in
index 2629ac3..4290e45 100644
--- a/configure.in
+++ b/configure.in
@@ -220,7 +220,7 @@ AC_STRUCT_TM
AC_C_CONST
AC_C_INLINE
AC_MSG_CHECKING([[for C99-conforming inline]])
-AC_COMPILE_IFELSE([[
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
int add(int change);
static int sum;
@@ -236,7 +236,7 @@ AC_COMPILE_IFELSE([[
sub(int change)
{
return add(-change);
- }]],
+ }]])],
[AC_MSG_RESULT([[yes]])
AC_DEFINE([NONSTATIC_INLINE], [inline],
[Define as inline if the compiler lets you declare a function without inline, then define it with inline, and have that definition refer to identifiers with internal linkage. This is allowed by C99 6.7.4p6 and 6.7.4p3 together. Otherwise define as nothing.])],
--
1.7.1

View File

@ -0,0 +1,38 @@
From 701b16e0ee6f159cbf8498f4569022005dfdebbd Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Wed, 19 Mar 2014 11:48:34 +0100
Subject: [PATCH] lists.h: list_is_singleton() now returns false for empty list
We have a crash report of ELinks 0.12pre6 with backtrace going through
bookmark_all_terminals(). I believe it is caused by list_is_singleton()
returning true for an empty list. Consequently, bookmark_terminal()
attempts to access a list item that does not exist.
While it would be possible to fix bookmark_all_terminals() to explicitly
check the list for emptiness, I propose to fix list_is_singleton() such
that it does not return true for an empty list. I checked the other
uses of list_is_singleton() and the proposed change should not introduce
any change in the behavior elsewhere.
Bug: https://bugzilla.redhat.com/1075415
---
src/util/lists.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/util/lists.h b/src/util/lists.h
index b577c9f..9da38ae 100644
--- a/src/util/lists.h
+++ b/src/util/lists.h
@@ -146,7 +146,8 @@ do { \
#define list_empty(x) (list_magic_chkbool(x, "list_empty") && (x).next == &(x))
#define list_is_singleton(x) \
- (list_magic_chkbool(x, "list_is_singleton") && (x).next == (x).prev)
+ (list_magic_chkbool(x, "list_is_singleton") && (x).next == (x).prev \
+ && !list_empty(x))
#define list_has_prev(l,p) \
(list_magic_chkbool(l, "list_has_prev") && (p)->prev != (void *) &(l))
--
1.8.3.1

View File

@ -0,0 +1,73 @@
From d83c0edf4c6ae42359ff856d7a879ecba5769595 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Fri, 17 Feb 2017 16:51:41 +0100
Subject: [PATCH 1/2] fix compatibility with OpenSSL 1.1
---
src/network/ssl/socket.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c
index c9e2be4..467fc48 100644
--- a/src/network/ssl/socket.c
+++ b/src/network/ssl/socket.c
@@ -83,7 +83,7 @@ static void
ssl_set_no_tls(struct socket *socket)
{
#ifdef CONFIG_OPENSSL
- ((ssl_t *) socket->ssl)->options |= SSL_OP_NO_TLSv1;
+ SSL_set_options((ssl_t *) socket->ssl, SSL_OP_NO_TLSv1);
#elif defined(CONFIG_GNUTLS)
{
/* GnuTLS does not support SSLv2 because it is "insecure".
@@ -419,7 +419,7 @@ ssl_connect(struct socket *socket)
}
if (client_cert) {
- SSL_CTX *ctx = ((SSL *) socket->ssl)->ctx;
+ SSL_CTX *ctx = SSL_get_SSL_CTX((SSL *) socket->ssl);
SSL_CTX_use_certificate_chain_file(ctx, client_cert);
SSL_CTX_use_PrivateKey_file(ctx, client_cert,
--
2.7.4
From ec952cc5b79973bee73fcfc813159d40c22b7228 Mon Sep 17 00:00:00 2001
From: Tomas Mraz <tmraz@fedoraproject.org>
Date: Fri, 17 Feb 2017 16:44:11 +0100
Subject: [PATCH 2/2] drop disablement of TLS1.0 on second attempt to connect
It would not work correctly anyway and the code does not build
with OpenSSL-1.1.0.
---
src/network/ssl/socket.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c
index 467fc48..b981c1e 100644
--- a/src/network/ssl/socket.c
+++ b/src/network/ssl/socket.c
@@ -82,6 +82,11 @@
static void
ssl_set_no_tls(struct socket *socket)
{
+#if 0
+/* This implements the insecure renegotiation, which should not be used.
+ * The code also would not work on current Fedora (>= Fedora 23) anyway,
+ * because it would just switch off TLS 1.0 keeping TLS 1.1 and 1.2 enabled.
+ */
#ifdef CONFIG_OPENSSL
SSL_set_options((ssl_t *) socket->ssl, SSL_OP_NO_TLSv1);
#elif defined(CONFIG_GNUTLS)
@@ -96,6 +101,7 @@ ssl_set_no_tls(struct socket *socket)
gnutls_protocol_set_priority(*(ssl_t *) socket->ssl, protocol_priority);
}
#endif
+#endif
}
#ifdef USE_OPENSSL
--
2.7.4

View File

@ -0,0 +1,25 @@
From a73e1ecfbfbc42bfc4798a98a4afd90bd35eb7f0 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Fri, 17 Feb 2017 16:21:48 +0100
Subject: [PATCH] configure.in: recognize recent versions of GCC
---
configure.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.in b/configure.in
index 6bcfeec..28c685d 100644
--- a/configure.in
+++ b/configure.in
@@ -1588,7 +1588,7 @@ if test "x$ac_cv_c_compiler_gnu" = "xyes"; then
# alternative is just too ugly. Thanks gcc guys!! ;)
CFLAGS="$CFLAGS -fno-strict-aliasing"
;;
- 4.*)
+ 4.*|5.*|6.*|7)
# Do not show warnings related to (char * | unsigned char *) type
# difference.
CFLAGS="$CFLAGS -fno-strict-aliasing -Wno-pointer-sign"
--
2.11.1

View File

@ -0,0 +1,974 @@
From 30d96f81dbefffd3f1523256cc5a5328ea1c7ecb Mon Sep 17 00:00:00 2001
From: Kalle Olavi Niemitalo <kon@iki.fi>
Date: Mon, 2 May 2011 14:41:40 +0300
Subject: [PATCH 1/4] 1024: Use RFC 3546 server_name TLS extension
For both GnuTLS and OpenSSL. Not tested with nss-compat-openssl.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/network/ssl/socket.c | 19 ++++++++++++++++++-
src/network/ssl/ssl.c | 29 ++++++++++++++++++++++++-----
src/network/ssl/ssl.h | 14 ++++++++++++--
3 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c
index 45b4b4a..dc682d0 100644
--- a/src/network/ssl/socket.c
+++ b/src/network/ssl/socket.c
@@ -22,6 +22,7 @@
#include "network/socket.h"
#include "network/ssl/socket.h"
#include "network/ssl/ssl.h"
+#include "protocol/uri.h"
#include "util/memory.h"
@@ -117,12 +118,28 @@ int
ssl_connect(struct socket *socket)
{
int ret;
+ unsigned char *server_name;
+ struct connection *conn = socket->conn;
- if (init_ssl_connection(socket) == S_SSL_ERROR) {
+ /* TODO: Recode server_name to UTF-8. */
+ server_name = get_uri_string(conn->proxied_uri, URI_HOST);
+ if (!server_name) {
+ socket->ops->done(socket, connection_state(S_OUT_OF_MEM));
+ return -1;
+ }
+
+ /* RFC 3546 says literal IPv4 and IPv6 addresses are not allowed. */
+ if (is_ip_address(server_name, strlen(server_name)))
+ mem_free_set(&server_name, NULL);
+
+ if (init_ssl_connection(socket, server_name) == S_SSL_ERROR) {
+ mem_free_if(server_name);
socket->ops->done(socket, connection_state(S_SSL_ERROR));
return -1;
}
+ mem_free_if(server_name);
+
if (socket->no_tls)
ssl_set_no_tls(socket);
diff --git a/src/network/ssl/ssl.c b/src/network/ssl/ssl.c
index 685c31e..7767a71 100644
--- a/src/network/ssl/ssl.c
+++ b/src/network/ssl/ssl.c
@@ -212,13 +212,26 @@ struct module ssl_module = struct_module(
);
int
-init_ssl_connection(struct socket *socket)
+init_ssl_connection(struct socket *socket,
+ const unsigned char *server_name)
{
#ifdef CONFIG_OPENSSL
socket->ssl = SSL_new(context);
if (!socket->ssl) return S_SSL_ERROR;
+
+ /* If the server name is known, pass it to OpenSSL.
+ *
+ * The return value of SSL_set_tlsext_host_name is not
+ * documented. The source shows that it returns 1 if
+ * successful; on error, it calls SSLerr and returns 0. */
+ if (server_name
+ && !SSL_set_tlsext_host_name(socket->ssl, server_name)) {
+ SSL_free(socket->ssl);
+ socket->ssl = NULL;
+ return S_SSL_ERROR;
+ }
+
#elif defined(CONFIG_GNUTLS)
- /* const unsigned char server_name[] = "localhost"; */
ssl_t *state = mem_alloc(sizeof(ssl_t));
if (!state) return S_SSL_ERROR;
@@ -255,9 +268,15 @@ init_ssl_connection(struct socket *socket)
/* gnutls_handshake_set_private_extensions(*state, 1); */
gnutls_cipher_set_priority(*state, cipher_priority);
gnutls_kx_set_priority(*state, kx_priority);
- /* gnutls_certificate_type_set_priority(*state, cert_type_priority);
- gnutls_server_name_set(*state, GNUTLS_NAME_DNS, server_name,
- sizeof(server_name) - 1); */
+ /* gnutls_certificate_type_set_priority(*state, cert_type_priority); */
+
+ if (server_name
+ && gnutls_server_name_set(*state, GNUTLS_NAME_DNS, server_name,
+ strlen(server_name))) {
+ gnutls_deinit(*state);
+ mem_free(state);
+ return S_SSL_ERROR;
+ }
socket->ssl = state;
#endif
diff --git a/src/network/ssl/ssl.h b/src/network/ssl/ssl.h
index 7c54a7a..bfd94e1 100644
--- a/src/network/ssl/ssl.h
+++ b/src/network/ssl/ssl.h
@@ -11,8 +11,18 @@ struct socket;
extern struct module ssl_module;
/* Initializes the SSL connection data. Returns S_OK on success and S_SSL_ERROR
- * on failure. */
-int init_ssl_connection(struct socket *socket);
+ * on failure.
+ *
+ * server_name is the DNS name of the server (in UTF-8), or NULL if
+ * ELinks knows only the IP address. ELinks reports that name to the
+ * server so that the server can choose the correct certificate if it
+ * has multiple virtual hosts on the same IP address. See RFC 3546
+ * section 3.1.
+ *
+ * server_name does not affect how ELinks verifies the certificate
+ * after the server has returned it. */
+int init_ssl_connection(struct socket *socket,
+ const unsigned char *server_name);
/* Releases the SSL connection data */
void done_ssl_connection(struct socket *socket);
--
2.1.0
From e7484a980572b665747c28aa1376e29a12fb4b19 Mon Sep 17 00:00:00 2001
From: Kalle Olavi Niemitalo <kon@iki.fi>
Date: Tue, 3 May 2011 03:52:21 +0300
Subject: [PATCH 2/4] 1024: Verify server certificate hostname with OpenSSL
Not tested with nss-compat-ossl.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/network/ssl/Makefile | 7 +-
src/network/ssl/match-hostname.c | 125 +++++++++++++++++
src/network/ssl/match-hostname.h | 10 ++
src/network/ssl/socket.c | 211 ++++++++++++++++++++++++++++-
src/network/ssl/ssl.c | 41 +++++-
src/network/ssl/ssl.h | 3 +
src/network/ssl/test/Makefile | 9 ++
src/network/ssl/test/match-hostname-test.c | 123 +++++++++++++++++
src/network/ssl/test/test-match-hostname | 3 +
9 files changed, 529 insertions(+), 3 deletions(-)
create mode 100644 src/network/ssl/match-hostname.c
create mode 100644 src/network/ssl/match-hostname.h
create mode 100644 src/network/ssl/test/Makefile
create mode 100644 src/network/ssl/test/match-hostname-test.c
create mode 100755 src/network/ssl/test/test-match-hostname
diff --git a/src/network/ssl/Makefile b/src/network/ssl/Makefile
index 26f02c2..6f265da 100644
--- a/src/network/ssl/Makefile
+++ b/src/network/ssl/Makefile
@@ -3,6 +3,11 @@ include $(top_builddir)/Makefile.config
INCLUDES += $(GNUTLS_CFLAGS) $(OPENSSL_CFLAGS)
-OBJS = ssl.o socket.o
+SUBDIRS = test
+
+# ELinks uses match-hostname.o only if CONFIG_OPENSSL.
+# However, match-hostname.o has test cases that always need it.
+# The test framework doesn't seem to support conditional tests.
+OBJS = match-hostname.o ssl.o socket.o
include $(top_srcdir)/Makefile.lib
diff --git a/src/network/ssl/match-hostname.c b/src/network/ssl/match-hostname.c
new file mode 100644
index 0000000..9a64bb4
--- /dev/null
+++ b/src/network/ssl/match-hostname.c
@@ -0,0 +1,125 @@
+/* Matching a host name to wildcards in SSL certificates */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "elinks.h"
+
+#include "intl/charsets.h"
+#include "network/ssl/match-hostname.h"
+#include "util/conv.h"
+#include "util/error.h"
+#include "util/string.h"
+
+/** Checks whether a host name matches a pattern that may contain
+ * wildcards.
+ *
+ * @param[in] hostname
+ * The host name to which the user wanted to connect.
+ * Should be in UTF-8 and need not be null-terminated.
+ * @param[in] hostname_length
+ * The length of @a hostname, in bytes.
+ * @param[in] pattern
+ * A pattern that the host name might match.
+ * Should be in UTF-8 and need not be null-terminated.
+ * The pattern may contain wildcards, as specified in
+ * RFC 2818 section 3.1.
+ * @param[in] pattern_length
+ * The length of @a pattern, in bytes.
+ *
+ * @return
+ * Nonzero if the host name matches. Zero if it doesn't.
+ *
+ * According to RFC 2818 section 3.1, '*' matches any number of
+ * characters except '.'. For example, "*r*.example.org" matches
+ * "random.example.org" or "history.example.org" but not
+ * "frozen.fruit.example.org".
+ *
+ * This function does not allocate memory, and consumes at most
+ * O(@a hostname_length * @a pattern_length) time. */
+int
+match_hostname_pattern(const unsigned char *hostname,
+ size_t hostname_length,
+ const unsigned char *pattern,
+ size_t pattern_length)
+{
+ const unsigned char *const hostname_end = hostname + hostname_length;
+ const unsigned char *const pattern_end = pattern + pattern_length;
+
+ assert(hostname <= hostname_end);
+ assert(pattern <= pattern_end);
+ if_assert_failed return 0;
+
+ while (pattern < pattern_end) {
+ if (*pattern == '*') {
+ const unsigned char *next_wildcard;
+ size_t literal_length;
+
+ ++pattern;
+ next_wildcard = memchr(pattern, '*',
+ pattern_end - pattern);
+ if (next_wildcard == NULL)
+ literal_length = pattern_end - pattern;
+ else
+ literal_length = next_wildcard - pattern;
+
+ for (;;) {
+ size_t hostname_left = hostname_end - hostname;
+ unicode_val_T uni;
+
+ if (hostname_left < literal_length)
+ return 0;
+
+ /* If next_wildcard == NULL, then the
+ * literal string is at the end of the
+ * pattern, so anchor the match to the
+ * end of the hostname. The end of
+ * this function can then easily
+ * verify that the whole hostname was
+ * matched.
+ *
+ * But do not jump directly there;
+ * first verify that there are no '.'
+ * characters in between. */
+ if ((next_wildcard != NULL
+ || hostname_left == literal_length)
+ && !c_strlcasecmp(pattern, literal_length,
+ hostname, literal_length))
+ break;
+
+ /* The literal string doesn't match here.
+ * Skip one character of the hostname and
+ * retry. If the skipped character is '.'
+ * or one of the equivalent characters
+ * listed in RFC 3490 section 3.1
+ * requirement 1, then return 0, because
+ * '*' must not match such characters.
+ * Do the same if invalid UTF-8 is found.
+ * Cast away const. */
+ uni = utf8_to_unicode((unsigned char **) hostname,
+ hostname_end);
+ if (uni == 0x002E
+ || uni == 0x3002
+ || uni == 0xFF0E
+ || uni == 0xFF61
+ || uni == UCS_NO_CHAR)
+ return 0;
+ }
+
+ pattern += literal_length;
+ hostname += literal_length;
+ } else {
+ if (hostname == hostname_end)
+ return 0;
+
+ if (c_toupper(*pattern) != c_toupper(*hostname))
+ return 0;
+
+ ++pattern;
+ ++hostname;
+ }
+ }
+
+ return hostname == hostname_end;
+}
diff --git a/src/network/ssl/match-hostname.h b/src/network/ssl/match-hostname.h
new file mode 100644
index 0000000..60d32b2
--- /dev/null
+++ b/src/network/ssl/match-hostname.h
@@ -0,0 +1,10 @@
+
+#ifndef EL__NETWORK_SSL_MATCH_HOSTNAME_H
+#define EL__NETWORK_SSL_MATCH_HOSTNAME_H
+
+int match_hostname_pattern(const unsigned char *hostname,
+ size_t hostname_length,
+ const unsigned char *pattern,
+ size_t pattern_length);
+
+#endif
diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c
index dc682d0..a67bbde 100644
--- a/src/network/ssl/socket.c
+++ b/src/network/ssl/socket.c
@@ -6,13 +6,24 @@
#ifdef CONFIG_OPENSSL
#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#define USE_OPENSSL
+#elif defined(CONFIG_NSS_COMPAT_OSSL)
+#include <nss_compat_ossl/nss_compat_ossl.h>
+#define USE_OPENSSL
#elif defined(CONFIG_GNUTLS)
#include <gnutls/gnutls.h>
#else
#error "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And then you want exactly *what* from me?"
#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
#include <errno.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
#include "elinks.h"
@@ -20,6 +31,7 @@
#include "main/select.h"
#include "network/connection.h"
#include "network/socket.h"
+#include "network/ssl/match-hostname.h"
#include "network/ssl/socket.h"
#include "network/ssl/ssl.h"
#include "protocol/uri.h"
@@ -83,6 +95,203 @@ ssl_set_no_tls(struct socket *socket)
#endif
}
+#ifdef USE_OPENSSL
+
+/** Checks whether the host component of a URI matches a host name in
+ * the server certificate.
+ *
+ * @param[in] uri_host
+ * The host name (or IP address) to which the user wanted to connect.
+ * Should be in UTF-8.
+ * @param[in] cert_host_asn1
+ * A host name found in the server certificate: either as commonName
+ * in the subject field, or as a dNSName in the subjectAltName
+ * extension. This may contain wildcards, as specified in RFC 2818
+ * section 3.1.
+ *
+ * @return
+ * Nonzero if the host matches. Zero if it doesn't, or on error.
+ *
+ * If @a uri_host is an IP address literal rather than a host name,
+ * then this function returns 0, meaning that the host name does not match.
+ * According to RFC 2818, if the certificate is intended to match an
+ * IP address, then it must have that IP address as an iPAddress
+ * SubjectAltName, rather than in commonName. For comparing those,
+ * match_uri_host_ip() must be used instead of this function. */
+static int
+match_uri_host_name(const unsigned char *uri_host,
+ ASN1_STRING *cert_host_asn1)
+{
+ const size_t uri_host_len = strlen(uri_host);
+ unsigned char *cert_host = NULL;
+ int cert_host_len;
+ int matched = 0;
+
+ if (is_ip_address(uri_host, uri_host_len))
+ goto mismatch;
+
+ /* This function is used for both dNSName and commonName.
+ * Although dNSName is always an IA5 string, commonName allows
+ * many other encodings too. Normalize all to UTF-8. */
+ cert_host_len = ASN1_STRING_to_UTF8(&cert_host,
+ cert_host_asn1);
+ if (cert_host_len < 0)
+ goto mismatch;
+
+ matched = match_hostname_pattern(uri_host, uri_host_len,
+ cert_host, cert_host_len);
+
+mismatch:
+ if (cert_host)
+ OPENSSL_free(cert_host);
+ return matched;
+}
+
+/** Checks whether the host component of a URI matches an IP address
+ * in the server certificate.
+ *
+ * @param[in] uri_host
+ * The IP address (or host name) to which the user wanted to connect.
+ * Should be in UTF-8.
+ * @param[in] cert_host_asn1
+ * An IP address found as iPAddress in the subjectAltName extension
+ * of the server certificate. According to RFC 5280 section 4.2.1.6,
+ * that is an octet string in network byte order. According to
+ * RFC 2818 section 3.1, wildcards are not allowed.
+ *
+ * @return
+ * Nonzero if the host matches. Zero if it doesn't, or on error.
+ *
+ * If @a uri_host is a host name rather than an IP address literal,
+ * then this function returns 0, meaning that the address does not match.
+ * This function does not try to resolve the host name to an IP address
+ * and compare that to @a cert_host_asn1, because such an approach would
+ * be vulnerable to DNS spoofing.
+ *
+ * This function does not support the address-and-netmask format used
+ * in the name constraints extension of a CA certificate (RFC 5280
+ * section 4.2.1.10). */
+static int
+match_uri_host_ip(const unsigned char *uri_host,
+ ASN1_OCTET_STRING *cert_host_asn1)
+{
+ const unsigned char *cert_host_addr = ASN1_STRING_data(cert_host_asn1);
+ struct in_addr uri_host_in;
+#ifdef CONFIG_IPV6
+ struct in6_addr uri_host_in6;
+#endif
+
+ /* RFC 5280 defines the iPAddress alternative of GeneralName
+ * as an OCTET STRING. Verify that the type is indeed that.
+ * This is an assertion because, if someone puts the wrong
+ * type of data there, then it will not even be recognized as
+ * an iPAddress, and this function will not be called.
+ *
+ * (Because GeneralName is defined in an implicitly tagged
+ * ASN.1 module, the OCTET STRING tag is not part of the DER
+ * encoding. BER also allows a constructed encoding where
+ * each substring begins with the OCTET STRING tag; but ITU-T
+ * Rec. X.690 (07/2002) subclause 8.21 says those would be
+ * OCTET STRING even if the outer string were of some other
+ * type. "A Layman's Guide to a Subset of ASN.1, BER, and
+ * DER" (Kaliski, 1993) claims otherwise, though.) */
+ assert(ASN1_STRING_type(cert_host_asn1) == V_ASN1_OCTET_STRING);
+ if_assert_failed return 0;
+
+ /* cert_host_addr, url_host_in, and url_host_in6 are all in
+ * network byte order. */
+ switch (ASN1_STRING_length(cert_host_asn1)) {
+ case 4:
+ return inet_aton(uri_host, &uri_host_in) != 0
+ && memcmp(cert_host_addr, &uri_host_in.s_addr, 4) == 0;
+
+#ifdef CONFIG_IPV6
+ case 16:
+ return inet_pton(AF_INET6, uri_host, &uri_host_in6) == 1
+ && memcmp(cert_host_addr, &uri_host_in6.s6_addr, 16) == 0;
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+/** Verify one certificate in the server certificate chain.
+ * This callback is documented in SSL_set_verify(3). */
+static int
+verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
+{
+ X509 *cert;
+ SSL *ssl;
+ struct socket *socket;
+ struct connection *conn;
+ unsigned char *host_in_uri;
+ GENERAL_NAMES *alts;
+ int saw_dns_name = 0;
+ int matched = 0;
+
+ /* If OpenSSL already found a problem, keep that. */
+ if (!preverify_ok)
+ return 0;
+
+ /* Examine only the server certificate, not CA certificates. */
+ if (X509_STORE_CTX_get_error_depth(ctx) != 0)
+ return preverify_ok;
+
+ cert = X509_STORE_CTX_get_current_cert(ctx);
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ socket = SSL_get_ex_data(ssl, socket_SSL_ex_data_idx);
+ conn = socket->conn;
+ host_in_uri = get_uri_string(conn->uri, URI_HOST | URI_IDN);
+ if (!host_in_uri)
+ return 0;
+
+ /* RFC 5280 section 4.2.1.6 describes the subjectAltName extension.
+ * RFC 2818 section 3.1 says Common Name must not be used
+ * if dNSName is present. */
+ alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (alts != NULL) {
+ int alt_count;
+ int alt_pos;
+ GENERAL_NAME *alt;
+
+ alt_count = sk_GENERAL_NAME_num(alts);
+ for (alt_pos = 0; !matched && alt_pos < alt_count; ++alt_pos) {
+ alt = sk_GENERAL_NAME_value(alts, alt_pos);
+ if (alt->type == GEN_DNS) {
+ saw_dns_name = 1;
+ matched = match_uri_host_name(host_in_uri,
+ alt->d.dNSName);
+ } else if (alt->type == GEN_IPADD) {
+ matched = match_uri_host_ip(host_in_uri,
+ alt->d.iPAddress);
+ }
+ }
+
+ /* Free the GENERAL_NAMES list and each element. */
+ sk_GENERAL_NAME_pop_free(alts, GENERAL_NAME_free);
+ }
+
+ if (!matched && !saw_dns_name) {
+ X509_NAME *name;
+ int cn_index;
+ X509_NAME_ENTRY *entry = NULL;
+
+ name = X509_get_subject_name(cert);
+ cn_index = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
+ if (cn_index >= 0)
+ entry = X509_NAME_get_entry(name, cn_index);
+ if (entry != NULL)
+ matched = match_uri_host_name(host_in_uri,
+ X509_NAME_ENTRY_get_data(entry));
+ }
+
+ mem_free(host_in_uri);
+ return matched;
+}
+
+#endif /* USE_OPENSSL */
+
static void
ssl_want_read(struct socket *socket)
{
@@ -149,7 +358,7 @@ ssl_connect(struct socket *socket)
if (get_opt_bool("connection.ssl.cert_verify"))
SSL_set_verify(socket->ssl, SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- NULL);
+ verify_callback);
if (get_opt_bool("connection.ssl.client_cert.enable")) {
unsigned char *client_cert;
diff --git a/src/network/ssl/ssl.c b/src/network/ssl/ssl.c
index 7767a71..d1881c8 100644
--- a/src/network/ssl/ssl.c
+++ b/src/network/ssl/ssl.c
@@ -39,7 +39,35 @@
#define PATH_MAX 256 /* according to my /usr/include/bits/posix1_lim.h */
#endif
-SSL_CTX *context = NULL;
+static SSL_CTX *context = NULL;
+int socket_SSL_ex_data_idx = -1;
+
+/** Prevent SSL_dup() if the SSL is associated with struct socket.
+ * We cannot copy struct socket and it doesn't have a reference count
+ * either. */
+static int
+socket_SSL_ex_data_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
+ void *from_d, int idx, long argl, void *argp)
+{
+ /* The documentation of from_d in RSA_get_ex_new_index(3)
+ * is a bit unclear. The caller does something like:
+ *
+ * void *data = CRYPTO_get_ex_data(from, idx);
+ * socket_SSL_dup(to, from, &data, idx, argl, argp);
+ * CRYPTO_set_ex_data(to, idx, data);
+ *
+ * i.e., from_d always points to a pointer, even though
+ * it is just a void * in the prototype. */
+ struct socket *socket = *(void **) from_d;
+
+ assert(idx == socket_SSL_ex_data_idx);
+ if_assert_failed return 0;
+
+ if (socket)
+ return 0; /* prevent SSL_dup() */
+ else
+ return 1; /* allow SSL_dup() */
+}
static void
init_openssl(struct module *module)
@@ -48,12 +76,17 @@ init_openssl(struct module *module)
context = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_options(context, SSL_OP_ALL);
SSL_CTX_set_default_verify_paths(context);
+ socket_SSL_ex_data_idx = SSL_get_ex_new_index(0, NULL,
+ NULL,
+ socket_SSL_ex_data_dup,
+ NULL);
}
static void
done_openssl(struct module *module)
{
if (context) SSL_CTX_free(context);
+ /* There is no function that undoes SSL_get_ex_new_index. */
}
static union option_info openssl_options[] = {
@@ -219,6 +252,12 @@ init_ssl_connection(struct socket *socket,
socket->ssl = SSL_new(context);
if (!socket->ssl) return S_SSL_ERROR;
+ if (!SSL_set_ex_data(socket->ssl, socket_SSL_ex_data_idx, socket)) {
+ SSL_free(socket->ssl);
+ socket->ssl = NULL;
+ return S_SSL_ERROR;
+ }
+
/* If the server name is known, pass it to OpenSSL.
*
* The return value of SSL_set_tlsext_host_name is not
diff --git a/src/network/ssl/ssl.h b/src/network/ssl/ssl.h
index bfd94e1..480b4db 100644
--- a/src/network/ssl/ssl.h
+++ b/src/network/ssl/ssl.h
@@ -29,6 +29,9 @@ void done_ssl_connection(struct socket *socket);
unsigned char *get_ssl_connection_cipher(struct socket *socket);
+#if defined(CONFIG_OPENSSL) || defined(CONFIG_NSS_COMPAT_OSSL)
+extern int socket_SSL_ex_data_idx;
+#endif
/* Internal type used in ssl module. */
diff --git a/src/network/ssl/test/Makefile b/src/network/ssl/test/Makefile
new file mode 100644
index 0000000..f2196eb
--- /dev/null
+++ b/src/network/ssl/test/Makefile
@@ -0,0 +1,9 @@
+top_builddir=../../../..
+include $(top_builddir)/Makefile.config
+
+SUBDIRS =
+TEST_PROGS = match-hostname-test
+TESTDEPS += \
+ $(top_builddir)/src/network/ssl/match-hostname.o
+
+include $(top_srcdir)/Makefile.lib
diff --git a/src/network/ssl/test/match-hostname-test.c b/src/network/ssl/test/match-hostname-test.c
new file mode 100644
index 0000000..fbdf6fa
--- /dev/null
+++ b/src/network/ssl/test/match-hostname-test.c
@@ -0,0 +1,123 @@
+/* Test match_hostname_pattern() */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "elinks.h"
+
+#include "network/ssl/match-hostname.h"
+#include "util/string.h"
+
+struct match_hostname_pattern_test_case
+{
+ const unsigned char *pattern;
+ const unsigned char *hostname;
+ int match;
+};
+
+static const struct match_hostname_pattern_test_case match_hostname_pattern_test_cases[] = {
+ { "*r*.example.org", "random.example.org", 1 },
+ { "*r*.example.org", "history.example.org", 1 },
+ { "*r*.example.org", "frozen.fruit.example.org", 0 },
+ { "*r*.example.org", "steamed.fruit.example.org", 0 },
+
+ { "ABC.def.Ghi", "abc.DEF.gHI", 1 },
+
+ { "*", "localhost", 1 },
+ { "*", "example.org", 0 },
+ { "*.*", "example.org", 1 },
+ { "*.*.*", "www.example.org", 1 },
+ { "*.*.*", "example.org", 0 },
+
+ { "assign", "assignee", 0 },
+ { "*peg", "arpeggiator", 0 },
+ { "*peg*", "arpeggiator", 1 },
+ { "*r*gi*", "arpeggiator", 1 },
+ { "*r*git*", "arpeggiator", 0 },
+
+ { NULL, NULL, 0 }
+};
+
+int
+main(void)
+{
+ const struct match_hostname_pattern_test_case *test;
+ int count_ok = 0;
+ int count_fail = 0;
+ struct string hostname_str = NULL_STRING;
+ struct string pattern_str = NULL_STRING;
+
+ if (!init_string(&hostname_str) || !init_string(&pattern_str)) {
+ fputs("Out of memory.\n", stderr);
+ done_string(&hostname_str);
+ done_string(&pattern_str);
+ return EXIT_FAILURE;
+ }
+
+ for (test = match_hostname_pattern_test_cases; test->pattern; test++) {
+ int match;
+
+ match = match_hostname_pattern(
+ test->hostname,
+ strlen(test->hostname),
+ test->pattern,
+ strlen(test->pattern));
+ if (!match == !test->match) {
+ /* Test OK */
+ count_ok++;
+ } else {
+ fprintf(stderr, "match_hostname_pattern() test failed\n"
+ "\tHostname: %s\n"
+ "\tPattern: %s\n"
+ "\tActual result: %d\n"
+ "\tCorrect result: %d\n",
+ test->hostname,
+ test->pattern,
+ match,
+ test->match);
+ count_fail++;
+ }
+
+ /* Try with strings that are not null-terminated. */
+ hostname_str.length = 0;
+ add_to_string(&hostname_str, test->hostname);
+ add_to_string(&hostname_str, "ZZZ");
+ pattern_str.length = 0;
+ add_to_string(&pattern_str, test->pattern);
+ add_to_string(&hostname_str, "______");
+
+ match = match_hostname_pattern(
+ hostname_str.source,
+ strlen(test->hostname),
+ pattern_str.source,
+ strlen(test->pattern));
+ if (!match == !test->match) {
+ /* Test OK */
+ count_ok++;
+ } else {
+ fprintf(stderr, "match_hostname_pattern() test failed\n"
+ "\tVariant: Strings were not null-terminated.\n"
+ "\tHostname: %s\n"
+ "\tPattern: %s\n"
+ "\tActual result: %d\n"
+ "\tCorrect result: %d\n",
+ test->hostname,
+ test->pattern,
+ match,
+ test->match);
+ count_fail++;
+ }
+ }
+
+ printf("Summary of match_hostname_pattern() tests: %d OK, %d failed.\n",
+ count_ok, count_fail);
+
+ done_string(&hostname_str);
+ done_string(&pattern_str);
+ return count_fail ? EXIT_FAILURE : EXIT_SUCCESS;
+
+}
diff --git a/src/network/ssl/test/test-match-hostname b/src/network/ssl/test/test-match-hostname
new file mode 100755
index 0000000..01d7173
--- /dev/null
+++ b/src/network/ssl/test/test-match-hostname
@@ -0,0 +1,3 @@
+#! /bin/sh -e
+
+./match-hostname-test
--
2.1.0
From 0cb6967bb9ccabc583bbdc6ee76baf4fdf0f90cc Mon Sep 17 00:00:00 2001
From: mancha <mancha@mac.hush.com>
Date: Sun, 15 Jul 2012 23:27:53 +0200
Subject: [PATCH 3/4] Fix hostname verification code.
[ From bug 1123 attachment 569. --KON ]
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/network/ssl/match-hostname.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/network/ssl/match-hostname.c b/src/network/ssl/match-hostname.c
index 9a64bb4..80d93b0 100644
--- a/src/network/ssl/match-hostname.c
+++ b/src/network/ssl/match-hostname.c
@@ -97,7 +97,7 @@ match_hostname_pattern(const unsigned char *hostname,
* '*' must not match such characters.
* Do the same if invalid UTF-8 is found.
* Cast away const. */
- uni = utf8_to_unicode((unsigned char **) hostname,
+ uni = utf8_to_unicode((unsigned char **) &hostname,
hostname_end);
if (uni == 0x002E
|| uni == 0x3002
--
2.1.0
From cf8586b0389911d944d767646d5a91c2e1bae86c Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Fri, 5 Jun 2015 17:08:46 +0200
Subject: [PATCH 4/4] ssl: use the OpenSSL-provided host name check
... if built against a new enough version of OpenSSL
Suggested-by: Christian Heimes
---
configure.in | 3 +++
src/network/ssl/socket.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/configure.in b/configure.in
index 91d0257..1d858bd 100644
--- a/configure.in
+++ b/configure.in
@@ -1044,6 +1044,9 @@ else
fi
AC_MSG_RESULT($cf_result)
+if test "$cf_result" = yes; then
+ AC_CHECK_FUNCS(X509_VERIFY_PARAM_set1_host)
+fi
# ---- GNU TLS
diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c
index a67bbde..c9e2be4 100644
--- a/src/network/ssl/socket.c
+++ b/src/network/ssl/socket.c
@@ -7,6 +7,9 @@
#ifdef CONFIG_OPENSSL
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
+#ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
+#include <openssl/x509_vfy.h>
+#endif
#define USE_OPENSSL
#elif defined(CONFIG_NSS_COMPAT_OSSL)
#include <nss_compat_ossl/nss_compat_ossl.h>
@@ -97,6 +100,30 @@ ssl_set_no_tls(struct socket *socket)
#ifdef USE_OPENSSL
+#ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
+/* activate the OpenSSL-provided host name check */
+static int
+ossl_set_hostname(void *ssl, unsigned char *server_name)
+{
+ int ret = -1;
+
+ X509_VERIFY_PARAM *vpm = X509_VERIFY_PARAM_new();
+ if (vpm) {
+ if (X509_VERIFY_PARAM_set1_host(vpm, (char *) server_name, 0)
+ && SSL_set1_param(ssl, vpm))
+ {
+ /* successfully activated the OpenSSL host name check */
+ ret = 0;
+ }
+
+ X509_VERIFY_PARAM_free(vpm);
+ }
+
+ return ret;
+}
+
+#else /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
+
/** Checks whether the host component of a URI matches a host name in
* the server certificate.
*
@@ -289,6 +316,7 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
mem_free(host_in_uri);
return matched;
}
+#endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
#endif /* USE_OPENSSL */
@@ -329,6 +357,9 @@ ssl_connect(struct socket *socket)
int ret;
unsigned char *server_name;
struct connection *conn = socket->conn;
+#ifdef USE_OPENSSL
+ int (*verify_callback_ptr)(int, X509_STORE_CTX *);
+#endif /* USE_OPENSSL */
/* TODO: Recode server_name to UTF-8. */
server_name = get_uri_string(conn->proxied_uri, URI_HOST);
@@ -347,6 +378,23 @@ ssl_connect(struct socket *socket)
return -1;
}
+#ifdef USE_OPENSSL
+#ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
+ /* activate the OpenSSL-provided host name check */
+ if (ossl_set_hostname(socket->ssl, server_name)) {
+ mem_free_if(server_name);
+ socket->ops->done(socket, connection_state(S_SSL_ERROR));
+ return -1;
+ }
+
+ /* verify_callback() is not needed with X509_VERIFY_PARAM_set1_host() */
+ verify_callback_ptr = NULL;
+#else
+ /* use our own callback implementing the host name check */
+ verify_callback_ptr = verify_callback;
+#endif
+#endif /* USE_OPENSSL */
+
mem_free_if(server_name);
if (socket->no_tls)
@@ -358,7 +406,7 @@ ssl_connect(struct socket *socket)
if (get_opt_bool("connection.ssl.cert_verify"))
SSL_set_verify(socket->ssl, SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- verify_callback);
+ verify_callback_ptr);
if (get_opt_bool("connection.ssl.client_cert.enable")) {
unsigned char *client_cert;
--
2.4.3

View File

@ -0,0 +1,197 @@
From 0bfe44b6e0041210859c91e1589d5dc45c3991de Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Tue, 6 Nov 2018 18:35:19 +0100
Subject: [PATCH] elinks: fix programming mistakes detected by static analysis
---
src/bfu/menu.c | 1 +
src/bfu/msgbox.c | 1 +
src/config/conf.c | 5 ++++-
src/dialogs/options.c | 3 ++-
src/intl/gettext/loadmsgcat.c | 14 ++++++++++++--
src/protocol/ftp/ftp.c | 8 +++++++-
src/scripting/lua/core.c | 8 ++++++--
src/terminal/event.c | 2 +-
src/util/string.c | 2 +-
9 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/src/bfu/menu.c b/src/bfu/menu.c
index 74b60d7..07285b7 100644
--- a/src/bfu/menu.c
+++ b/src/bfu/menu.c
@@ -125,6 +125,7 @@ do_menu_selected(struct terminal *term, struct menu_item *items,
refresh_hotkeys(term, menu);
add_window(term, menu_handler, menu);
} else {
+ /* FIXME: This will cause BAD_FREE when called from do_setup_menu() */
free_menu_items(items);
}
}
diff --git a/src/bfu/msgbox.c b/src/bfu/msgbox.c
index d7af62b..f272459 100644
--- a/src/bfu/msgbox.c
+++ b/src/bfu/msgbox.c
@@ -103,6 +103,7 @@ msg_text_do(unsigned char *format, va_list ap)
VA_COPY(ap2, ap);
infolen = vsnprintf(NULL, 0, format, ap2);
+ va_end(ap2);
info = mem_alloc(infolen + 1);
if (!info) return NULL;
diff --git a/src/config/conf.c b/src/config/conf.c
index 12bba7c..e879ea5 100644
--- a/src/config/conf.c
+++ b/src/config/conf.c
@@ -702,7 +702,10 @@ read_config_file(unsigned char *name)
if (fd < 0) return NULL;
set_bin(fd);
- if (!init_string(&string)) return NULL;
+ if (!init_string(&string)) {
+ close(fd);
+ return NULL;
+ }
while ((r = safe_read(fd, cfg_buffer, FILE_BUF)) > 0) {
int i;
diff --git a/src/dialogs/options.c b/src/dialogs/options.c
index f40d07d..a3a0a8b 100644
--- a/src/dialogs/options.c
+++ b/src/dialogs/options.c
@@ -125,8 +125,9 @@ push_ok_button(struct dialog_data *dlg_data, struct widget_data *button)
static widget_handler_status_T
push_save_button(struct dialog_data *dlg_data, struct widget_data *button)
{
+ struct terminal *term = dlg_data->win->term;
push_ok_button(dlg_data, button);
- write_config(dlg_data->win->term);
+ write_config(term);
return EVENT_PROCESSED;
}
diff --git a/src/intl/gettext/loadmsgcat.c b/src/intl/gettext/loadmsgcat.c
index 0eac283..1be7b2b 100644
--- a/src/intl/gettext/loadmsgcat.c
+++ b/src/intl/gettext/loadmsgcat.c
@@ -312,8 +312,10 @@ source_success:
unsigned char *read_ptr;
data = (struct mo_file_header *) malloc(size);
- if (data == NULL)
+ if (data == NULL) {
+ close(fd);
return;
+ }
to_read = size;
read_ptr = (unsigned char *) data;
@@ -321,6 +323,7 @@ source_success:
ssize_t nb = safe_read(fd, read_ptr, to_read);
if (nb <= 0) {
+ free(data);
close(fd);
return;
}
@@ -345,8 +348,15 @@ source_success:
}
domain = (struct loaded_domain *) malloc(sizeof(struct loaded_domain));
- if (domain == NULL)
+ if (domain == NULL) {
+#ifdef LOADMSGCAT_USE_MMAP
+ if (use_mmap)
+ munmap((void *) data, size);
+ else
+#endif
+ free(data);
return;
+ }
domain_file->data = domain;
domain->data = (unsigned char *) data;
diff --git a/src/protocol/ftp/ftp.c b/src/protocol/ftp/ftp.c
index 10c9e28..fe3b7f0 100644
--- a/src/protocol/ftp/ftp.c
+++ b/src/protocol/ftp/ftp.c
@@ -926,11 +926,17 @@ ftp_data_connect(struct connection *conn, int pf, struct sockaddr_storage *sa,
}
fd = socket(pf, SOCK_STREAM, 0);
- if (fd < 0 || set_nonblocking_fd(fd) < 0) {
+ if (fd < 0) {
abort_connection(conn, connection_state(S_FTP_ERROR));
return -1;
}
+ if (set_nonblocking_fd(fd) < 0) {
+ abort_connection(conn, connection_state(S_FTP_ERROR));
+ close(fd);
+ return -1;
+ }
+
set_ip_tos_throughput(fd);
conn->data_socket->fd = fd;
diff --git a/src/scripting/lua/core.c b/src/scripting/lua/core.c
index 1c4dbbc..f86bf0d 100644
--- a/src/scripting/lua/core.c
+++ b/src/scripting/lua/core.c
@@ -207,12 +207,16 @@ l_pipe_read(LS)
if (l > 0) {
unsigned char *news = mem_realloc(s, len + l);
- if (!news) goto lua_error;
+ if (!news) {
+ pclose(fp);
+ goto lua_error;
+ }
s = news;
memcpy(s + len, buf, l);
len += l;
- } else if (l < 0) {
+ } else {
+ pclose(fp);
goto lua_error;
}
}
diff --git a/src/terminal/event.c b/src/terminal/event.c
index 9ad90df..d0de6f0 100644
--- a/src/terminal/event.c
+++ b/src/terminal/event.c
@@ -251,13 +251,13 @@ handle_interlink_event(struct terminal *term, struct interlink_event *ilev)
/* Either the initialization of the first session failed or we
* are doing a remote session so quit.*/
if (!decode_session_info(term, info)) {
- destroy_terminal(term);
/* Make sure the user is notified if the initialization
* of the first session fails. */
if (program.terminate) {
usrerror(_("Failed to create session.", term));
program.retval = RET_FATAL;
}
+ destroy_terminal(term);
return 0;
}
diff --git a/src/util/string.c b/src/util/string.c
index 604a00d..833fb9b 100644
--- a/src/util/string.c
+++ b/src/util/string.c
@@ -417,10 +417,10 @@ add_file_to_string(struct string *string, const unsigned char *filename)
string->length += fread(string->source + string->length, 1,
(size_t) filelen, file);
string->source[string->length] = 0;
- fclose(file);
if (string->length != newlength) goto err;
+ fclose(file);
return string;
err:
--
2.17.2

View File

@ -0,0 +1,861 @@
From f513964579f72fc77eea6e0961e49cc8299bf204 Mon Sep 17 00:00:00 2001
From: Witold Filipczyk <witekfl@poczta.onet.pl>
Date: Sun, 31 Aug 2008 14:23:28 +0200
Subject: [PATCH] Use real_box in dialog.c.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/bfu/button.c | 32 +++++++++++++-------------
src/bfu/button.h | 3 +-
src/bfu/checkbox.c | 13 +++++-----
src/bfu/checkbox.h | 3 +-
src/bfu/dialog.c | 59 ++++++++++++++++++++++++++++++++++-------------
src/bfu/dialog.h | 2 +
src/bfu/group.c | 18 +++++++-------
src/bfu/group.h | 2 +-
src/bfu/inpfield.c | 10 ++++----
src/bfu/inpfield.h | 2 +-
src/bfu/listbox.c | 3 +-
src/bfu/listbox.h | 2 +-
src/bfu/text.c | 16 +++++++-----
src/bfu/text.h | 5 ++-
src/dialogs/download.c | 12 +++++-----
src/terminal/draw.c | 36 +++++++++++++++++++++++++++++
src/terminal/draw.h | 10 ++++++++
src/terminal/window.c | 15 ++++++++++++
src/terminal/window.h | 2 +
19 files changed, 170 insertions(+), 75 deletions(-)
diff --git a/src/bfu/button.c b/src/bfu/button.c
index 8267c94..8e6ac62 100644
--- a/src/bfu/button.c
+++ b/src/bfu/button.c
@@ -115,7 +115,7 @@ buttons_width(struct widget_data *widget_data, int n,
}
void
-dlg_format_buttons(struct terminal *term,
+dlg_format_buttons(struct terminal *term, struct dialog_data *dlg_data,
struct widget_data *widget_data, int n,
int x, int *y, int w, int *rw, enum format_align align, int format_only)
{
@@ -212,7 +212,7 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
}
- draw_text(term, pos->x, pos->y, BUTTON_LEFT, BUTTON_LEFT_LEN, 0, color);
+ draw_text2(term, dlg_data, pos->x, pos->y, BUTTON_LEFT, BUTTON_LEFT_LEN, 0, color);
if (len > 0) {
unsigned char *text = widget_data->widget->text;
int hk_pos = widget_data->widget->info.button.hotkey_pos;
@@ -236,15 +236,15 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
NULL);
if (hk_pos)
- draw_text(term, x, pos->y,
+ draw_text2(term, dlg_data, x, pos->y,
text, hk_pos, 0, color);
- draw_text(term, x + cells_to_hk, pos->y,
+ draw_text2(term, dlg_data, x + cells_to_hk, pos->y,
&text[hk_pos + 1], hk_bytes,
attr, shortcut_color);
if (right > 1)
- draw_text(term, x+cells_to_hk+hk_cells,
+ draw_text2(term, dlg_data, x+cells_to_hk+hk_cells,
pos->y,
&text[hk_pos + hk_bytes + 1],
right - 1, 0, color);
@@ -257,11 +257,11 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
len - hk_width,
NULL);
- draw_text(term, x, pos->y,
+ draw_text2(term, dlg_data, x, pos->y,
text, hk_len,
attr, shortcut_color);
- draw_text(term, x + hk_width, pos->y,
+ draw_text2(term, dlg_data, x + hk_width, pos->y,
&text[hk_len], len_to_display,
0, color);
}
@@ -271,18 +271,18 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
if (hk_pos) {
- draw_text(term, x, pos->y, text, hk_pos, 0, color);
+ draw_text2(term, dlg_data, x, pos->y, text, hk_pos, 0, color);
}
- draw_text(term, x + hk_pos, pos->y,
+ draw_text2(term, dlg_data, x + hk_pos, pos->y,
&text[hk_pos + 1], 1, attr, shortcut_color);
if (right > 1) {
- draw_text(term, x + hk_pos + 1, pos->y,
+ draw_text2(term, dlg_data, x + hk_pos + 1, pos->y,
&text[hk_pos + 2], right - 1, 0, color);
}
} else {
- draw_text(term, x, pos->y, text, 1, attr, shortcut_color);
- draw_text(term, x + 1, pos->y, &text[1], len - 1, 0, color);
+ draw_text2(term, dlg_data, x, pos->y, text, 1, attr, shortcut_color);
+ draw_text2(term, dlg_data, x + 1, pos->y, &text[1], len - 1, 0, color);
}
}
#ifdef CONFIG_UTF8
@@ -290,15 +290,15 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
int text_cells = utf8_ptr2cells(widget_data->widget->text, NULL);
int hk = (widget_data->widget->info.button.hotkey_pos >= 0);
- draw_text(term, x + text_cells - hk, pos->y,
+ draw_text2(term, dlg_data, x + text_cells - hk, pos->y,
BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color);
} else
#endif /* CONFIG_UTF8 */
- draw_text(term, x + len, pos->y, BUTTON_RIGHT,
+ draw_text2(term, dlg_data, x + len, pos->y, BUTTON_RIGHT,
BUTTON_RIGHT_LEN, 0, color);
if (sel) {
- set_cursor(term, x, pos->y, 1);
- set_window_ptr(dlg_data->win, pos->x, pos->y);
+ set_cursor2(term, dlg_data, x, pos->y, 1);
+ set_window_ptr2(dlg_data, dlg_data->win, pos->x, pos->y);
}
return EVENT_PROCESSED;
}
diff --git a/src/bfu/button.h b/src/bfu/button.h
index e6e907d..de986c8 100644
--- a/src/bfu/button.h
+++ b/src/bfu/button.h
@@ -5,6 +5,7 @@
#include "util/align.h"
struct dialog;
+struct dialog_data;
struct terminal;
struct widget_data;
@@ -89,6 +90,6 @@ void add_dlg_button_do(struct dialog *dlg, unsigned char *text, int flags, widge
#endif
extern const struct widget_ops button_ops;
-void dlg_format_buttons(struct terminal *, struct widget_data *, int, int, int *, int, int *, enum format_align, int);
+void dlg_format_buttons(struct terminal *, struct dialog_data *, struct widget_data *, int, int, int *, int, int *, enum format_align, int);
#endif
diff --git a/src/bfu/checkbox.c b/src/bfu/checkbox.c
index 7ed97e0..d7c974b 100644
--- a/src/bfu/checkbox.c
+++ b/src/bfu/checkbox.c
@@ -36,7 +36,7 @@ add_dlg_radio_do(struct dialog *dlg, unsigned char *text,
}
void
-dlg_format_checkbox(struct terminal *term,
+dlg_format_checkbox(struct terminal *term, struct dialog_data *dlg_data,
struct widget_data *widget_data,
int x, int *y, int w, int *rw,
enum format_align align, int format_only)
@@ -49,7 +49,7 @@ dlg_format_checkbox(struct terminal *term,
if (text && *text) {
if (rw) *rw -= CHECKBOX_LS;
- dlg_format_text_do(term, text, x + CHECKBOX_LS, y,
+ dlg_format_text_do(term, dlg_data, text, x + CHECKBOX_LS, y,
w - CHECKBOX_LS, rw,
get_bfu_color(term, "dialog.checkbox-label"),
align, format_only);
@@ -78,11 +78,11 @@ display_checkbox(struct dialog_data *dlg_data, struct widget_data *widget_data)
else
text = widget_data->widget->info.checkbox.gid ? "( )" : "[ ]";
- draw_text(term, pos->x, pos->y, text, CHECKBOX_LEN, 0, color);
+ draw_text2(term, dlg_data, pos->x, pos->y, text, CHECKBOX_LEN, 0, color);
if (selected) {
- set_cursor(term, pos->x + 1, pos->y, 1);
- set_window_ptr(dlg_data->win, pos->x, pos->y);
+ set_cursor2(term, dlg_data, pos->x + 1, pos->y, 1);
+ set_window_ptr2(dlg_data, dlg_data->win, pos->x, pos->y);
}
return EVENT_PROCESSED;
@@ -128,7 +128,6 @@ mouse_checkbox(struct dialog_data *dlg_data, struct widget_data *widget_data)
static widget_handler_status_T
select_checkbox(struct dialog_data *dlg_data, struct widget_data *widget_data)
{
-
if (!widget_data->widget->info.checkbox.gid) {
/* Checkbox. */
int *cdata = (int *) widget_data->cdata;
@@ -159,8 +158,8 @@ select_checkbox(struct dialog_data *dlg_data, struct widget_data *widget_data)
}
widget_data->info.checkbox.checked = 1;
}
-
display_widget(dlg_data, widget_data);
+
return EVENT_PROCESSED;
}
diff --git a/src/bfu/checkbox.h b/src/bfu/checkbox.h
index 573f1d2..b4e65ce 100644
--- a/src/bfu/checkbox.h
+++ b/src/bfu/checkbox.h
@@ -2,6 +2,7 @@
#define EL__BFU_CHECKBOX_H
struct dialog;
+struct dialog_data;
struct terminal;
struct widget_data;
@@ -30,7 +31,7 @@ void add_dlg_radio_do(struct dialog *dlg, unsigned char *text, int groupid, int
extern const struct widget_ops checkbox_ops;
void
-dlg_format_checkbox(struct terminal *term,
+dlg_format_checkbox(struct terminal *term, struct dialog_data *dlg_data,
struct widget_data *widget_data,
int x, int *y, int w, int *rw,
enum format_align align, int format_only);
diff --git a/src/bfu/dialog.c b/src/bfu/dialog.c
index b2df9f8..414283f 100644
--- a/src/bfu/dialog.c
+++ b/src/bfu/dialog.c
@@ -82,20 +82,18 @@ redraw_dialog(struct dialog_data *dlg_data, int layout)
}
if (!dlg_data->dlg->layout.only_widgets) {
- struct box box;
-
- set_box(&box,
+ set_box(&dlg_data->real_box,
dlg_data->box.x + (DIALOG_LEFT_BORDER + 1),
dlg_data->box.y + (DIALOG_TOP_BORDER + 1),
dlg_data->box.width - 2 * (DIALOG_LEFT_BORDER + 1),
dlg_data->box.height - 2 * (DIALOG_TOP_BORDER + 1));
- draw_border(term, &box, get_bfu_color(term, "dialog.frame"), DIALOG_FRAME);
+ draw_border(term, &dlg_data->real_box, get_bfu_color(term, "dialog.frame"), DIALOG_FRAME);
assert(dlg_data->dlg->title);
title_color = get_bfu_color(term, "dialog.title");
- if (title_color && box.width > 2) {
+ if (title_color && dlg_data->real_box.width > 2) {
unsigned char *title = dlg_data->dlg->title;
int titlelen = strlen(title);
int titlecells = titlelen;
@@ -107,7 +105,7 @@ redraw_dialog(struct dialog_data *dlg_data, int layout)
&title[titlelen]);
#endif /* CONFIG_UTF8 */
- titlecells = int_min(box.width - 2, titlecells);
+ titlecells = int_min(dlg_data->real_box.width - 2, titlecells);
#ifdef CONFIG_UTF8
if (term->utf8_cp)
@@ -115,13 +113,13 @@ redraw_dialog(struct dialog_data *dlg_data, int layout)
NULL);
#endif /* CONFIG_UTF8 */
- x = (box.width - titlecells) / 2 + box.x;
- y = box.y - 1;
+ x = (dlg_data->real_box.width - titlecells) / 2 + dlg_data->real_box.x;
+ y = dlg_data->real_box.y - 1;
- draw_text(term, x - 1, y, " ", 1, 0, title_color);
- draw_text(term, x, y, title, titlelen, 0, title_color);
- draw_text(term, x + titlecells, y, " ", 1, 0,
+ draw_text2(term, dlg_data, x - 1, y, " ", 1, 0, title_color);
+ draw_text2(term, dlg_data, x, y, title, titlelen, 0, title_color);
+ draw_text2(term, dlg_data, x + titlecells, y, " ", 1, 0,
title_color);
}
}
@@ -181,6 +179,23 @@ init_widget(struct dialog_data *dlg_data, int i)
return widget_data;
}
+static int
+check_range(struct dialog_data *dlg_data, struct widget_data *widget_data)
+{
+ if (!dlg_data->dlg->layout.only_widgets) {
+ struct box *box = &widget_data->box;
+ struct box *dlgbox = &dlg_data->real_box;
+ int y = box->y - dlgbox->y;
+
+ if ((y < dlg_data->y) || (y >= dlg_data->y + dlgbox->height)) {
+ dlg_data->y = y / dlgbox->height * dlgbox->height;
+ redraw_dialog(dlg_data, 0);
+ return 1;
+ }
+ }
+ return 0;
+}
+
void
select_widget(struct dialog_data *dlg_data, struct widget_data *widget_data)
{
@@ -190,6 +205,9 @@ select_widget(struct dialog_data *dlg_data, struct widget_data *widget_data)
dlg_data->selected_widget_id = widget_data - dlg_data->widgets_data;
+ if (check_range(dlg_data, widget_data))
+ return;
+
display_widget(dlg_data, previously_selected_widget);
display_widget(dlg_data, widget_data);
}
@@ -228,6 +246,11 @@ cycle_widget_focus(struct dialog_data *dlg_data, int direction)
} while (!widget_is_focusable(selected_widget(dlg_data))
&& dlg_data->selected_widget_id != prev_selected);
+ if (check_range(dlg_data, selected_widget(dlg_data))) {
+ redraw_from_window(dlg_data->win);
+ return;
+ }
+
display_widget(dlg_data, previously_selected_widget);
display_widget(dlg_data, selected_widget(dlg_data));
redraw_from_window(dlg_data->win);
@@ -238,6 +261,7 @@ dialog_ev_init(struct dialog_data *dlg_data)
{
int i;
+ dlg_data->y = 0;
/* TODO: foreachback_widget() */
for (i = dlg_data->number_of_widgets - 1; i >= 0; i--) {
struct widget_data *widget_data;
@@ -421,6 +445,7 @@ dialog_ev_abort(struct dialog_data *dlg_data)
}
freeml(dlg_data->ml);
+ dlg_data->y = 0;
}
/* TODO: use EVENT_PROCESSED/EVENT_NOT_PROCESSED. */
@@ -554,17 +579,17 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
switch (wdata->widget->type) {
case WIDGET_FIELD_PASS:
case WIDGET_FIELD:
- dlg_format_field(term, wdata, x, y, w, rw, ALIGN_LEFT,
+ dlg_format_field(term, dlg_data, wdata, x, y, w, rw, ALIGN_LEFT,
format_only);
break;
case WIDGET_LISTBOX:
- dlg_format_listbox(term, wdata, x, y, w, h, rw,
+ dlg_format_listbox(term, dlg_data, wdata, x, y, w, h, rw,
ALIGN_LEFT, format_only);
break;
case WIDGET_TEXT:
- dlg_format_text(term, wdata, x, y, w, rw, h,
+ dlg_format_text(term, dlg_data, wdata, x, y, w, rw, h,
format_only);
break;
@@ -583,7 +608,7 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
break;
}
- dlg_format_group(term, wdata, size, x, y, w, rw,
+ dlg_format_group(term, dlg_data, wdata, size, x, y, w, rw,
format_only);
wdata += size - 1;
@@ -591,7 +616,7 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
/* No horizontal space between checkboxes belonging to
* the same group. */
- dlg_format_checkbox(term, wdata, x, y, w, rw,
+ dlg_format_checkbox(term, dlg_data, wdata, x, y, w, rw,
ALIGN_LEFT, format_only);
if (widgets > 1
&& group == widget_has_group(&wdata[1]))
@@ -603,7 +628,7 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
/* We assume that the buttons are all stuffed at the very end
* of the dialog. */
case WIDGET_BUTTON:
- dlg_format_buttons(term, wdata, widgets,
+ dlg_format_buttons(term, dlg_data, wdata, widgets,
x, y, w, rw, ALIGN_CENTER, format_only);
return;
}
diff --git a/src/bfu/dialog.h b/src/bfu/dialog.h
index b0cde3b..bec914c 100644
--- a/src/bfu/dialog.h
+++ b/src/bfu/dialog.h
@@ -100,6 +100,8 @@ struct dialog_data {
struct memory_list *ml;
struct box box;
+ struct box real_box;
+ int y;
int number_of_widgets;
int selected_widget_id;
struct term_event *term_event;
diff --git a/src/bfu/group.c b/src/bfu/group.c
index cc4c6d8..15bd827 100644
--- a/src/bfu/group.c
+++ b/src/bfu/group.c
@@ -20,7 +20,7 @@
#define CHECKBOX_LEN 3 /* "[X]" or "(X)" */
void
-dlg_format_group(struct terminal *term,
+dlg_format_group(struct terminal *term, struct dialog_data *dlg_data,
struct widget_data *widget_data,
int n, int x, int *y, int w, int *rw, int format_only)
{
@@ -87,14 +87,14 @@ dlg_format_group(struct terminal *term,
text,
label_length,
NULL);
- draw_text(term, xpos + width
+ draw_text2(term, dlg_data, xpos + width
+ label_padding,
*y, text, lb, 0,
color);
} else
#endif /* CONFIG_UTF8 */
{
- draw_text(term, xpos + width
+ draw_text2(term, dlg_data, xpos + width
+ label_padding,
*y, text,
label_length, 0,
@@ -113,12 +113,12 @@ dlg_format_group(struct terminal *term,
text,
label_length,
NULL);
- draw_text(term, xpos, *y,
+ draw_text2(term, dlg_data, xpos, *y,
text, lb, 0, color);
} else
#endif /* CONFIG_UTF8 */
{
- draw_text(term, xpos, *y,
+ draw_text2(term, dlg_data, xpos, *y,
text, label_length,
0, color);
}
@@ -155,11 +155,11 @@ group_layouter(struct dialog_data *dlg_data)
#endif /* CONFIG_UTF8 */
rw = int_min(w, strlen(dlg_data->dlg->title));
- dlg_format_group(term, dlg_data->widgets_data, n,
+ dlg_format_group(term, dlg_data, dlg_data->widgets_data, n,
0, &y, w, &rw, 1);
y++;
- dlg_format_buttons(term, dlg_data->widgets_data + n, 2, 0, &y, w,
+ dlg_format_buttons(term, dlg_data, dlg_data->widgets_data + n, 2, 0, &y, w,
&rw, ALIGN_CENTER, 1);
w = rw;
@@ -167,10 +167,10 @@ group_layouter(struct dialog_data *dlg_data)
draw_dialog(dlg_data, w, y);
y = dlg_data->box.y + DIALOG_TB + 1;
- dlg_format_group(term, dlg_data->widgets_data, n,
+ dlg_format_group(term, dlg_data, dlg_data->widgets_data, n,
dlg_data->box.x + DIALOG_LB, &y, w, NULL, 0);
y++;
- dlg_format_buttons(term, dlg_data->widgets_data + n, 2,
+ dlg_format_buttons(term, dlg_data, dlg_data->widgets_data + n, 2,
dlg_data->box.x + DIALOG_LB, &y, w, &rw, ALIGN_CENTER, 0);
}
diff --git a/src/bfu/group.h b/src/bfu/group.h
index 0de645d..9b92c2a 100644
--- a/src/bfu/group.h
+++ b/src/bfu/group.h
@@ -5,7 +5,7 @@ struct dialog_data;
struct terminal;
struct widget_data;
-void dlg_format_group(struct terminal *term,
+void dlg_format_group(struct terminal *term, struct dialog_data *dlg_data,
struct widget_data *widget_data,
int n, int x, int *y, int w, int *rw, int format_only);
diff --git a/src/bfu/inpfield.c b/src/bfu/inpfield.c
index 4c0dcd2..0a9c63e 100644
--- a/src/bfu/inpfield.c
+++ b/src/bfu/inpfield.c
@@ -103,7 +103,7 @@ check_nonempty(struct dialog_data *dlg_data, struct widget_data *widget_data)
}
void
-dlg_format_field(struct terminal *term,
+dlg_format_field(struct terminal *term, struct dialog_data *dlg_data,
struct widget_data *widget_data,
int x, int *y, int w, int *rw, enum format_align align, int format_only)
{
@@ -132,7 +132,7 @@ dlg_format_field(struct terminal *term,
if (label && *label) {
if (!format_only) text_color = get_bfu_color(term, "dialog.text");
- dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT, format_only);
+ dlg_format_text_do(term, dlg_data, label, x, y, w, rw, text_color, ALIGN_LEFT, format_only);
}
/* XXX: We want the field and label on the same line if the terminal
@@ -140,7 +140,7 @@ dlg_format_field(struct terminal *term,
if (label && *label && float_label) {
if (widget_data->widget->info.field.flags & INPFIELD_FLOAT) {
(*y) -= INPUTFIELD_HEIGHT;
- dlg_format_text_do(term, INPUTFIELD_FLOAT_SEPARATOR,
+ dlg_format_text_do(term, dlg_data, INPUTFIELD_FLOAT_SEPARATOR,
x + label_width, y, w, rw,
text_color, ALIGN_LEFT, format_only);
w -= INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
@@ -312,7 +312,7 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
if (term->utf8_cp)
w = utf8_cells2bytes(text, w, NULL);
#endif /* CONFIG_UTF8 */
- draw_text(term, widget_data->box.x, widget_data->box.y,
+ draw_text2(term, dlg_data, widget_data->box.x, widget_data->box.y,
text, w, 0, color);
} else {
struct box box;
@@ -763,7 +763,7 @@ input_line_layouter(struct dialog_data *dlg_data)
- ses->status.show_status_bar
- ses->status.show_tabs_bar;
- dlg_format_field(win->term, dlg_data->widgets_data, 0,
+ dlg_format_field(win->term, dlg_data, dlg_data->widgets_data, 0,
&y, win->term->width, NULL, ALIGN_LEFT, 0);
}
diff --git a/src/bfu/inpfield.h b/src/bfu/inpfield.h
index d45a902..fb2270e 100644
--- a/src/bfu/inpfield.h
+++ b/src/bfu/inpfield.h
@@ -62,7 +62,7 @@ extern const struct widget_ops field_pass_ops;
widget_handler_status_T check_number(struct dialog_data *, struct widget_data *);
widget_handler_status_T check_nonempty(struct dialog_data *, struct widget_data *);
-void dlg_format_field(struct terminal *, struct widget_data *, int, int *, int, int *, enum format_align, int format_only);
+void dlg_format_field(struct terminal *, struct dialog_data *, struct widget_data *, int, int *, int, int *, enum format_align, int format_only);
void input_field(struct terminal *, struct memory_list *, int, unsigned char *,
unsigned char *, unsigned char *, unsigned char *, void *,
diff --git a/src/bfu/listbox.c b/src/bfu/listbox.c
index 7ec1b66..e4de12f 100644
--- a/src/bfu/listbox.c
+++ b/src/bfu/listbox.c
@@ -41,7 +41,8 @@ get_listbox_widget_data(struct widget_data *widget_data)
/* Layout for generic boxes */
void
-dlg_format_listbox(struct terminal *term, struct widget_data *widget_data,
+dlg_format_listbox(struct terminal *term, struct dialog_data *dlg_data,
+ struct widget_data *widget_data,
int x, int *y, int w, int max_height, int *rw,
enum format_align align, int format_only)
{
diff --git a/src/bfu/listbox.h b/src/bfu/listbox.h
index c3599e5..63b8be4 100644
--- a/src/bfu/listbox.h
+++ b/src/bfu/listbox.h
@@ -133,7 +133,7 @@ struct listbox_item {
extern const struct widget_ops listbox_ops;
-void dlg_format_listbox(struct terminal *, struct widget_data *, int, int *, int, int, int *, enum format_align, int format_only);
+void dlg_format_listbox(struct terminal *, struct dialog_data *, struct widget_data *, int, int *, int, int, int *, enum format_align, int format_only);
struct listbox_item *traverse_listbox_items_list(struct listbox_item *, struct listbox_data *, int, int, int (*)(struct listbox_item *, void *, int *), void *);
diff --git a/src/bfu/text.c b/src/bfu/text.c
index e8be019..3d2895e 100644
--- a/src/bfu/text.c
+++ b/src/bfu/text.c
@@ -211,7 +211,8 @@ split_lines(struct widget_data *widget_data, int max_width)
/* Format text according to dialog box and alignment. */
void
-dlg_format_text_do(struct terminal *term, unsigned char *text,
+dlg_format_text_do(struct terminal *term, struct dialog_data *dlg_data,
+ unsigned char *text,
int x, int *y, int width, int *real_width,
struct color_pair *color, enum format_align align,
int format_only)
@@ -255,12 +256,13 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
assert(cells <= width && shift < width);
- draw_text(term, x + shift, *y, text, line_width, 0, color);
+ draw_text2(term, dlg_data, x + shift, *y, text, line_width, 0, color);
}
}
void
-dlg_format_text(struct terminal *term, struct widget_data *widget_data,
+dlg_format_text(struct terminal *term, struct dialog_data *dlg_data,
+ struct widget_data *widget_data,
int x, int *y, int width, int *real_width, int max_height,
int format_only)
{
@@ -335,7 +337,7 @@ dlg_format_text(struct terminal *term, struct widget_data *widget_data,
widget_data->info.text.current = 0;
}
- dlg_format_text_do(term, text,
+ dlg_format_text_do(term, dlg_data, text,
x, y, width, real_width,
get_bfu_color(term, "dialog.text"),
widget_data->widget->info.text.align, format_only);
@@ -395,8 +397,8 @@ display_text(struct dialog_data *dlg_data, struct widget_data *widget_data)
/* Hope this is at least a bit reasonable. Set cursor
* and window pointer to start of the first text line. */
- set_cursor(win->term, widget_data->box.x, widget_data->box.y, 1);
- set_window_ptr(win, widget_data->box.x, widget_data->box.y);
+ set_cursor2(win->term, dlg_data, widget_data->box.x, widget_data->box.y, 1);
+ set_window_ptr2(dlg_data, win, widget_data->box.x, widget_data->box.y);
return EVENT_PROCESSED;
}
@@ -423,7 +425,7 @@ format_and_display_text(struct widget_data *widget_data,
draw_box(term, &widget_data->box, ' ', 0,
get_bfu_color(term, "dialog.generic"));
- dlg_format_text(term, widget_data,
+ dlg_format_text(term, dlg_data, widget_data,
widget_data->box.x, &y, widget_data->box.width, NULL,
height, 0);
diff --git a/src/bfu/text.h b/src/bfu/text.h
index 8dd3365..b181c1a 100644
--- a/src/bfu/text.h
+++ b/src/bfu/text.h
@@ -4,6 +4,7 @@
#include "util/color.h"
struct dialog;
+struct dialog_data;
struct terminal;
struct widget_info_text {
@@ -45,12 +46,12 @@ void add_dlg_text(struct dialog *dlg, unsigned char *text,
enum format_align align, int bottom_pad);
extern const struct widget_ops text_ops;
-void dlg_format_text_do(struct terminal *term,
+void dlg_format_text_do(struct terminal *term, struct dialog_data *dlg_data,
unsigned char *text, int x, int *y, int w, int *rw,
struct color_pair *scolor, enum format_align align, int format_only);
void
-dlg_format_text(struct terminal *term, struct widget_data *widget_data,
+dlg_format_text(struct terminal *term, struct dialog_data *dlg_data, struct widget_data *widget_data,
int x, int *y, int dlg_width, int *real_width, int height, int format_only);
#define text_is_scrollable(widget_data) \
diff --git a/src/dialogs/download.c b/src/dialogs/download.c
index 0116578..b90f047 100644
--- a/src/dialogs/download.c
+++ b/src/dialogs/download.c
@@ -157,7 +157,7 @@ download_dialog_layouter(struct dialog_data *dlg_data)
int_lower_bound(&w, DOWN_DLG_MIN);
}
- dlg_format_text_do(term, url, 0, &y, w, &rw,
+ dlg_format_text_do(term, dlg_data, url, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT, 1);
y++;
@@ -166,11 +166,11 @@ download_dialog_layouter(struct dialog_data *dlg_data)
#if CONFIG_BITTORRENT
if (bittorrent) y += 2;
#endif
- dlg_format_text_do(term, msg, 0, &y, w, &rw,
+ dlg_format_text_do(term, dlg_data, msg, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT, 1);
y++;
- dlg_format_buttons(term, dlg_data->widgets_data,
+ dlg_format_buttons(term, dlg_data, dlg_data->widgets_data,
dlg_data->number_of_widgets, 0, &y, w,
&rw, ALIGN_CENTER, 1);
@@ -190,7 +190,7 @@ download_dialog_layouter(struct dialog_data *dlg_data)
y = dlg_data->box.y + DIALOG_TB + 1;
x = dlg_data->box.x + DIALOG_LB;
- dlg_format_text_do(term, url, x, &y, w, NULL,
+ dlg_format_text_do(term, dlg_data, url, x, &y, w, NULL,
dialog_text_color, ALIGN_LEFT, 0);
if (show_meter) {
@@ -207,11 +207,11 @@ download_dialog_layouter(struct dialog_data *dlg_data)
}
#endif
y++;
- dlg_format_text_do(term, msg, x, &y, w, NULL,
+ dlg_format_text_do(term, dlg_data, msg, x, &y, w, NULL,
dialog_text_color, ALIGN_LEFT, 0);
y++;
- dlg_format_buttons(term, dlg_data->widgets_data,
+ dlg_format_buttons(term, dlg_data, dlg_data->widgets_data,
dlg_data->number_of_widgets, x, &y, w,
NULL, ALIGN_CENTER, 0);
diff --git a/src/terminal/draw.c b/src/terminal/draw.c
index b3b3706..267d9ac 100644
--- a/src/terminal/draw.c
+++ b/src/terminal/draw.c
@@ -7,6 +7,7 @@
#include "elinks.h"
+#include "bfu/dialog.h"
#include "config/options.h"
#include "intl/charsets.h"
#include "terminal/color.h"
@@ -559,6 +560,23 @@ draw_text(struct terminal *term, int x, int y,
}
void
+draw_text2(struct terminal *term, struct dialog_data *dlg_data, int x, int y,
+ unsigned char *text, int length,
+ enum screen_char_attr attr, struct color_pair *color)
+{
+ struct box *box = &dlg_data->real_box;
+
+ if (box->height) {
+ int y_max = box->y + box->height;
+
+ y -= dlg_data->y;
+ if (y < box->y || y >= y_max) return;
+ }
+ draw_text(term, x, y, text, length, attr, color);
+}
+
+
+void
set_cursor(struct terminal *term, int x, int y, int blockable)
{
assert(term && term->screen);
@@ -580,6 +598,24 @@ set_cursor(struct terminal *term, int x, int y, int blockable)
}
void
+set_cursor2(struct terminal *term, struct dialog_data *dlg_data, int x, int y, int blockable)
+{
+ struct box *box = &dlg_data->real_box;
+
+ assert(term && term->screen);
+ if_assert_failed return;
+
+ if (box->height) {
+ int y_max = box->y + box->height;
+
+ y -= dlg_data->y;
+ if (y < box->y || y >= y_max) return;
+ }
+ set_cursor(term, x, y, blockable);
+}
+
+
+void
clear_terminal(struct terminal *term)
{
struct box box;
diff --git a/src/terminal/draw.h b/src/terminal/draw.h
index 6dcd31a..20fba4e 100644
--- a/src/terminal/draw.h
+++ b/src/terminal/draw.h
@@ -4,6 +4,7 @@
#include "intl/charsets.h" /* unicode_val_T */
struct color_pair;
+struct dialog_data;
struct box;
struct terminal;
@@ -280,6 +281,12 @@ void draw_text(struct terminal *term, int x, int y,
enum screen_char_attr attr,
struct color_pair *color);
+/** Draws text for dialogs. */
+void draw_text2(struct terminal *term, struct dialog_data *dlg_data, int x, int y,
+ unsigned char *text, int length,
+ enum screen_char_attr attr, struct color_pair *color);
+
+
/** Draws @a length chars from @a line on the screen. */
void draw_line(struct terminal *term, int x, int y, int length,
struct screen_char *line);
@@ -289,6 +296,9 @@ void draw_line(struct terminal *term, int x, int y, int length,
* bottom right corner of the screen. */
void set_cursor(struct terminal *term, int x, int y, int blockable);
+/* set cursor for dialogs */
+void set_cursor2(struct terminal *term, struct dialog_data *dlg_data, int x, int y, int blockable);
+
/** Blanks the screen. */
void clear_terminal(struct terminal *);
diff --git a/src/terminal/window.c b/src/terminal/window.c
index 9ac7191..934207d 100644
--- a/src/terminal/window.c
+++ b/src/terminal/window.c
@@ -7,6 +7,7 @@
#include "elinks.h"
+#include "bfu/dialog.h"
#include "bfu/menu.h"
#include "terminal/event.h"
#include "terminal/tab.h"
@@ -227,3 +228,17 @@ would_window_receive_keypresses(const struct window *win)
return 1;
}
#endif /* CONFIG_SCRIPTING_SPIDERMONKEY */
+
+void
+set_window_ptr2(struct dialog_data *dlg_data, struct window *window, int x, int y)
+{
+ struct box *box = &dlg_data->real_box;
+
+ if (box->height) {
+ int y_max = box->y + box->height;
+
+ y -= dlg_data->y;
+ if (y < box->y || y >= y_max) return;
+ }
+ set_window_ptr(window, x, y);
+}
diff --git a/src/terminal/window.h b/src/terminal/window.h
index 8bb329d..c8250ac 100644
--- a/src/terminal/window.h
+++ b/src/terminal/window.h
@@ -3,6 +3,7 @@
#include "util/lists.h"
+struct dialog_data;
struct term_event;
struct terminal;
struct window;
@@ -73,6 +74,7 @@ void add_window(struct terminal *, window_handler_T, void *);
void delete_window(struct window *);
void delete_window_ev(struct window *, struct term_event *ev);
#define set_window_ptr(window, x_, y_) do { (window)->x = (x_); (window)->y = (y_); } while (0)
+void set_window_ptr2(struct dialog_data *dlg_data, struct window *window, int x, int y);
void get_parent_ptr(struct window *, int *, int *);
void add_empty_window(struct terminal *, void (*)(void *), void *);
--
1.7.1