From 3eb4ab9990a9d3ed3eadce2d0a4c5ef8548a5af4 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Thu, 22 Jun 2017 15:09:53 -0500
Subject: [PATCH 001/131] Fix make dist
Signed-off-by: David Woodhouse
---
tests/Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 88261546..213834fb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -37,7 +37,7 @@ USER_CERTS = $(certsdir)/user-cert.pem $(certsdir)/dsa-cert.pem $(certsdir)/ec-c
EXTRA_DIST = certs/ca.pem certs/ca-key.pem certs/user-cert.pem $(USER_KEYS) $(USER_CERTS) \
certs/server-cert.pem certs/server-key.pem configs/test1.passwd \
common.sh configs/test-user-cert.config configs/test-user-pass.config \
- configs/user-cert.prm softhsm2.conf.in softhsm .config/pkcs11/modules/softhsm2.module
+ configs/user-cert.prm softhsm2.conf.in softhsm
dist_check_SCRIPTS =
From f57eccd4c7a027aee50ab00ef1b042ac8e3ed8f7 Mon Sep 17 00:00:00 2001
From: Brennan Hildebrand
Date: Tue, 18 Jul 2017 15:42:11 -0700
Subject: [PATCH 002/131] Small mod to esp.c to support FreeBSD.
---
esp.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/esp.c b/esp.c
index ae60269e..7876fd51 100644
--- a/esp.c
+++ b/esp.c
@@ -23,6 +23,10 @@
#include
#include
#include
+#ifdef __FreeBSD__
+#include
+#include
+#endif
#include
#include
From 395201c8074d0e0bfe28c4df65a19edfbb2dbcec Mon Sep 17 00:00:00 2001
From: Taylor May
Date: Wed, 2 Aug 2017 22:19:36 -0500
Subject: [PATCH 003/131] Suppress warnings from noverify in challenge-login
Suppress the InsecureRequestWarning messages in globalprotect-challenge-login.py when using the --no-verify flag.
---
globalprotect-challenge-login.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/globalprotect-challenge-login.py b/globalprotect-challenge-login.py
index e592a2a2..0fb3d7ed 100755
--- a/globalprotect-challenge-login.py
+++ b/globalprotect-challenge-login.py
@@ -35,6 +35,10 @@
else:
cert = None
+if not args.verify:
+ from requests.packages.urllib3.exceptions import InsecureRequestWarning
+ requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+
s = requests.Session()
s.headers['User-Agent'] = 'PAN GlobalProtect'
s.cert = cert
From 4d6b342317e9ed6cfc5e67cfdb5494ca29b8363d Mon Sep 17 00:00:00 2001
From: Alexander Kurilo
Date: Thu, 10 Aug 2017 15:17:43 +0300
Subject: [PATCH 004/131] Remove supposedly excessive check to fix #50
In my case, XML had "6" in 13th argument instead of expected -1;
removing the check didn't seem to break anything.
---
auth-globalprotect.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 392fd8b7..29ea90b2 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -79,7 +79,7 @@ static const struct gp_login_arg gp_login_args[] = {
[10] = { .opt="unknown-arg10", .show=1 },
[11] = { .opt="unknown-arg11", .show=1 },
[12] = { .opt="connection-type", .err_missing=1, .check="tunnel" },
- [13] = { .opt="minus1", .err_missing=1, .check="-1" },
+ [13] = { .opt="minus1", .err_missing=1 },
[14] = { .opt="clientVer", .err_missing=1, .check="4100" },
[15] = { .opt="preferred-ip", .save=1 },
};
From 71428d036b46e07dab7576ef6090844f2d57c4ae Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Sat, 27 May 2017 12:02:45 +0100
Subject: [PATCH 005/131] Add -g to test CFLAGS
Signed-off-by: David Woodhouse
---
.gitlab-ci.yml | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3218c8b1..90f7536a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,7 +12,7 @@ CentOS7/GnuTLS:
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
java-devel-openjdk
- ./autogen.sh
- - ./configure --with-java
+ - ./configure --with-java CFLAGS=-g
- make -j4
# XFAIL the auth-pkcs11 test because GnuTLS 3.3.8 doesn't support pin-value
- make VERBOSE=1 -j4 check
@@ -38,7 +38,7 @@ CentOS7/OpenSSL:
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
java-devel-openjdk 'pkgconfig(libp11)'
- ./autogen.sh
- - ./configure --without-gnutls --with-openssl --with-java --without-openssl-version-check --enable-dtls-xfail --disable-dsa-tests
+ - ./configure --without-gnutls --with-openssl --with-java --without-openssl-version-check --enable-dtls-xfail --disable-dsa-tests CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -63,7 +63,7 @@ CentOS6/OpenSSL:
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
java-devel-openjdk vpnc 'pkgconfig(libp11)' 'pkgconfig(p11-kit-1)'
- ./autogen.sh
- - ./configure --with-java --without-openssl-version-check --enable-dtls-xfail
+ - ./configure --with-java --without-openssl-version-check --enable-dtls-xfail CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -86,7 +86,7 @@ Fedora/GnuTLS:
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
java-devel-openjdk
- ./autogen.sh
- - ./configure --with-java
+ - ./configure --with-java CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -109,7 +109,7 @@ Fedora/GnuTLS/clang:
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
java-devel-openjdk clang
- ./autogen.sh
- - ./configure --with-java CC=clang
+ - ./configure --with-java CC=clang CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -133,7 +133,7 @@ Fedora/OpenSSL:
java-devel-openjdk 'pkgconfig(libp11)'
- dnf --enablerepo=updates-testing update -y libp11\* gnutls
- ./autogen.sh
- - ./configure --without-gnutls --with-openssl --without-openssl-version-check --disable-dsa-tests
+ - ./configure --without-gnutls --with-openssl --without-openssl-version-check --disable-dsa-tests CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -157,7 +157,7 @@ Fedora/OpenSSL/clang:
java-devel-openjdk 'pkgconfig(libp11)' clang
- dnf --enablerepo=updates-testing update -y libp11\* gnutls
- ./autogen.sh
- - ./configure CC=clang --without-gnutls --with-openssl --without-openssl-version-check --disable-dsa-tests
+ - ./configure CC=clang --without-gnutls --with-openssl --without-openssl-version-check --disable-dsa-tests CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -178,7 +178,7 @@ MinGW32/GnuTLS:
- mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
- echo ':DOSWin:M::MZ::/usr/bin/wine:' > /proc/sys/fs/binfmt_misc/register
- ./autogen.sh
- - mingw32-configure
+ - mingw32-configure CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -199,7 +199,7 @@ MinGW32/OpenSSL:
- mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
- echo ':DOSWin:M::MZ::/usr/bin/wine:' > /proc/sys/fs/binfmt_misc/register
- ./autogen.sh
- - mingw32-configure --without-gnutls --with-openssl --without-openssl-version-check
+ - mingw32-configure --without-gnutls --with-openssl --without-openssl-version-check CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -220,7 +220,7 @@ MinGW64/GnuTLS:
- mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
- echo ':DOSWin:M::MZ::/usr/bin/wine:' > /proc/sys/fs/binfmt_misc/register
- ./autogen.sh
- - mingw64-configure
+ - mingw64-configure CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
@@ -241,7 +241,7 @@ MinGW64/OpenSSL:
- mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
- echo ':DOSWin:M::MZ::/usr/bin/wine:' > /proc/sys/fs/binfmt_misc/register
- ./autogen.sh
- - mingw64-configure --without-gnutls --with-openssl --without-openssl-version-check
+ - mingw64-configure --without-gnutls --with-openssl --without-openssl-version-check CFLAGS=-g
- make -j4
- make VERBOSE=1 -j4 check
tags:
From cecadffb25e46c283b930a0a599dce9db1172c9b Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Wed, 31 May 2017 09:45:03 +0100
Subject: [PATCH 006/131] Make dup_config_arg() always duplicate the argument
.... even when conversion fails. Otherwise we end up trying to free a
member of argv[], which never works well.
Signed-off-by: David Woodhouse
---
main.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/main.c b/main.c
index c127b62c..8ea298fd 100644
--- a/main.c
+++ b/main.c
@@ -913,9 +913,21 @@ static char *xstrdup(const char *arg)
#define keep_config_arg() \
(config_file ? xstrdup(config_arg) : convert_arg_to_utf8(argv, config_arg))
-#define dup_config_arg() \
- ((config_file || is_arg_utf8(config_arg)) ? xstrdup(config_arg) : \
- convert_arg_to_utf8(argv, config_arg))
+#define dup_config_arg() __dup_config_arg(argv, config_arg)
+
+static inline char *__dup_config_arg(char **argv, char *config_arg)
+{
+ char *res;
+
+ if (config_file || is_arg_utf8(config_arg))
+ return xstrdup(config_arg);
+
+ res = convert_arg_to_utf8(argv, config_arg);
+ /* Force a copy, even if conversion failed */
+ if (res == config_arg)
+ res = xstrdup(res);
+ return res;
+}
static int next_option(int argc, char **argv, char **config_arg)
{
From 2e7415faf02b8d9a0d809c537a25bcbff10cc2ef Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Wed, 31 May 2017 11:37:00 +0100
Subject: [PATCH 007/131] Warn if setlocale() fails
Signed-off-by: David Woodhouse
---
main.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/main.c b/main.c
index 8ea298fd..a18bfd22 100644
--- a/main.c
+++ b/main.c
@@ -1093,7 +1093,9 @@ int main(int argc, char **argv)
bindtextdomain("openconnect", LOCALEDIR);
#endif
- setlocale(LC_ALL, "");
+ if (!setlocale(LC_ALL, ""))
+ fprintf(stderr,
+ _("WARNING: Cannot set locale: %s\n"), strerror(errno));
#ifdef HAVE_NL_LANGINFO
charset = nl_langinfo(CODESET);
From d8848c75d47e8919626247966845c821e1b1d051 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Wed, 31 May 2017 11:43:11 +0100
Subject: [PATCH 008/131] Update translations from GNOME
Signed-off-by: David Woodhouse
---
po/pl.po | 557 ++++++++++++++++++++++++++++---------------------------
1 file changed, 284 insertions(+), 273 deletions(-)
diff --git a/po/pl.po b/po/pl.po
index bed87c55..05aa7d66 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: openconnect\n"
"Report-Msgid-Bugs-To: openconnect-devel@lists.infradead.org\n"
-"POT-Creation-Date: 2017-05-15 00:47+0100\n"
+"POT-Creation-Date: 2017-05-31 11:37+0100\n"
"PO-Revision-Date: 2011-09-22 22:31+0000\n"
"Last-Translator: FULL NAME \n"
"Language-Team: Polish (http://www.transifex.net/projects/p/meego/team/pl/)\n"
@@ -464,7 +464,7 @@ msgstr ""
msgid "deflate failed %d\n"
msgstr "%d „deflate” się nie powiodło\n"
-#: cstp.c:903 dtls.c:261 dtls.c:720 esp.c:171 mainloop.c:69 oncp.c:937
+#: cstp.c:903 dtls.c:281 dtls.c:740 esp.c:166 mainloop.c:69 oncp.c:954
msgid "Allocation failed\n"
msgstr "Przydzielenie się nie powiodło\n"
@@ -491,7 +491,7 @@ msgstr "Otrzymano odpowiedź „DPD” CSTP\n"
msgid "Got CSTP Keepalive\n"
msgstr "Otrzymano „Keepalive” CSTP\n"
-#: cstp.c:957 oncp.c:1026
+#: cstp.c:957 oncp.c:1043
#, c-format
msgid "Received uncompressed data packet of %d bytes\n"
msgstr "Otrzymano nieskompresowany pakiet danych o rozmiarze %d bajtów\n"
@@ -518,35 +518,35 @@ msgstr "otrzymano pakiet wymuszenia zakończenia serwera\n"
msgid "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"
msgstr "Nieznany pakiet %02x %02x %02x %02x %02x %02x %02x %02x\n"
-#: cstp.c:1044 oncp.c:1143
+#: cstp.c:1044 oncp.c:1160
#, c-format
msgid "SSL wrote too few bytes! Asked for %d, sent %d\n"
msgstr "SSL zapisało za mało bajtów. Poproszono o %d, wysłano %d\n"
#. Not that this will ever happen; we don't even process
#. the setting when we're asked for it.
-#: cstp.c:1072 oncp.c:1181
+#: cstp.c:1072 oncp.c:1198
msgid "CSTP rekey due\n"
msgstr "„rekey” CSTP do\n"
#. if we failed rehandshake try establishing a new-tunnel instead of failing
-#: cstp.c:1079 oncp.c:1188
+#: cstp.c:1079 oncp.c:1205
msgid "Rehandshake failed; attempting new-tunnel\n"
msgstr "Ponowne powitanie się nie powiodło. Próbowanie „new-tunnel”\n"
-#: cstp.c:1090 oncp.c:1199
+#: cstp.c:1090 oncp.c:1216
msgid "CSTP Dead Peer Detection detected dead peer!\n"
msgstr "Wykrywanie martwych partnerów CSTP wykryło martwego partnera.\n"
-#: cstp.c:1094 oncp.c:1113 oncp.c:1203
+#: cstp.c:1094 oncp.c:1130 oncp.c:1220
msgid "Reconnect failed\n"
msgstr "Ponowne połączenie się nie powiodło\n"
-#: cstp.c:1110 oncp.c:1219
+#: cstp.c:1110 oncp.c:1236
msgid "Send CSTP DPD\n"
msgstr "Wysłanie „DPD” CSTP\n"
-#: cstp.c:1122 oncp.c:1230
+#: cstp.c:1122 oncp.c:1247
msgid "Send CSTP Keepalive\n"
msgstr "Wysłanie „Keepalive” CSTP\n"
@@ -557,7 +557,7 @@ msgstr ""
"Wysyłanie nieskompresowanego pakietu danych o rozmiarze %d bajtów (wynosił "
"%d)\n"
-#: cstp.c:1158 oncp.c:1255
+#: cstp.c:1158 oncp.c:1272
#, c-format
msgid "Sending uncompressed data packet of %d bytes\n"
msgstr "Wysyłanie nieskompresowanego pakietu danych o rozmiarze %d bajtów\n"
@@ -576,206 +576,206 @@ msgstr "Próbowanie uwierzytelnienia „Digest” do pośrednika\n"
msgid "Attempting Digest authentication to server '%s'\n"
msgstr "Próbowanie uwierzytelnienia „Digest” do serwera „%s”\n"
-#: dtls.c:93
+#: dtls.c:113
msgid "DTLS connection attempted with an existing fd\n"
msgstr "Próbowano połączenia DTLS za pomocą istniejącego deskryptora pliku\n"
-#: dtls.c:99
+#: dtls.c:119
msgid "No DTLS address\n"
msgstr "Brak adresu DTLS\n"
#. We probably didn't offer it any ciphers it liked
-#: dtls.c:106
+#: dtls.c:126
msgid "Server offered no DTLS cipher option\n"
msgstr "Serwer nie zaproponował żadnej opcji szyfrowania DTLS\n"
#. XXX: Theoretically, SOCKS5 proxies can do UDP too
-#: dtls.c:113
+#: dtls.c:133
msgid "No DTLS when connected via proxy\n"
msgstr "Brak DTLS podczas łączenia przez pośrednika\n"
-#: dtls.c:179
+#: dtls.c:199
#, c-format
msgid "DTLS option %s : %s\n"
msgstr "Opcja DTLS %s: %s\n"
-#: dtls.c:220
+#: dtls.c:240
#, c-format
msgid "DTLS initialised. DPD %d, Keepalive %d\n"
msgstr "Zainicjowano DTLS. DPD %d, Keepalive %d\n"
-#: dtls.c:246
+#: dtls.c:266
msgid "Attempt new DTLS connection\n"
msgstr "Próba nowego połączenia DTLS\n"
-#: dtls.c:272
+#: dtls.c:292
#, c-format
msgid "Received DTLS packet 0x%02x of %d bytes\n"
msgstr "Otrzymano pakiet DTLS 0x%02x z %d bajtów\n"
-#: dtls.c:286
+#: dtls.c:306
msgid "Got DTLS DPD request\n"
msgstr "Otrzymano żądanie „DPD” DTLS\n"
-#: dtls.c:292
+#: dtls.c:312
msgid "Failed to send DPD response. Expect disconnect\n"
msgstr ""
"Wysłanie odpowiedzi DPD się nie powiodło. Należy oczekiwać rozłączenia\n"
-#: dtls.c:296
+#: dtls.c:316
msgid "Got DTLS DPD response\n"
msgstr "Otrzymano odpowiedź „DPD” DTLS\n"
-#: dtls.c:300
+#: dtls.c:320
msgid "Got DTLS Keepalive\n"
msgstr "Otrzymano „Keepalive” DTLS\n"
-#: dtls.c:306
+#: dtls.c:326
msgid "Compressed DTLS packet received when compression not enabled\n"
msgstr "Otrzymano skompresowany pakiet DTLS, kiedy kompresja jest wyłączona\n"
-#: dtls.c:314
+#: dtls.c:334
#, c-format
msgid "Unknown DTLS packet type %02x, len %d\n"
msgstr "Nieznany typ pakietu DTLS %02x, len %d\n"
-#: dtls.c:336
+#: dtls.c:356
msgid "DTLS rekey due\n"
msgstr "„rekey” DTLS do\n"
-#: dtls.c:343
+#: dtls.c:363
msgid "DTLS Rehandshake failed; reconnecting.\n"
msgstr "Ponowne powitanie DTLS się nie powiodło. Łączenie ponownie.\n"
-#: dtls.c:352
+#: dtls.c:372
msgid "DTLS Dead Peer Detection detected dead peer!\n"
msgstr "Wykrywanie martwych partnerów DTLS wykryło martwego partnera.\n"
-#: dtls.c:358
+#: dtls.c:378
msgid "Send DTLS DPD\n"
msgstr "Wysłanie „DPD” DTLS\n"
-#: dtls.c:363
+#: dtls.c:383
msgid "Failed to send DPD request. Expect disconnect\n"
msgstr "Wysłanie żądania DPD się nie powiodło. Należy oczekiwać rozłączenia\n"
-#: dtls.c:376
+#: dtls.c:396
msgid "Send DTLS Keepalive\n"
msgstr "Wysłanie „Keepalive” DTLS\n"
-#: dtls.c:381
+#: dtls.c:401
msgid "Failed to send keepalive request. Expect disconnect\n"
msgstr ""
"Wysłanie żądania Keepalive się nie powiodło. Należy oczekiwać rozłączenia\n"
-#: dtls.c:412 tun.c:541
+#: dtls.c:432 tun.c:541
#, c-format
msgid "Unknown packet (len %d) received: %02x %02x %02x %02x...\n"
msgstr "Otrzymano nieznany pakiet (len %d): %02x %02x %02x %02x...\n"
-#: dtls.c:419
+#: dtls.c:439
#, c-format
msgid "TOS this: %d, TOS last: %d\n"
msgstr "Ten TOS: %d, ostatni TOS: %d\n"
-#: dtls.c:423
+#: dtls.c:443
msgid "UDP setsockopt"
msgstr "setsockopt UDP"
-#: dtls.c:454
+#: dtls.c:474
#, c-format
msgid "DTLS got write error %d. Falling back to SSL\n"
msgstr "DTLS otrzymało błąd zapisu %d. Używanie SSL\n"
-#: dtls.c:468
+#: dtls.c:488
#, c-format
msgid "DTLS got write error: %s. Falling back to SSL\n"
msgstr "DTLS otrzymało błąd zapisu: %s. Używanie SSL\n"
-#: dtls.c:483
+#: dtls.c:503
#, c-format
msgid "Sent DTLS packet of %d bytes; DTLS send returned %d\n"
msgstr "Wysłano pakiet DTLS o rozmiarze %d bajtów. Wysłanie DTLS zwróciło %d\n"
-#: dtls.c:511
+#: dtls.c:531
#, c-format
msgid "Initiating IPv4 MTU detection (min=%d, max=%d)\n"
msgstr "Inicjowanie wykrywania MTU IPv4 (min=%d, max=%d)\n"
-#: dtls.c:531
+#: dtls.c:551
msgid "Too long time in MTU detect loop; assuming negotiated MTU.\n"
msgstr ""
"Za dużo czasu w pętli wykrywania MTU. Przyjmowanie wynegocjowanego MTU.\n"
-#: dtls.c:535
+#: dtls.c:555
#, c-format
msgid "Too long time in MTU detect loop; MTU set to %d.\n"
msgstr "Za dużo czasu w pętli wykrywania MTU. Ustawiono MTU na %d.\n"
-#: dtls.c:544
+#: dtls.c:564
#, c-format
msgid "Sending MTU DPD probe (%u bytes, min=%u, max=%u)\n"
msgstr "Wysyłanie sondy „DPD” MTU (%u bajtów, min=%u, max=%u)\n"
-#: dtls.c:548
+#: dtls.c:568
#, c-format
msgid "Failed to send DPD request (%d %d)\n"
msgstr "Wysłanie żądania DPD się nie powiodło (%d %d)\n"
-#: dtls.c:562 dtls.c:670
+#: dtls.c:582 dtls.c:690
#, c-format
msgid "Received unexpected packet (%.2x) in MTU detection; skipping.\n"
msgstr ""
"Odebrano nieoczekiwany pakiet (%.2x) podczas wykrywania MTU. Pomijanie.\n"
-#: dtls.c:574
+#: dtls.c:594
#, c-format
msgid "Timeout while waiting for DPD response; trying %d\n"
msgstr ""
"Przekroczono czas oczekiwania podczas oczekiwania na odpowiedź DPD. "
"Próbowanie %d\n"
-#: dtls.c:581 dtls.c:662
+#: dtls.c:601 dtls.c:682
msgid "Timeout while waiting for DPD response; resending probe.\n"
msgstr ""
"Przekroczono czas oczekiwania podczas czekania na odpowiedź DPD. Ponowne "
"wysyłanie sondy.\n"
-#: dtls.c:588 dtls.c:689
+#: dtls.c:608 dtls.c:709
#, c-format
msgid "Failed to recv DPD request (%d)\n"
msgstr "Odebranie żądania DPD się nie powiodło (%d)\n"
-#: dtls.c:593
+#: dtls.c:613
#, c-format
msgid "Received MTU DPD probe (%u bytes of %u)\n"
msgstr "Otrzymano sondę „DPD” MTU (%u bajtów z %u)\n"
-#: dtls.c:631
+#: dtls.c:651
msgid "Initiating IPv6 MTU detection\n"
msgstr "Inicjowanie wykrywania MTU IPv6\n"
-#: dtls.c:646
+#: dtls.c:666
#, c-format
msgid "Sending MTU DPD probe (%u bytes)\n"
msgstr "Wysyłanie sondy „DPD” MTU (%u bajtów)\n"
-#: dtls.c:650
+#: dtls.c:670
#, c-format
msgid "Failed to send DPD request (%d)\n"
msgstr "Wysłanie żądania DPD się nie powiodło (%d)\n"
-#: dtls.c:675
+#: dtls.c:695
#, c-format
msgid "Received MTU DPD probe (%u bytes)\n"
msgstr "Otrzymano sondę „DPD” MTU (%u bajtów)\n"
-#: dtls.c:739
+#: dtls.c:759
#, c-format
msgid "Detected MTU of %d bytes (was %d)\n"
msgstr "Wykryto MTU o rozmiarze %d bajtów (wynosił %d)\n"
-#: dtls.c:742
+#: dtls.c:762
#, c-format
msgid "No change in MTU after detection (was %d)\n"
msgstr "Brak zmian w MTU po wykrywaniu (wynosił %d)\n"
@@ -810,101 +810,101 @@ msgstr ""
"Przyjmowanie pakietu ESP poza kolejnością z sekwencją %u (oczekiwano "
"%)\n"
-#: esp.c:68
+#: esp.c:63
#, c-format
msgid "Parameters for %s ESP: SPI 0x%08x\n"
msgstr "Parametry dla ESP %s: SPI 0x%08x\n"
-#: esp.c:71
+#: esp.c:66
#, c-format
msgid "ESP encryption type %s key 0x%s\n"
msgstr "Szyfrowanie ESP typu %s klucz 0x%s\n"
-#: esp.c:74
+#: esp.c:69
#, c-format
msgid "ESP authentication type %s key 0x%s\n"
msgstr "Uwierzytelnienie ESP typu %s klucz 0x%s\n"
-#: esp.c:133
+#: esp.c:128
msgid "incoming"
msgstr "przychodzące"
-#: esp.c:134
+#: esp.c:129
msgid "outgoing"
msgstr "wychodzące"
-#: esp.c:136 esp.c:153
+#: esp.c:131 esp.c:148
msgid "Send ESP probes\n"
msgstr "Wysłanie próbek ESP\n"
-#: esp.c:180
+#: esp.c:175
#, c-format
msgid "Received ESP packet of %d bytes\n"
msgstr "Otrzymano pakiet ESP o rozmiarze %d bajtów\n"
-#: esp.c:196
+#: esp.c:191
#, c-format
msgid "Consider SPI 0x%x, seq %u against outgoing ESP setup\n"
msgstr "Rozważenie SPI 0x%x, sekwencja %u z wychodzącymi ustawieniami ESP\n"
-#: esp.c:202
+#: esp.c:197
#, c-format
msgid "Received ESP packet with invalid SPI 0x%08x\n"
msgstr "Otrzymano pakiet ESP z nieprawidłowym SPI 0x%08x\n"
-#: esp.c:210
+#: esp.c:205
#, c-format
msgid "Received ESP packet with unrecognised payload type %02x\n"
msgstr "Otrzymano pakiet ESP z nierozpoznanym typem ładunku %02x\n"
-#: esp.c:217
+#: esp.c:212
#, c-format
msgid "Invalid padding length %02x in ESP\n"
msgstr "Nieprawidłowa długość wypełnienia %02x w ESP\n"
-#: esp.c:229
+#: esp.c:224
msgid "Invalid padding bytes in ESP\n"
msgstr "Nieprawidłowe bajty wypełnienia w ESP\n"
-#: esp.c:237
+#: esp.c:232
msgid "ESP session established with server\n"
msgstr "Nawiązano sesję ESP z serwerem\n"
-#: esp.c:248
+#: esp.c:243
msgid "Failed to allocate memory to decrypt ESP packet\n"
msgstr "Przydzielenie pamięci do odszyfrowania pakietu ESP się nie powiodło\n"
-#: esp.c:254
+#: esp.c:249
msgid "LZO decompression of ESP packet failed\n"
msgstr "Dekompresja LZO pakietu ESP się nie powiodła\n"
-#: esp.c:260
+#: esp.c:255
#, c-format
msgid "LZO decompressed %d bytes into %d\n"
msgstr "LZO zdekompresowało %d bajtów do %d\n"
-#: esp.c:274
+#: esp.c:269
msgid "Rekey not implemented for ESP\n"
msgstr "„rekey” nie jest zaimplementowane dla ESP\n"
-#: esp.c:278
+#: esp.c:273
msgid "ESP detected dead peer\n"
msgstr "ESP wykryło martwego partnera\n"
-#: esp.c:285
+#: esp.c:280
msgid "Send ESP probes for DPD\n"
msgstr "Wysłanie próbek ESP dla DPD\n"
-#: esp.c:291
+#: esp.c:286
msgid "Keepalive not implemented for ESP\n"
msgstr "„Keepalive” nie jest zaimplementowane dla ESP\n"
-#: esp.c:314
+#: esp.c:309
#, c-format
msgid "Failed to send ESP packet: %s\n"
msgstr "Wysłanie pakietu ESP się nie powiodło: %s\n"
-#: esp.c:320
+#: esp.c:315
#, c-format
msgid "Sent ESP packet of %d bytes\n"
msgstr "Wysłano pakiet ESP o rozmiarze %d bajtów\n"
@@ -1014,31 +1014,31 @@ msgstr "Zainicjowanie szyfru ESP się nie powiodło: %s\n"
msgid "Failed to initialize ESP HMAC: %s\n"
msgstr "Zainicjowanie „HMAC” ESP się nie powiodło: %s\n"
-#: gnutls-esp.c:116
+#: gnutls-esp.c:117
#, c-format
msgid "Failed to generate random keys for ESP: %s\n"
msgstr "Utworzenie losowych kluczy dla ESP się nie powiodło: %s\n"
-#: gnutls-esp.c:146 gnutls-esp.c:212
+#: gnutls-esp.c:147 gnutls-esp.c:213
#, c-format
msgid "Failed to calculate HMAC for ESP packet: %s\n"
msgstr "Obliczenie HMAC dla pakietu ESP się nie powiodło: %s\n"
-#: gnutls-esp.c:153 openssl-esp.c:191
+#: gnutls-esp.c:154 openssl-esp.c:192
msgid "Received ESP packet with invalid HMAC\n"
msgstr "Otrzymano pakiet ESP z nieprawidłowym HMAC\n"
-#: gnutls-esp.c:169
+#: gnutls-esp.c:170
#, c-format
msgid "Decrypting ESP packet failed: %s\n"
msgstr "Odszyfrowanie pakietu ESP się nie powiodło: %s\n"
-#: gnutls-esp.c:189
+#: gnutls-esp.c:190
#, c-format
msgid "Failed to generate ESP packet IV: %s\n"
msgstr "Utworzenie pakietu „IV” ESP się nie powiodło: %s\n"
-#: gnutls-esp.c:204
+#: gnutls-esp.c:205
#, c-format
msgid "Failed to encrypt ESP packet: %s\n"
msgstr "Zaszyfrowanie pakietu ESP się nie powiodło: %s\n"
@@ -1082,11 +1082,11 @@ msgstr "Wysłanie SSL się nie powiodło: %s\n"
msgid "Could not extract expiration time of certificate\n"
msgstr "Nie można wydobyć czasu wygaśnięcia certyfikatu\n"
-#: gnutls.c:351 openssl.c:1621
+#: gnutls.c:351 openssl.c:1616
msgid "Client certificate has expired at"
msgstr "Certyfikat klienta wygasł w"
-#: gnutls.c:353 openssl.c:1626
+#: gnutls.c:353 openssl.c:1621
msgid "Client certificate expires soon at"
msgstr "Certyfikat klienta niedługo wygaśnie w"
@@ -1390,158 +1390,158 @@ msgstr "Dodawanie wspierającego CA „%s”\n"
msgid "Setting certificate failed: %s\n"
msgstr "Ustawienie certyfikatu się nie powiodło: %s\n"
-#: gnutls.c:2078
+#: gnutls.c:2073
msgid "Server presented no certificate\n"
msgstr "Serwer nie przedstawił żadnego certyfikatu\n"
-#: gnutls.c:2086
+#: gnutls.c:2081
#, c-format
msgid "Error comparing server's cert on rehandshake: %s\n"
msgstr ""
"Błąd podczas porównywania certyfikatu serwera przy ponownym powitaniu: %s\n"
-#: gnutls.c:2091 openssl.c:1544
+#: gnutls.c:2086 openssl.c:1539
msgid "Server presented different cert on rehandshake\n"
msgstr "Serwer przedstawił inny certyfikat podczas ponownego powitania\n"
-#: gnutls.c:2096 openssl.c:1547
+#: gnutls.c:2091 openssl.c:1542
msgid "Server presented identical cert on rehandshake\n"
msgstr "Serwer przedstawił identyczny certyfikat podczas ponownego powitania\n"
-#: gnutls.c:2102
+#: gnutls.c:2097
msgid "Error initialising X509 cert structure\n"
msgstr "Błąd podczas inicjowania struktury certyfikatów X.509\n"
-#: gnutls.c:2108
+#: gnutls.c:2103
msgid "Error importing server's cert\n"
msgstr "Błąd podczas importowania certyfikatu serwera\n"
-#: gnutls.c:2117 main.c:1748
+#: gnutls.c:2112 main.c:1760
msgid "Could not calculate hash of server's certificate\n"
msgstr "Nie można obliczyć sumy kontrolnej certyfikatu serwera\n"
-#: gnutls.c:2122
+#: gnutls.c:2117
msgid "Error checking server cert status\n"
msgstr "Błąd podczas sprawdzania stanu certyfikatu serwera\n"
-#: gnutls.c:2127
+#: gnutls.c:2122
msgid "certificate revoked"
msgstr "unieważniony certyfikat"
-#: gnutls.c:2129
+#: gnutls.c:2124
msgid "signer not found"
msgstr "nie odnaleziono podpisującego"
-#: gnutls.c:2131
+#: gnutls.c:2126
msgid "signer not a CA certificate"
msgstr "podpisujący nie jest certyfikatem CA"
-#: gnutls.c:2133
+#: gnutls.c:2128
msgid "insecure algorithm"
msgstr "niebezpieczny algorytm"
-#: gnutls.c:2135
+#: gnutls.c:2130
msgid "certificate not yet activated"
msgstr "certyfikat nie został jeszcze aktywowany"
-#: gnutls.c:2137
+#: gnutls.c:2132
msgid "certificate expired"
msgstr "certyfikat wygasł"
#. If this is set and no other reason, it apparently means
#. that signature verification failed. Not entirely sure
#. why we don't just set a bit for that too.
-#: gnutls.c:2142
+#: gnutls.c:2137
msgid "signature verification failed"
msgstr "sprawdzenie poprawności podpisu się nie powiodło"
-#: gnutls.c:2191 openssl.c:1428 openssl.c:1580
+#: gnutls.c:2186 openssl.c:1423 openssl.c:1575
msgid "certificate does not match hostname"
msgstr "certyfikat nie pasuje do nazwy komputera"
-#: gnutls.c:2196 openssl.c:1427 openssl.c:1586
+#: gnutls.c:2191 openssl.c:1422 openssl.c:1581
#, c-format
msgid "Server certificate verify failed: %s\n"
msgstr "Sprawdzenie poprawności certyfikatu klienta się nie powiodło: %s\n"
-#: gnutls.c:2270
+#: gnutls.c:2264
msgid "Failed to allocate memory for cafile certs\n"
msgstr "Przydzielenie pamięci dla certyfikatów pliku CA się nie powiodło\n"
-#: gnutls.c:2291
+#: gnutls.c:2285
#, c-format
msgid "Failed to read certs from cafile: %s\n"
msgstr "Odczytanie certyfikatów z pliku CA się nie powiodło: %s\n"
-#: gnutls.c:2307
+#: gnutls.c:2301
#, c-format
msgid "Failed to open CA file '%s': %s\n"
msgstr "Otwarcie pliku CA „%s” się nie powiodło: %s\n"
-#: gnutls.c:2320 openssl.c:1710
+#: gnutls.c:2314 openssl.c:1703
msgid "Loading certificate failed. Aborting.\n"
msgstr "Wczytanie certyfikatu się nie powiodło. Przerywanie.\n"
-#: gnutls.c:2391
+#: gnutls.c:2385
#, c-format
msgid "Failed to set TLS priority string (\"%s\"): %s\n"
msgstr "Ustawienie ciągu priorytetu TLS się nie powiodło („%s”): %s\n"
-#: gnutls.c:2403 openssl.c:1827
+#: gnutls.c:2397 openssl.c:1820
#, c-format
msgid "SSL negotiation with %s\n"
msgstr "Negocjacja SSL z %s\n"
-#: gnutls.c:2450 openssl.c:1853
+#: gnutls.c:2444 openssl.c:1846
msgid "SSL connection cancelled\n"
msgstr "Anulowano połączenie SSL\n"
-#: gnutls.c:2457
+#: gnutls.c:2451
#, c-format
msgid "SSL connection failure: %s\n"
msgstr "Niepowodzenie połączenia SSL: %s\n"
-#: gnutls.c:2466
+#: gnutls.c:2460
#, c-format
msgid "GnuTLS non-fatal return during handshake: %s\n"
msgstr "Niekrytyczny zwrot biblioteki GnuTLS podczas powitania: %s\n"
-#: gnutls.c:2472 openssl.c:1870
+#: gnutls.c:2466 openssl.c:1863
#, c-format
msgid "Connected to HTTPS on %s\n"
msgstr "Połączono z HTTPS na %s\n"
-#: gnutls.c:2475
+#: gnutls.c:2469
#, c-format
msgid "Renegotiated SSL on %s\n"
msgstr "Ponownie negocjowano SSL na %s\n"
-#: gnutls.c:2795 openssl-pkcs11.c:199
+#: gnutls.c:2789 openssl-pkcs11.c:199
#, c-format
msgid "PIN required for %s"
msgstr "Wymagany jest kod PIN dla %s"
-#: gnutls.c:2799 openssl-pkcs11.c:202
+#: gnutls.c:2793 openssl-pkcs11.c:202
msgid "Wrong PIN"
msgstr "Błędny kod PIN"
-#: gnutls.c:2802
+#: gnutls.c:2796
msgid "This is the final try before locking!"
msgstr "To ostatnia próba przed zablokowaniem."
-#: gnutls.c:2804
+#: gnutls.c:2798
msgid "Only a few tries left before locking!"
msgstr "Pozostało tylko kilka prób przed zablokowaniem."
-#: gnutls.c:2809 openssl-pkcs11.c:206
+#: gnutls.c:2803 openssl-pkcs11.c:206
msgid "Enter PIN:"
msgstr "Proszę wprowadzić kod PIN:"
-#: gnutls.c:2940 openssl.c:1998
+#: gnutls.c:2934 openssl.c:1991
msgid "Unsupported OATH HMAC algorithm\n"
msgstr "Nieobsługiwany algorytm HMAC „OATH”\n"
-#: gnutls.c:2949
+#: gnutls.c:2943
#, c-format
msgid "Failed to calculate OATH HMAC: %s\n"
msgstr "Obliczenie HMAC „OATH” się nie powiodło: %s\n"
@@ -1853,7 +1853,7 @@ msgstr ""
"Przydzielenie nowej ścieżki dla względnego przekierowania się nie powiodło: "
"%s\n"
-#: http.c:938 oncp.c:592 oncp.c:629
+#: http.c:938 oncp.c:607 oncp.c:644
#, c-format
msgid "Unexpected %d result from server\n"
msgstr "Oczekiwano %d wyników z serwera\n"
@@ -2007,15 +2007,15 @@ msgstr "Obsługiwane są tylko pośredniki HTTP i SOCKS(5)\n"
#: library.c:112
msgid "Cisco AnyConnect or openconnect"
-msgstr ""
+msgstr "Cisco AnyConnect lub openconnect"
#: library.c:113
msgid "Compatible with Cisco AnyConnect SSL VPN, as well as ocserv"
-msgstr ""
+msgstr "Zgodny z VPN Cisco AnyConnect SSL, a także z ocserv"
#: library.c:128
msgid "Juniper Network Connect"
-msgstr ""
+msgstr "Juniper Network Connect"
#: library.c:129
msgid "Compatible with Juniper Network Connect / Pulse Secure SSL VPN"
@@ -2030,12 +2030,12 @@ msgstr "Nieznany protokół VPN „%s”\n"
msgid "Built against SSL library with no Cisco DTLS support\n"
msgstr "Zbudowano z biblioteką SSL bez obsługi DTLS firmy Cisco\n"
-#: library.c:613
+#: library.c:611
#, c-format
msgid "Failed to parse server URL '%s'\n"
msgstr "Przetworzenie adresu URL serwera „%s” się nie powiodło\n"
-#: library.c:619
+#: library.c:617
msgid "Only https:// permitted for server URL\n"
msgstr "W adresach URL serwera dozwolone jest tylko „https://”\n"
@@ -2044,14 +2044,14 @@ msgstr "W adresach URL serwera dozwolone jest tylko „https://”\n"
msgid "Unknown certificate hash: %s.\n"
msgstr "Nieznana suma kontrolna certyfikatu: %s.\n"
-#: library.c:1017
+#: library.c:1014
#, c-format
msgid ""
"The size of the provided fingerprint is less than the minimum required "
"(%u).\n"
msgstr "Rozmiar podanego odcisku jest mniejszy niż minimalnie wymagany (%u).\n"
-#: library.c:1076
+#: library.c:1075
msgid "No form handler; cannot authenticate.\n"
msgstr "Brak programu obsługującego formularze. Nie można uwierzytelnić.\n"
@@ -2114,15 +2114,17 @@ msgid ""
"WARNING: This binary lacks DTLS and/or ESP support. Performance will be "
"impaired.\n"
msgstr ""
+"OSTRZEŻENIE: ten plik binarny nie obsługuje DTLS lub ESP. Wydajność będzie "
+"zmniejszona.\n"
#: main.c:652
#, c-format
msgid "Supported protocols:"
-msgstr ""
+msgstr "Obsługiwane protokoły:"
#: main.c:654 main.c:670
msgid " (default)"
-msgstr ""
+msgstr " (domyślny)"
#: main.c:667
#, c-format
@@ -2130,6 +2132,8 @@ msgid ""
"\n"
" Set VPN protocol:\n"
msgstr ""
+"\n"
+" Ustawienie protokołu VPN:\n"
#: main.c:708
msgid "fgets (stdin)"
@@ -2161,6 +2165,8 @@ msgid ""
"Open client for multiple VPN protocols, version %s\n"
"\n"
msgstr ""
+"Otwarty klient dla wielu protokołów VPN, wersja %s\n"
+"\n"
#: main.c:790
msgid "Read options from config file"
@@ -2436,37 +2442,42 @@ msgstr "Ustawia lokalny port dla datagramów DTLS"
msgid "Failed to allocate string\n"
msgstr "Przydzielenie ciągu się nie powiodło\n"
-#: main.c:953
+#: main.c:963
#, c-format
msgid "Failed to get line from config file: %s\n"
msgstr "Uzyskanie wiersza z pliku konfiguracji się nie powiodło: %s\n"
-#: main.c:993
+#: main.c:1003
#, c-format
msgid "Unrecognised option at line %d: '%s'\n"
msgstr "Nierozpoznana opcja w wierszu %d: „%s”\n"
-#: main.c:1003
+#: main.c:1013
#, c-format
msgid "Option '%s' does not take an argument at line %d\n"
msgstr "Opcja „%s” nie przyjmuje parametru w wierszu %d\n"
-#: main.c:1007
+#: main.c:1017
#, c-format
msgid "Option '%s' requires an argument at line %d\n"
msgstr "Opcja „%s” wymaga parametru w wierszu %d\n"
-#: main.c:1032
+#: main.c:1042
#, c-format
msgid "Invalid user \"%s\": %s\n"
msgstr "Nieprawidłowy użytkownik „%s”: %s\n"
-#: main.c:1042
+#: main.c:1052
#, c-format
msgid "Invalid user ID \"%d\": %s\n"
msgstr "Nieprawidłowy identyfikator użytkownika „%d”: %s\n"
-#: main.c:1094
+#: main.c:1096
+#, c-format
+msgid "WARNING: Cannot set locale: %s\n"
+msgstr ""
+
+#: main.c:1106
#, c-format
msgid ""
"WARNING: This version of openconnect was built without iconv\n"
@@ -2477,7 +2488,7 @@ msgstr ""
" a używany jest przestarzały zestaw znaków „%s”.\n"
" Program może się dziwnie zachowywać.\n"
-#: main.c:1101
+#: main.c:1113
#, c-format
msgid ""
"WARNING: This version of openconnect is %s but\n"
@@ -2486,42 +2497,42 @@ msgstr ""
"OSTRZEŻENIE: ta wersja OpenConnect to %s, ale\n"
" biblioteki libopenconnect to %s\n"
-#: main.c:1111
+#: main.c:1123
#, c-format
msgid "Failed to allocate vpninfo structure\n"
msgstr "Przydzielenie struktury vpninfo się nie powiodło\n"
-#: main.c:1166
+#: main.c:1178
#, c-format
msgid "Cannot use 'config' option inside config file\n"
msgstr "Nie można użyć opcji „config” wewnątrz pliku konfiguracji\n"
-#: main.c:1174
+#: main.c:1186
#, c-format
msgid "Cannot open config file '%s': %s\n"
msgstr "Nie można otworzyć pliku konfiguracji „%s”: %s\n"
-#: main.c:1190
+#: main.c:1202
#, c-format
msgid "Invalid compression mode '%s'\n"
msgstr "Nieprawidłowy tryb kompresji \"%s\"\n"
-#: main.c:1211
+#: main.c:1223
#, c-format
msgid "Missing colon in resolve option\n"
msgstr "Brak dwukropka w opcji „resolve”\n"
-#: main.c:1216
+#: main.c:1228
#, c-format
msgid "Failed to allocate memory\n"
msgstr "Przydzielenie pamięci się nie powiodło\n"
-#: main.c:1296 main.c:1305
+#: main.c:1308 main.c:1317
#, c-format
msgid "MTU %d too small\n"
msgstr "MTU %d jest za małe\n"
-#: main.c:1335
+#: main.c:1347
#, c-format
msgid ""
"Disabling all HTTP connection re-use due to --no-http-keepalive option.\n"
@@ -2532,7 +2543,7 @@ msgstr ""
"Jeśli to pomoże, to prosimy to zgłosić na adres (w języku angielskim).\n"
-#: main.c:1341
+#: main.c:1353
#, c-format
msgid ""
"The --no-cert-check option was insecure and has been removed.\n"
@@ -2542,129 +2553,129 @@ msgstr ""
"Należy naprawić certyfikat serwera lub użyć opcji --servercert, aby mu "
"zaufać.\n"
-#: main.c:1358
+#: main.c:1370
#, c-format
msgid "Queue length zero not permitted; using 1\n"
msgstr "Zerowa długość kolejki jest niedozwolona. Używanie 1\n"
-#: main.c:1372
+#: main.c:1384
#, c-format
msgid "OpenConnect version %s\n"
msgstr "OpenConnect wersja %s\n"
-#: main.c:1406
+#: main.c:1418
#, c-format
msgid "Invalid software token mode \"%s\"\n"
msgstr "Nieprawidłowy tryb tokena programowego „%s”\n"
-#: main.c:1416
+#: main.c:1428
#, c-format
msgid "Invalid OS identity \"%s\"\n"
msgstr "Nieprawidłowa tożsamość systemu operacyjnego „%s”\n"
-#: main.c:1449
+#: main.c:1461
#, c-format
msgid "Too many arguments on command line\n"
msgstr "Za dużo parametrów w wierszu poleceń\n"
-#: main.c:1452
+#: main.c:1464
#, c-format
msgid "No server specified\n"
msgstr "Nie podano serwera\n"
-#: main.c:1468
+#: main.c:1480
#, c-format
msgid "This version of openconnect was built without libproxy support\n"
msgstr ""
"Ta wersja OpenConnect została zbudowana bez obsługi biblioteki libproxy\n"
-#: main.c:1497
+#: main.c:1509
#, c-format
msgid "Error opening cmd pipe\n"
msgstr "Błąd podczas otwierania potoku cmd\n"
-#: main.c:1530
+#: main.c:1542
#, c-format
msgid "Failed to obtain WebVPN cookie\n"
msgstr "Uzyskanie ciasteczka WebVPN się nie powiodło\n"
-#: main.c:1551
+#: main.c:1563
#, c-format
msgid "Creating SSL connection failed\n"
msgstr "Utworzenie połączenia SSL się nie powiodło\n"
-#: main.c:1567
+#: main.c:1579
#, c-format
msgid "Set up DTLS failed; using SSL instead\n"
msgstr "Ustawienie DTLS się nie powiodło. Używanie SSL zamiast tego\n"
-#: main.c:1588
+#: main.c:1600
#, c-format
msgid "Connected as %s%s%s, using %s%s\n"
msgstr "Połączono jako %s%s%s, używając %s%s\n"
-#: main.c:1597
+#: main.c:1609
msgid "No --script argument provided; DNS and routing are not configured\n"
msgstr ""
"Nie podano parametru --script. DNS i trasowanie nie są skonfigurowane\n"
-#: main.c:1599
+#: main.c:1611
msgid "See http://www.infradead.org/openconnect/vpnc-script.html\n"
msgstr ""
"Proszę zobaczyć http://www.infradead.org/openconnect/vpnc-script.html\n"
-#: main.c:1612
+#: main.c:1624
#, c-format
msgid "Failed to open '%s' for write: %s\n"
msgstr "Otwarcie „%s” do zapisu się nie powiodło: %s\n"
-#: main.c:1624
+#: main.c:1636
#, c-format
msgid "Continuing in background; pid %d\n"
msgstr "Kontynuowanie w tle. PID %d\n"
-#: main.c:1641
+#: main.c:1653
msgid "User requested reconnect\n"
msgstr "Użytkownik zażądał ponownego połączenia\n"
-#: main.c:1649
+#: main.c:1661
msgid "Cookie was rejected on reconnection; exiting.\n"
msgstr ""
"Ciasteczko zostało odrzucone podczas łączenia ponownie. Kończenie "
"działania.\n"
-#: main.c:1653
+#: main.c:1665
msgid "Session terminated by server; exiting.\n"
msgstr "Sesja została zakończona przez serwer. Kończenie działania.\n"
-#: main.c:1657
+#: main.c:1669
msgid "User cancelled (SIGINT); exiting.\n"
msgstr "Anulowane przez użytkownika (SIGINT). Kończenie działania.\n"
-#: main.c:1661
+#: main.c:1673
msgid "User detached from session (SIGHUP); exiting.\n"
msgstr "Użytkownik odłączył od sesji (SIGHUP). Kończenie działania.\n"
-#: main.c:1665
+#: main.c:1677
msgid "Unknown error; exiting.\n"
msgstr "Nieznany błąd; kończenie działania.\n"
-#: main.c:1684
+#: main.c:1696
#, c-format
msgid "Failed to open %s for write: %s\n"
msgstr "Otwarcie %s do zapisu się nie powiodło: %s\n"
-#: main.c:1692
+#: main.c:1704
#, c-format
msgid "Failed to write config to %s: %s\n"
msgstr "Zapisanie konfiguracji do %s się nie powiodło: %s\n"
-#: main.c:1751
+#: main.c:1763
#, c-format
msgid "Server SSL certificate didn't match: %s\n"
msgstr "Certyfikat SSL serwera się nie zgadza: %s\n"
-#: main.c:1770
+#: main.c:1782
#, c-format
msgid ""
"\n"
@@ -2675,103 +2686,103 @@ msgstr ""
"Sprawdzenie poprawność certyfikatu z serwera VPN „%s” się nie powiodło.\n"
"Przyczyna: %s\n"
-#: main.c:1773
+#: main.c:1785
#, c-format
msgid ""
"To trust this server in future, perhaps add this to your command line:\n"
msgstr ""
"Aby zaufać temu serwerowi w przyszłości, można dodać to do wiersza poleceń:\n"
-#: main.c:1774
+#: main.c:1786
#, c-format
msgid " --servercert %s\n"
msgstr " --servercert %s\n"
-#: main.c:1779
+#: main.c:1791
#, c-format
msgid "Enter '%s' to accept, '%s' to abort; anything else to view: "
msgstr ""
"Wpisanie \"%s\" zaakceptuje, \"%s\" przerwie, inne wartości spowodują "
"wyświetlenie: "
-#: main.c:1780 main.c:1798
+#: main.c:1792 main.c:1810
msgid "no"
msgstr "nie"
-#: main.c:1780 main.c:1786
+#: main.c:1792 main.c:1798
msgid "yes"
msgstr "tak"
-#: main.c:1807
+#: main.c:1819
#, c-format
msgid "Server key hash: %s\n"
msgstr "Suma kontrolna klucza serwera: %s\n"
-#: main.c:1841
+#: main.c:1853
#, c-format
msgid "Auth choice \"%s\" matches multiple options\n"
msgstr "Wybór uwierzytelnienia „%s” pasuje do wielu opcji\n"
-#: main.c:1844
+#: main.c:1856
#, c-format
msgid "Auth choice \"%s\" not available\n"
msgstr "Wybór uwierzytelnienia „%s” jest niedostępny\n"
-#: main.c:1865
+#: main.c:1877
msgid "User input required in non-interactive mode\n"
msgstr "Wymagane jest działanie użytkownika w trybie nieinteraktywnym\n"
-#: main.c:2042
+#: main.c:2054
#, c-format
msgid "Failed to open token file for write: %s\n"
msgstr "Otwarcie pliku token do zapisu się nie powiodło: %s\n"
-#: main.c:2050
+#: main.c:2062
#, c-format
msgid "Failed to write token: %s\n"
msgstr "Zapisanie tokenu się nie powiodło: %s\n"
-#: main.c:2096 main.c:2117
+#: main.c:2108 main.c:2129
#, c-format
msgid "Soft token string is invalid\n"
msgstr "Ciąg tokena programowego jest nieprawidłowy\n"
-#: main.c:2099
+#: main.c:2111
#, c-format
msgid "Can't open ~/.stokenrc file\n"
msgstr "Nie można otworzyć pliku ~/.stokenrc\n"
-#: main.c:2102
+#: main.c:2114
#, c-format
msgid "OpenConnect was not built with libstoken support\n"
msgstr "OpenConnect zostało zbudowane bez obsługi biblioteki libstoken\n"
-#: main.c:2105
+#: main.c:2117
#, c-format
msgid "General failure in libstoken\n"
msgstr "Ogólne niepowodzenie w bibliotece libstoken\n"
-#: main.c:2120
+#: main.c:2132
#, c-format
msgid "OpenConnect was not built with liboath support\n"
msgstr "OpenConnect zostało zbudowane bez obsługi biblioteki liboath\n"
-#: main.c:2123
+#: main.c:2135
#, c-format
msgid "General failure in liboath\n"
msgstr "Ogólne niepowodzenie w bibliotece liboath\n"
-#: main.c:2134
+#: main.c:2146
#, c-format
msgid "Yubikey token not found\n"
msgstr "Nie odnaleziono tokena Yubikey\n"
-#: main.c:2137
+#: main.c:2149
#, c-format
msgid "OpenConnect was not built with Yubikey support\n"
msgstr "OpenConnect zostało zbudowane bez obsługi Yubikey\n"
-#: main.c:2140
+#: main.c:2152
#, c-format
msgid "General Yubikey failure: %s\n"
msgstr "Ogólne niepowodzenie Yubikey: %s\n"
@@ -2922,216 +2933,216 @@ msgstr "Otrzymano trasę wykluczania „split” %s\n"
msgid "Received WINS server %s\n"
msgstr "Otrzymano serwer WINS %s\n"
-#: oncp.c:311
+#: oncp.c:313
#, c-format
msgid "ESP encryption: 0x%02x (%s)\n"
msgstr "Szyfrowanie ESP: 0x%02x (%s)\n"
-#: oncp.c:328
+#: oncp.c:332
#, c-format
msgid "ESP HMAC: 0x%02x (%s)\n"
msgstr "HMAC ESP: 0x%02x (%s)\n"
-#: oncp.c:338
+#: oncp.c:342
#, c-format
msgid "ESP compression: %d\n"
msgstr "Kompresja ESP: %d\n"
-#: oncp.c:346
+#: oncp.c:350
#, c-format
msgid "ESP port: %d\n"
msgstr "Port ESP: %d\n"
-#: oncp.c:353
+#: oncp.c:357
#, c-format
msgid "ESP key lifetime: %u bytes\n"
msgstr "Czas życia klucza ESP: %u bajtów\n"
-#: oncp.c:361
+#: oncp.c:365
#, c-format
msgid "ESP key lifetime: %u seconds\n"
msgstr "Czas życia klucza ESP: %u sekund\n"
-#: oncp.c:369
+#: oncp.c:373
#, c-format
msgid "ESP to SSL fallback: %u seconds\n"
msgstr "Przechodzenie z ESP do SSL: %u sekund\n"
-#: oncp.c:377
+#: oncp.c:381
#, c-format
msgid "ESP replay protection: %d\n"
msgstr "Ochrona powtarzania ESP: %d\n"
-#: oncp.c:385
+#: oncp.c:389
#, c-format
msgid "ESP SPI (outbound): %x\n"
msgstr "„SPI” ESP (wychodzące): %x\n"
-#: oncp.c:393
+#: oncp.c:398
#, c-format
msgid "%d bytes of ESP secrets\n"
msgstr "%d bajtów haseł ESP\n"
-#: oncp.c:405
+#: oncp.c:410
#, c-format
msgid "Unknown TLV group %d attr %d len %d:%s\n"
msgstr "Nieznana grupa TLV %d attr %d len %d:%s\n"
-#: oncp.c:483
+#: oncp.c:488
msgid "Failed to parse KMP header\n"
msgstr "Przetworzenie nagłówka KMP się nie powiodło\n"
-#: oncp.c:499
+#: oncp.c:505
msgid "Failed to parse KMP message\n"
msgstr "Przetworzenie komunikatu KMP się nie powiodło\n"
-#: oncp.c:505
+#: oncp.c:511
#, c-format
msgid "Got KMP message %d of size %d\n"
msgstr "Otrzymano komunikat KMP %d o rozmiarze %d\n"
-#: oncp.c:521
+#: oncp.c:527
#, c-format
msgid "Received non-ESP TLVs (group %d) in ESP negotiation KMP\n"
msgstr "Otrzymano TLV niebędące ESP (grupa %d) w KMP negocjacji ESP\n"
-#: oncp.c:570 oncp.c:615 oncp.c:647 oncp.c:773
+#: oncp.c:585 oncp.c:630 oncp.c:662 oncp.c:788
msgid "Error creating oNCP negotiation request\n"
msgstr "Błąd podczas tworzenia żądania negocjacji oNCP\n"
-#: oncp.c:656 oncp.c:807
+#: oncp.c:671 oncp.c:823
msgid "Short write in oNCP negotiation\n"
msgstr "Krótki zapis w negocjacji oNCP\n"
-#: oncp.c:668 oncp.c:692
+#: oncp.c:683 oncp.c:707
#, c-format
msgid "Read %d bytes of SSL record\n"
msgstr "Odczyt %d bajtów wpisu SSL\n"
-#: oncp.c:672
+#: oncp.c:687
#, c-format
msgid "Unexpected response of size %d after hostname packet\n"
msgstr "Oczekiwano odpowiedzi o rozmiarze %d po pakiecie nazwy komputera\n"
-#: oncp.c:679
+#: oncp.c:694
#, c-format
msgid "Server response to hostname packet is error 0x%02x\n"
msgstr "Odpowiedź serwera na pakiet nazwy komputera to błąd 0x%02x\n"
-#: oncp.c:696
+#: oncp.c:711
msgid "Invalid packet waiting for KMP 301\n"
msgstr "Nieprawidłowy pakiet oczekujący na KMP 301\n"
-#: oncp.c:709
+#: oncp.c:724
#, c-format
msgid "Expected KMP message 301 from server but got %d\n"
msgstr "Oczekiwano komunikatu „301” KMP z serwera, ale otrzymano %d\n"
-#: oncp.c:718
+#: oncp.c:733
#, c-format
msgid "KMP message 301 from server too large (%d bytes)\n"
msgstr "Komunikat „301” KMP z serwera jest za duży (%d bajtów)\n"
-#: oncp.c:724
+#: oncp.c:739
#, c-format
msgid "Got KMP message 301 of length %d\n"
msgstr "Otrzymano komunikat „301” KMP o długości %d\n"
-#: oncp.c:731
+#: oncp.c:746
msgid "Failed to read continuation record length\n"
msgstr "Odczytanie długości wpisu kontynuacji się nie powiodło\n"
-#: oncp.c:737
+#: oncp.c:752
#, c-format
msgid "Record of additional %d bytes too large; would make %d\n"
msgstr "Wpis jest za dużo o dodatkowe %d bajtów. Byłby %d\n"
-#: oncp.c:746
+#: oncp.c:761
#, c-format
msgid "Failed to read continuation record of length %d\n"
msgstr "Odczytanie wpisu kontynuacji o długości %d się nie powiodło\n"
-#: oncp.c:752
+#: oncp.c:767
#, c-format
msgid "Read additional %d bytes of KMP 301 message\n"
msgstr "Odczyt dodatkowych %d bajtów komunikatu „301” KMP\n"
-#: oncp.c:792
+#: oncp.c:808
msgid "Error negotiating ESP keys\n"
msgstr "Błąd podczas negocjowania kluczy ESP\n"
-#: oncp.c:852
+#: oncp.c:869
msgid "new incoming"
msgstr "nowe przychodzące"
-#: oncp.c:853
+#: oncp.c:870
msgid "new outgoing"
msgstr "nowe wychodzące"
-#: oncp.c:858
+#: oncp.c:875
msgid "Ignoring ESP keys since ESP support not available in this build\n"
msgstr "Ignorowanie kluczy ESP, ponieważ obsługa ESP jest niedostępna\n"
-#: oncp.c:878
+#: oncp.c:895
msgid "Read only 1 byte of oNCP length field\n"
msgstr "Odczyt tylko 1 bajtu pola długości oNCP\n"
-#: oncp.c:887
+#: oncp.c:904
msgid "Server terminated connection (session expired)\n"
msgstr "Serwer zakończył połączenie (sesja wygasła)\n"
-#: oncp.c:891
+#: oncp.c:908
#, c-format
msgid "Server terminated connection (reason: %d)\n"
msgstr "Serwer zakończył połączenie (przyczyna: %d)\n"
-#: oncp.c:897
+#: oncp.c:914
msgid "Server sent zero-length oNCP record\n"
msgstr "Serwer wysłał wpis oNCP o zerowej długości\n"
-#: oncp.c:992
+#: oncp.c:1009
#, c-format
msgid "Incoming KMP message %d of size %d (got %d)\n"
msgstr "Przychodzący komunikat KMP %d o rozmiarze %d (otrzymano %d)\n"
-#: oncp.c:995
+#: oncp.c:1012
#, c-format
msgid "Continuing to process KMP message %d now size %d (got %d)\n"
msgstr ""
"Kontynuowanie przetwarzania komunikatu KMP %d o obecnym rozmiarze %d "
"(otrzymano %d)\n"
-#: oncp.c:1014
+#: oncp.c:1031
msgid "Unrecognised data packet\n"
msgstr "Nierozpoznany pakiet danych\n"
-#: oncp.c:1076
+#: oncp.c:1093
#, c-format
msgid "Unknown KMP message %d of size %d:\n"
msgstr "Nieznany komunikat KMP %d o rozmiarze %d:\n"
-#: oncp.c:1081
+#: oncp.c:1098
#, c-format
msgid ".... + %d more bytes unreceived\n"
msgstr "… + %d więcej bajtów nie zostało otrzymanych\n"
-#: oncp.c:1096
+#: oncp.c:1113
msgid "Packet outgoing:\n"
msgstr "Wychodzący pakiet:\n"
-#: oncp.c:1160
+#: oncp.c:1177
msgid "Sent ESP enable control packet\n"
msgstr "Wysłano pakiet kontroli włączenia ESP\n"
-#: oncp.c:1282
+#: oncp.c:1299
msgid "Logout failed.\n"
-msgstr ""
+msgstr "Wylogowanie się nie powiodło.\n"
-#: oncp.c:1284
+#: oncp.c:1301
msgid "Logout successful.\n"
-msgstr ""
+msgstr "Pomyślnie wylogowano.\n"
-#: openconnect-internal.h:1071 openconnect-internal.h:1079
+#: openconnect-internal.h:1084 openconnect-internal.h:1092
#, c-format
msgid "ERROR: %s() called with invalid UTF-8 for '%s' argument\n"
msgstr ""
@@ -3234,28 +3245,28 @@ msgstr "Zainicjowanie szyfru ESP się nie powiodło:\n"
msgid "Failed to initialize ESP HMAC\n"
msgstr "Zainicjowanie „HMAC” ESP się nie powiodło\n"
-#: openssl-esp.c:156
+#: openssl-esp.c:157
msgid "Failed to generate random keys for ESP:\n"
msgstr "Utworzenie losowych kluczy dla ESP się nie powiodło:\n"
-#: openssl-esp.c:206
+#: openssl-esp.c:207
msgid "Failed to set up decryption context for ESP packet:\n"
msgstr ""
"Ustawienie kontekstu odszyfrowywania dla pakietu ESP się nie powiodło:\n"
-#: openssl-esp.c:214
+#: openssl-esp.c:215
msgid "Failed to decrypt ESP packet:\n"
msgstr "Odszyfrowanie pakietu ESP się nie powiodło:\n"
-#: openssl-esp.c:234
+#: openssl-esp.c:235
msgid "Failed to generate random IV for ESP packet:\n"
msgstr "Utworzenie losowego „IV” dla pakietu ESP się nie powiodło:\n"
-#: openssl-esp.c:248
+#: openssl-esp.c:249
msgid "Failed to set up encryption context for ESP packet:\n"
msgstr "Ustawienie kontekstu szyfrowania dla pakietu ESP się nie powiodło:\n"
-#: openssl-esp.c:257
+#: openssl-esp.c:258
msgid "Failed to encrypt ESP packet:\n"
msgstr "Zaszyfrowanie pakietu ESP się nie powiodło:\n"
@@ -3509,105 +3520,105 @@ msgstr "Konwertowanie PKCS#8 na EVP_PKEY biblioteki OpenSSL się nie powiodło\n
msgid "Failed to identify private key type in '%s'\n"
msgstr "Zidentyfikowanie typu klucza prywatnego w „%s” się nie powiodło\n"
-#: openssl.c:1232
+#: openssl.c:1227
#, c-format
msgid "Matched DNS altname '%s'\n"
msgstr "Pasujące „altname” DNS „%s”\n"
-#: openssl.c:1239
+#: openssl.c:1234
#, c-format
msgid "No match for altname '%s'\n"
msgstr "Nic nie pasuje do „altname” „%s”\n"
-#: openssl.c:1253
+#: openssl.c:1248
#, c-format
msgid "Certificate has GEN_IPADD altname with bogus length %d\n"
msgstr "Certyfikat posiada „altname” GEN_IPADD z fałszywą długością %d\n"
-#: openssl.c:1264 openssl.c:1410
+#: openssl.c:1259 openssl.c:1405
#, c-format
msgid "Matched %s address '%s'\n"
msgstr "Pasujący adres %s „%s”\n"
-#: openssl.c:1271
+#: openssl.c:1266
#, c-format
msgid "No match for %s address '%s'\n"
msgstr "Nic nie pasuje do adresu %s „%s”\n"
-#: openssl.c:1313
+#: openssl.c:1308
#, c-format
msgid "URI '%s' has non-empty path; ignoring\n"
msgstr "Adres URI „%s” posiada niepustą ścieżkę. Ignorowanie\n"
-#: openssl.c:1318
+#: openssl.c:1313
#, c-format
msgid "Matched URI '%s'\n"
msgstr "Pasujący adres URI „%s”\n"
-#: openssl.c:1329
+#: openssl.c:1324
#, c-format
msgid "No match for URI '%s'\n"
msgstr "Nic nie pasuje do adresu URI „%s”\n"
-#: openssl.c:1344
+#: openssl.c:1339
#, c-format
msgid "No altname in peer cert matched '%s'\n"
msgstr "Żadne „altname” w certyfikacie partnera nie pasuje do „%s”\n"
-#: openssl.c:1352
+#: openssl.c:1347
msgid "No subject name in peer cert!\n"
msgstr "Brak nazwy tematu w certyfikacie partnera\n"
-#: openssl.c:1372
+#: openssl.c:1367
msgid "Failed to parse subject name in peer cert\n"
msgstr "Przetworzenie nazwy tematu w certyfikacie partnera się nie powiodło\n"
-#: openssl.c:1379
+#: openssl.c:1374
#, c-format
msgid "Peer cert subject mismatch ('%s' != '%s')\n"
msgstr "Niedopasowanie tematu certyfikatu partnera („%s” != „%s”)\n"
-#: openssl.c:1384 openssl.c:1418
+#: openssl.c:1379 openssl.c:1413
#, c-format
msgid "Matched peer certificate subject name '%s'\n"
msgstr "Pasująca nazwa tematu certyfikatu partnera „%s”\n"
-#: openssl.c:1480
+#: openssl.c:1475
#, c-format
msgid "Extra cert from cafile: '%s'\n"
msgstr "Dodatkowy certyfikat z pliku CA: „%s”\n"
-#: openssl.c:1618
+#: openssl.c:1613
msgid "Error in client cert notAfter field\n"
msgstr "Błąd w polu „notAfter” certyfikatu klienta\n"
-#: openssl.c:1631
+#: openssl.c:1626
msgid ""
msgstr ""
-#: openssl.c:1686
+#: openssl.c:1679
msgid "Create TLSv1 CTX failed\n"
msgstr "Utworzenie „CTX” TLSv1 się nie powiodło\n"
-#: openssl.c:1705
+#: openssl.c:1698
msgid "SSL certificate and key do not match\n"
msgstr "Certyfikat SSL i klucz nie pasują\n"
-#: openssl.c:1750
+#: openssl.c:1743
#, c-format
msgid "Failed to read certs from CA file '%s'\n"
msgstr "Odczytanie certyfikatów z pliku CA „%s” się nie powiodło\n"
-#: openssl.c:1783
+#: openssl.c:1776
#, c-format
msgid "Failed to open CA file '%s'\n"
msgstr "Otwarcie pliku CA „%s” się nie powiodło\n"
-#: openssl.c:1843
+#: openssl.c:1836
msgid "SSL connection failure\n"
msgstr "Niepowodzenie połączenia SSL\n"
-#: openssl.c:2004
+#: openssl.c:1997
msgid "Failed to calculate OATH HMAC\n"
msgstr "Obliczenie „HMAC” OATH się nie powiodło\n"
@@ -4345,16 +4356,16 @@ msgid "Unrecognised response from Yubikey when generating tokencode\n"
msgstr "Nierozpoznana odpowiedź z Yubikey podczas tworzenia kodu tokena\n"
#~ msgid ""
-#~ "Open client for Cisco AnyConnect VPN, version %s\n"
#~ "\n"
+#~ "WARNING: No DTLS support in this binary. Performance will be impaired.\n"
#~ msgstr ""
-#~ "Otwarty klient dla Cisco AnyConnect VPN, wersja %s\n"
#~ "\n"
+#~ "OSTRZEŻENIE: ten plik binarny nie obsługuje DTLS. Wydajność będzie "
+#~ "zmniejszona.\n"
#~ msgid ""
+#~ "Open client for Cisco AnyConnect VPN, version %s\n"
#~ "\n"
-#~ "WARNING: No DTLS support in this binary. Performance will be impaired.\n"
#~ msgstr ""
+#~ "Otwarty klient dla Cisco AnyConnect VPN, wersja %s\n"
#~ "\n"
-#~ "OSTRZEŻENIE: ten plik binarny nie obsługuje DTLS. Wydajność będzie "
-#~ "zmniejszona.\n"
From 0b103e8d4c7e7fb3c00e62c2fb1cf28c57e25faf Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Wed, 31 May 2017 12:43:25 +0100
Subject: [PATCH 009/131] Add glibc-langpack-cs to gitlab CI environment
We need it to make the charset testing work.
Signed-off-by: David Woodhouse
---
.gitlab-ci.yml | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 90f7536a..db2d4dbd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,7 +10,7 @@ CentOS7/GnuTLS:
'pkgconfig(libproxy-1.0)' 'pkgconfig(liboath)' 'pkgconfig(stoken)'
ocserv softhsm 'pkgconfig(uid_wrapper)' 'pkgconfig(socket_wrapper)'
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
- java-devel-openjdk
+ java-devel-openjdk glibc-langpack-cs
- ./autogen.sh
- ./configure --with-java CFLAGS=-g
- make -j4
@@ -36,7 +36,7 @@ CentOS7/OpenSSL:
'pkgconfig(libproxy-1.0)' 'pkgconfig(liboath)' 'pkgconfig(stoken)'
ocserv softhsm 'pkgconfig(uid_wrapper)' 'pkgconfig(socket_wrapper)'
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
- java-devel-openjdk 'pkgconfig(libp11)'
+ java-devel-openjdk 'pkgconfig(libp11)' glibc-langpack-cs
- ./autogen.sh
- ./configure --without-gnutls --with-openssl --with-java --without-openssl-version-check --enable-dtls-xfail --disable-dsa-tests CFLAGS=-g
- make -j4
@@ -62,6 +62,7 @@ CentOS6/OpenSSL:
ocserv softhsm 'pkgconfig(uid_wrapper)' 'pkgconfig(socket_wrapper)'
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
java-devel-openjdk vpnc 'pkgconfig(libp11)' 'pkgconfig(p11-kit-1)'
+ glibc-langpack-cs
- ./autogen.sh
- ./configure --with-java --without-openssl-version-check --enable-dtls-xfail CFLAGS=-g
- make -j4
@@ -84,7 +85,7 @@ Fedora/GnuTLS:
'pkgconfig(libproxy-1.0)' 'pkgconfig(liboath)' 'pkgconfig(stoken)'
ocserv softhsm 'pkgconfig(uid_wrapper)' 'pkgconfig(socket_wrapper)'
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
- java-devel-openjdk
+ java-devel-openjdk glibc-langpack-cs
- ./autogen.sh
- ./configure --with-java CFLAGS=-g
- make -j4
@@ -107,7 +108,7 @@ Fedora/GnuTLS/clang:
'pkgconfig(libproxy-1.0)' 'pkgconfig(liboath)' 'pkgconfig(stoken)'
ocserv softhsm 'pkgconfig(uid_wrapper)' 'pkgconfig(socket_wrapper)'
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
- java-devel-openjdk clang
+ java-devel-openjdk clang glibc-langpack-cs
- ./autogen.sh
- ./configure --with-java CC=clang CFLAGS=-g
- make -j4
@@ -130,7 +131,7 @@ Fedora/OpenSSL:
'pkgconfig(libproxy-1.0)' 'pkgconfig(liboath)' 'pkgconfig(stoken)'
ocserv softhsm 'pkgconfig(uid_wrapper)' 'pkgconfig(socket_wrapper)'
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
- java-devel-openjdk 'pkgconfig(libp11)'
+ java-devel-openjdk 'pkgconfig(libp11)' glibc-langpack-cs
- dnf --enablerepo=updates-testing update -y libp11\* gnutls
- ./autogen.sh
- ./configure --without-gnutls --with-openssl --without-openssl-version-check --disable-dsa-tests CFLAGS=-g
@@ -154,7 +155,7 @@ Fedora/OpenSSL/clang:
'pkgconfig(libproxy-1.0)' 'pkgconfig(liboath)' 'pkgconfig(stoken)'
ocserv softhsm 'pkgconfig(uid_wrapper)' 'pkgconfig(socket_wrapper)'
vpnc-script 'pkgconfig(libpskc)' 'pkgconfig(libpcsclite)'
- java-devel-openjdk 'pkgconfig(libp11)' clang
+ java-devel-openjdk 'pkgconfig(libp11)' clang glibc-langpack-cs
- dnf --enablerepo=updates-testing update -y libp11\* gnutls
- ./autogen.sh
- ./configure CC=clang --without-gnutls --with-openssl --without-openssl-version-check --disable-dsa-tests CFLAGS=-g
From d298a8b6ceb2dd57b1e1d032122329704f05ef4f Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 10:42:41 +0100
Subject: [PATCH 010/131] Allow reading stdin on Windows instead of forcibly
opening console
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This was filed against Ľubomír Carik's github project for openconnect-gui;
https://github.com/openconnect/openconnect-gui/issues/101
It isn't perfect, as the ANSI code page on Windows can be different
from the OEM code page used for the console, so fgetws() is likely
to do the wrong thing — which is why we force-opened the console and
used ReadConsoleW() in the first place. But perfect is the enemy of
good in this case, as reading from something other than stdin is
*definitely* wrong. We still use ReadConsoleW() when stdin does happen
to be the console, so that part shouldn't regress.
I hate Windows...
Signed-off-by: David Woodhouse
---
main.c | 55 +++++++++++++++++++++--------------------------
www/changelog.xml | 1 +
2 files changed, 25 insertions(+), 31 deletions(-)
diff --git a/main.c b/main.c
index a18bfd22..935147f4 100644
--- a/main.c
+++ b/main.c
@@ -367,36 +367,37 @@ static char *convert_arg_to_utf8(char **argv, char *arg)
static void read_stdin(char **string, int hidden, int allow_fail)
{
CONSOLE_READCONSOLE_CONTROL rcc = { sizeof(rcc), 0, 13, 0 };
- HANDLE conh, stdinh = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE stdinh = GetStdHandle(STD_INPUT_HANDLE);
DWORD cmode, nr_read;
wchar_t wbuf[1024];
char *buf;
- conh = stdinh;
- if (!GetConsoleMode(conh, &cmode)) {
- /* STDIN is not a console? Try opening it explicitly */
- conh = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ,
- 0,OPEN_EXISTING, 0, 0);
- if (conh == INVALID_HANDLE_VALUE || !GetConsoleMode(conh, &cmode)) {
+ if (GetConsoleMode(stdinh, &cmode)) {
+ if (hidden)
+ SetConsoleMode(stdinh, cmode & (~ENABLE_ECHO_INPUT));
+
+ if (!ReadConsoleW(stdinh, wbuf, sizeof(wbuf)/2, &nr_read, &rcc)) {
char *errstr = openconnect__win32_strerror(GetLastError());
- fprintf(stderr, _("Failed to open CONIN$: %s\n"), errstr);
+ fprintf(stderr, _("ReadConsole() failed: %s\n"), errstr);
free(errstr);
*string = NULL;
- goto out;
+ if (hidden)
+ SetConsoleMode(stdinh, cmode);
+ return;
}
+ if (hidden)
+ SetConsoleMode(stdinh, cmode);
+ } else {
+ /* Not a console; maybe reading from a piped stdin? */
+ if (!fgetws(wbuf, sizeof(wbuf)/2, stdin)) {
+ char *errstr = openconnect__win32_strerror(GetLastError());
+ fprintf(stderr, _("fgetws() failed: %s\n"), errstr);
+ free(errstr);
+ *string = NULL;
+ return;
+ }
+ nr_read = wcslen(wbuf);
}
- if (hidden) {
- SetConsoleMode(conh, cmode & (~ENABLE_ECHO_INPUT));
- }
-
- if (!ReadConsoleW(conh, wbuf, sizeof(wbuf)/2, &nr_read, &rcc)) {
- char *errstr = openconnect__win32_strerror(GetLastError());
- fprintf(stderr, _("ReadConsole() failed: %s\n"), errstr);
- free(errstr);
- *string = NULL;
- goto out;
- }
-
if (nr_read >= 2 && wbuf[nr_read - 1] == 10 && wbuf[nr_read - 2] == 13) {
wbuf[nr_read - 2] = 0;
nr_read -= 2;
@@ -408,7 +409,7 @@ static void read_stdin(char **string, int hidden, int allow_fail)
fprintf(stderr, _("Error converting console input: %s\n"),
errstr);
free(errstr);
- goto out;
+ return;
}
buf = malloc(nr_read);
if (!buf) {
@@ -422,18 +423,10 @@ static void read_stdin(char **string, int hidden, int allow_fail)
errstr);
free(errstr);
free(buf);
- goto out;
+ return;
}
*string = buf;
-
-out:
- if (hidden) {
- SetConsoleMode(conh, cmode);
- fprintf(stderr, "\n");
- }
- if (conh != stdinh && conh != INVALID_HANDLE_VALUE)
- CloseHandle(conh);
}
#elif defined(HAVE_ICONV)
diff --git a/www/changelog.xml b/www/changelog.xml
index 6016256a..ed2d08b1 100644
--- a/www/changelog.xml
+++ b/www/changelog.xml
@@ -15,6 +15,7 @@
- OpenConnect HEAD
+ - Fix --passwd-on-stdin for Windows to not forcibly open console.
- Fix portability of shell scripts in test suite.
- Add Google Authenticator TOTP support for Juniper.
- Add RFC7469 key PIN support for cert hashes.
From 39eb59e3dc5ab8889225e792a27a47ce8f1eff7a Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 11:33:16 +0100
Subject: [PATCH 011/131] Require GnuTLS 3.2.10+ for GnuTLS builds
It's not worth the effort to keep it building for <3.2 any more; nobody
cares... or noticess when we accidentally break it. So kill it; we've
been threatening to for ages.
Use 3.2.10 as the base because 3.2.x before that was broken on Windows.
Signed-off-by: David Woodhouse
---
configure.ac | 15 +++------------
www/building.xml | 2 +-
www/changelog.xml | 1 +
3 files changed, 5 insertions(+), 13 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5c50cf62..bb92df7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -279,18 +279,9 @@ fi
# First, check if GnuTLS exists and is usable
if test "$with_gnutls" = "yes" || test "$with_gnutls" = ""; then
- PKG_CHECK_MODULES(GNUTLS, gnutls >= 2.12.16,
- [if ! $PKG_CONFIG --atleast-version=2.12.16 gnutls; then
- AC_MSG_WARN([Your GnuTLS is too old. At least v2.12.16 is required])
- elif test "$have_win" = "yes"; then
- AC_MSG_CHECKING([for broken GnuTLS Windows versions])
- if $PKG_CONFIG --atleast-version=3.2.0 gnutls &&
- ! $PKG_CONFIG --atleast-version=3.2.10 gnutls; then
- AC_MSG_RESULT([broken])
- else
- AC_MSG_RESULT([OK])
- ssl_library=GnuTLS
- fi
+ PKG_CHECK_MODULES(GNUTLS, gnutls,
+ [if ! $PKG_CONFIG --atleast-version=3.2.10 gnutls; then
+ AC_MSG_WARN([Your GnuTLS is too old. At least v3.2.10 is required])
else
ssl_library=GnuTLS
fi], [:])
diff --git a/www/building.xml b/www/building.xml
index bcee63b9..d15f48bc 100644
--- a/www/building.xml
+++ b/www/building.xml
@@ -23,7 +23,7 @@ libraries and tools installed:
- libxml2
- zlib
- - Either OpenSSL or GnuTLS
+ - Either OpenSSL or GnuTLS (v3.2.10+)
- pkg-config
And optionally also:
diff --git a/www/changelog.xml b/www/changelog.xml
index ed2d08b1..300ea2c8 100644
--- a/www/changelog.xml
+++ b/www/changelog.xml
@@ -15,6 +15,7 @@
- OpenConnect HEAD
+ - Drop support for GnuTLS older than 3.2.10.
- Fix --passwd-on-stdin for Windows to not forcibly open console.
- Fix portability of shell scripts in test suite.
- Add Google Authenticator TOTP support for Juniper.
From 881dcb2eb58b2836c51a7b440bec9d2d4d51b916 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 11:47:02 +0100
Subject: [PATCH 012/131] Kill HAVE_GNUTLS_DTLS_SET_DATA_MTU
Signed-off-by: David Woodhouse
---
configure.ac | 2 --
gnutls-dtls.c | 9 ---------
2 files changed, 11 deletions(-)
diff --git a/configure.ac b/configure.ac
index bb92df7e..f48ea1fb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -450,8 +450,6 @@ case "$ssl_library" in
oldcflags="$CFLAGS"
LIBS="$LIBS $GNUTLS_LIBS"
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
- AC_CHECK_FUNC(gnutls_dtls_set_data_mtu,
- [AC_DEFINE(HAVE_GNUTLS_DTLS_SET_DATA_MTU, 1, [From GnuTLS 3.0.20])], [])
AC_CHECK_FUNC(gnutls_pkcs11_get_raw_issuer,
[AC_DEFINE(HAVE_GNUTLS_PKCS11_GET_RAW_ISSUER, 1, [From GnuTLS 3.2.7])], [])
AC_CHECK_FUNC(gnutls_certificate_set_x509_system_trust,
diff --git a/gnutls-dtls.c b/gnutls-dtls.c
index 4b515a7b..7d15be6c 100644
--- a/gnutls-dtls.c
+++ b/gnutls-dtls.c
@@ -354,7 +354,6 @@ int dtls_try_handshake(struct openconnect_info *vpninfo)
return -EIO;
}
-#ifdef HAVE_GNUTLS_DTLS_SET_DATA_MTU
/* Make sure GnuTLS's idea of the MTU is sufficient to take
a full VPN MTU (with 1-byte header) in a data record. */
err = gnutls_dtls_set_data_mtu(vpninfo->dtls_ssl, vpninfo->ip_info.mtu + 1);
@@ -364,14 +363,6 @@ int dtls_try_handshake(struct openconnect_info *vpninfo)
gnutls_strerror(err));
goto error;
}
-#else
- /* If we don't have gnutls_dtls_set_data_mtu() then make sure
- we leave enough headroom by adding the worst-case overhead.
- We only support AES128-CBC and DES-CBC3-SHA anyway, so
- working out the worst case isn't hard. */
- gnutls_dtls_set_mtu(vpninfo->dtls_ssl,
- vpninfo->ip_info.mtu + DTLS_OVERHEAD);
-#endif
}
vpninfo->dtls_state = DTLS_CONNECTED;
From 266a3938b8daad34af5b55c3e99590be0594bf19 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 11:49:54 +0100
Subject: [PATCH 013/131] Kill HAVE_GNUTLS_PKCS11_GET_RAW_ISSUER
Signed-off-by: David Woodhouse
---
configure.ac | 2 --
gnutls.c | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/configure.ac b/configure.ac
index f48ea1fb..7eed841a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -450,8 +450,6 @@ case "$ssl_library" in
oldcflags="$CFLAGS"
LIBS="$LIBS $GNUTLS_LIBS"
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
- AC_CHECK_FUNC(gnutls_pkcs11_get_raw_issuer,
- [AC_DEFINE(HAVE_GNUTLS_PKCS11_GET_RAW_ISSUER, 1, [From GnuTLS 3.2.7])], [])
AC_CHECK_FUNC(gnutls_certificate_set_x509_system_trust,
[AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST, 1, [From GnuTLS 3.0.20])], [])
if test "$ac_cv_func_gnutls_certificate_set_x509_system_trust" != "yes"; then
diff --git a/gnutls.c b/gnutls.c
index ea96cef5..aeae229e 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -1751,7 +1751,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
}
free_issuer = 0;
-#if defined(HAVE_P11KIT) && defined(HAVE_GNUTLS_PKCS11_GET_RAW_ISSUER)
+#ifdef HAVE_P11KIT
if (err && cert_is_p11) {
gnutls_datum_t t;
From 324b88d8dbd7e62134d2b7faa4c68fa910547da0 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 11:54:13 +0100
Subject: [PATCH 014/131] Kill HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST
Signed-off-by: David Woodhouse
---
configure.ac | 36 ------------------------------------
gnutls.c | 10 ++--------
2 files changed, 2 insertions(+), 44 deletions(-)
diff --git a/configure.ac b/configure.ac
index 7eed841a..8fec7905 100644
--- a/configure.ac
+++ b/configure.ac
@@ -450,42 +450,6 @@ case "$ssl_library" in
oldcflags="$CFLAGS"
LIBS="$LIBS $GNUTLS_LIBS"
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
- AC_CHECK_FUNC(gnutls_certificate_set_x509_system_trust,
- [AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST, 1, [From GnuTLS 3.0.20])], [])
- if test "$ac_cv_func_gnutls_certificate_set_x509_system_trust" != "yes"; then
- # We will need to tell GnuTLS the path to the system CA file.
- if test "$with_system_cafile" = "yes" || test "$with_system_cafile" = ""; then
- unset with_system_cafile
- AC_MSG_CHECKING([For location of system CA trust file])
- for file in /etc/ssl/certs/ca-certificates.crt \
- /etc/pki/tls/cert.pem \
- /usr/local/share/certs/ca-root-nss.crt \
- /etc/ssl/cert.pem \
- /etc/ssl/ca-bundle.pem \
- ; do
- if grep 'BEGIN CERTIFICATE-----' $file >/dev/null 2>&1; then
- with_system_cafile=${file}
- break
- fi
- done
- AC_MSG_RESULT([${with_system_cafile-NOT FOUND}])
- elif test "$with_system_cafile" = "no"; then
- AC_MSG_ERROR([You cannot disable the system CA certificate file.])
- fi
- if test "$with_system_cafile" = ""; then
- AC_MSG_ERROR([Unable to find a standard system CA certificate file.]
- [Your GnuTLS requires a path to a CA certificate store. This is a file]
- [which contains a list of the Certificate Authorities which are trusted.]
- [Most distributions ship with this file in a standard location, but none]
- [the known standard locations exist on your system. You should provide a]
- [--with-system-cafile= argument to this configure script, giving the full]
- [path to a default CA certificate file for GnuTLS to use. Also, please]
- [send full details of your system, including 'uname -a' output and the]
- [location of the system CA certificate store on your system, to the]
- [openconnect-devel@lists.infradead.org mailing list.])
- fi
- AC_DEFINE_UNQUOTED([DEFAULT_SYSTEM_CAFILE], ["$with_system_cafile"], [Location of System CA trust file])
- fi
AC_CHECK_FUNC(gnutls_cipher_set_iv,
[esp=yes], [])
AC_CHECK_FUNC(gnutls_pkcs12_simple_parse,
diff --git a/gnutls.c b/gnutls.c
index aeae229e..4f3c46e6 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -2228,15 +2228,9 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
if (!vpninfo->https_cred) {
gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
- if (!vpninfo->no_system_trust) {
-#ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST
+ if (!vpninfo->no_system_trust)
gnutls_certificate_set_x509_system_trust(vpninfo->https_cred);
-#else
- gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
- DEFAULT_SYSTEM_CAFILE,
- GNUTLS_X509_FMT_PEM);
-#endif
- }
+
gnutls_certificate_set_verify_function(vpninfo->https_cred,
verify_peer);
From 5f0eb81daa0df5668eedd8e48eaeea065c92d9ad Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 12:02:12 +0100
Subject: [PATCH 015/131] Build ESP and DTLS unconditionally with GnuTLS
We don't support any verions of GnuTLS that can't do these, any more.
Signed-off-by: David Woodhouse
---
configure.ac | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/configure.ac b/configure.ac
index 8fec7905..205f3026 100644
--- a/configure.ac
+++ b/configure.ac
@@ -450,8 +450,8 @@ case "$ssl_library" in
oldcflags="$CFLAGS"
LIBS="$LIBS $GNUTLS_LIBS"
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
- AC_CHECK_FUNC(gnutls_cipher_set_iv,
- [esp=yes], [])
+ esp=yes
+ dtls=yes
AC_CHECK_FUNC(gnutls_pkcs12_simple_parse,
[AC_DEFINE(HAVE_GNUTLS_PKCS12_SIMPLE_PARSE, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_certificate_set_key,
@@ -466,8 +466,6 @@ case "$ssl_library" in
[AC_DEFINE(HAVE_GNUTLS_URL_IS_SUPPORTED, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_system_key_add_x509,
[AC_DEFINE(HAVE_GNUTLS_SYSTEM_KEYS, 1, [From GnuTLS 3.4.0])], [])
- AC_CHECK_FUNC(gnutls_session_set_premaster,
- [dtls=yes], [])
AC_CHECK_FUNC(gnutls_pkcs11_add_provider,
[PKG_CHECK_MODULES(P11KIT, p11-kit-1,
[AC_DEFINE(HAVE_P11KIT, 1, [Have. P11. Kit.])
From 95970abc6bee57fed6b291d9f72bb421eb1736fe Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 12:07:20 +0100
Subject: [PATCH 016/131] Kill HAVE_GNUTLS_PKCS12_SIMPLE_PARSE
Signed-off-by: David Woodhouse
---
Makefile.am | 2 +-
configure.ac | 2 -
gnutls.h | 15 --
gnutls_pkcs12.c | 526 ------------------------------------------------
4 files changed, 1 insertion(+), 544 deletions(-)
delete mode 100644 gnutls_pkcs12.c
diff --git a/Makefile.am b/Makefile.am
index 5df72917..bb0f3774 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,7 +27,7 @@ openconnect_LDADD = libopenconnect.la $(SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIB
library_srcs = ssl.c http.c http-auth.c auth-common.c library.c compat.c lzs.c mainloop.c script.c ntlm.c digest.c
lib_srcs_cisco = auth.c cstp.c
lib_srcs_juniper = oncp.c lzo.c auth-juniper.c
-lib_srcs_gnutls = gnutls.c gnutls_pkcs12.c gnutls_tpm.c
+lib_srcs_gnutls = gnutls.c gnutls_tpm.c
lib_srcs_openssl = openssl.c openssl-pkcs11.c
lib_srcs_win32 = tun-win32.c sspi.c
lib_srcs_posix = tun.c
diff --git a/configure.ac b/configure.ac
index 205f3026..fbc1a994 100644
--- a/configure.ac
+++ b/configure.ac
@@ -452,8 +452,6 @@ case "$ssl_library" in
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
esp=yes
dtls=yes
- AC_CHECK_FUNC(gnutls_pkcs12_simple_parse,
- [AC_DEFINE(HAVE_GNUTLS_PKCS12_SIMPLE_PARSE, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_certificate_set_key,
[AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_SET_KEY, 1, [From GnuTLS 3.0.4])], [])
AC_CHECK_FUNC(gnutls_pk_to_sign,
diff --git a/gnutls.h b/gnutls.h
index e61443b0..3c4e7909 100644
--- a/gnutls.h
+++ b/gnutls.h
@@ -24,21 +24,6 @@
#include "openconnect-internal.h"
-#ifndef HAVE_GNUTLS_PKCS12_SIMPLE_PARSE
-/* If we're using a version of GnuTLS from before this was
- exported, pull in our local copy. */
-int gnutls_pkcs12_simple_parse(gnutls_pkcs12_t p12, const char *password,
- gnutls_x509_privkey_t *key,
- gnutls_x509_crt_t **chain,
- unsigned int *chain_len,
- gnutls_x509_crt_t **extra_certs,
- unsigned int *extra_certs_len,
- gnutls_x509_crl_t *crl,
- unsigned int flags);
-
-#endif /* !HAVE_GNUTLS_PKCS12_SIMPLE_PARSE */
-
-
#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
int gtls2_tpm_sign_cb(gnutls_session_t sess, void *_vpninfo,
gnutls_certificate_type_t cert_type,
diff --git a/gnutls_pkcs12.c b/gnutls_pkcs12.c
deleted file mode 100644
index a90f8a4b..00000000
--- a/gnutls_pkcs12.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * This is (now) gnutls_pkcs12_simple_parse() from GnuTLS 3.1, although
- * it was actually taken from parse_pkcs12() in GnuTLS 2.12.x (where it
- * was under LGPLv2.1) and modified locally. The modifications were
- * accepted back into GnuTLS in commit 9a43e8fa. Further modifications
- * by Nikos Mavrogiannopoulos are included here under LGPLv2.1 with his
- * explicit permission.
- */
-
-#include
-
-#ifndef HAVE_GNUTLS_PKCS12_SIMPLE_PARSE
-
-#include
-#include "gnutls.h"
-
-#define opaque unsigned char
-#define gnutls_assert() do {} while(0)
-#define gnutls_assert_val(x) (x)
-
-/*
- * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- * Free Software Foundation, Inc.
- *
- * Author: Nikos Mavrogiannopoulos
- *
- * This file WAS part of GnuTLS.
- *
- * The GnuTLS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- */
-
-
-/* Checks if the extra_certs contain certificates that may form a chain
- * with the first certificate in chain (it is expected that chain_len==1)
- * and appends those in the chain.
- */
-static int make_chain(gnutls_x509_crt_t **chain, unsigned int *chain_len,
- gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len)
-{
-unsigned int i;
-
- if (*chain_len != 1)
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
- i = 0;
- while(i<*extra_certs_len)
- {
- /* if it is an issuer but not a self-signed one */
- if (gnutls_x509_crt_check_issuer((*chain)[*chain_len - 1], (*extra_certs)[i]) != 0 &&
- gnutls_x509_crt_check_issuer((*extra_certs)[i], (*extra_certs)[i]) == 0)
- {
- void *tmp = *chain;
- *chain = gnutls_realloc (*chain, sizeof((*chain)[0]) *
- ++(*chain_len));
- if (*chain == NULL)
- {
- gnutls_assert();
- gnutls_free(tmp);
- return GNUTLS_E_MEMORY_ERROR;
- }
- (*chain)[*chain_len - 1] = (*extra_certs)[i];
-
- (*extra_certs)[i] = (*extra_certs)[*extra_certs_len-1];
- (*extra_certs_len)--;
-
- i=0;
- continue;
- }
- i++;
- }
- return 0;
-}
-
-/**
- * gnutls_pkcs12_simple_parse:
- * @p12: the PKCS#12 blob.
- * @password: optional password used to decrypt PKCS#12 blob, bags and keys.
- * @key: a structure to store the parsed private key.
- * @chain: the corresponding to key certificate chain
- * @chain_len: will be updated with the number of additional
- * @extra_certs: optional pointer to receive an array of additional
- * certificates found in the PKCS#12 blob.
- * @extra_certs_len: will be updated with the number of additional
- * certs.
- * @crl: an optional structure to store the parsed CRL.
- * @flags: should be zero
- *
- * This function parses a PKCS#12 blob in @p12blob and extracts the
- * private key, the corresponding certificate chain, and any additional
- * certificates and a CRL.
- *
- * The @extra_certs_ret and @extra_certs_ret_len parameters are optional
- * and both may be set to %NULL. If either is non-%NULL, then both must
- * be.
- *
- * MAC:ed PKCS#12 files are supported. Encrypted PKCS#12 bags are
- * supported. Encrypted PKCS#8 private keys are supported. However,
- * only password based security, and the same password for all
- * operations, are supported.
- *
- * The private keys may be RSA PKCS#1 or DSA private keys encoded in
- * the OpenSSL way.
- *
- * PKCS#12 file may contain many keys and/or certificates, and there
- * is no way to identify which key/certificate pair you want. You
- * should make sure the PKCS#12 file only contain one key/certificate
- * pair and/or one CRL.
- *
- * It is believed that the limitations of this function is acceptable
- * for most usage, and that any more flexibility would introduce
- * complexity that would make it harder to use this functionality at
- * all.
- *
- * If the provided structure has encrypted fields but no password
- * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED.
- *
- * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
- * negative error value.
- *
- * Since: 3.1
- **/
-int
-gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12,
- const char *password,
- gnutls_x509_privkey_t * key,
- gnutls_x509_crt_t ** chain,
- unsigned int * chain_len,
- gnutls_x509_crt_t ** extra_certs,
- unsigned int * extra_certs_len,
- gnutls_x509_crl_t * crl,
- unsigned int flags)
-{
- gnutls_pkcs12_bag_t bag = NULL;
- gnutls_x509_crt_t *_extra_certs = NULL;
- unsigned int _extra_certs_len = 0;
- gnutls_x509_crt_t *_chain = NULL;
- unsigned int _chain_len = 0;
- int idx = 0;
- int ret;
- size_t cert_id_size = 0;
- size_t key_id_size = 0;
- opaque cert_id[20];
- opaque key_id[20];
- int privkey_ok = 0;
-
- *key = NULL;
-
- if (crl)
- *crl = NULL;
-
- /* find the first private key */
- for (;;)
- {
- int elements_in_bag;
- int i;
-
- ret = gnutls_pkcs12_bag_init (&bag);
- if (ret < 0)
- {
- bag = NULL;
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_pkcs12_get_bag (p12, idx, bag);
- if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
- break;
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_pkcs12_bag_get_type (bag, 0);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- if (ret == GNUTLS_BAG_ENCRYPTED)
- {
- if (password == NULL)
- {
- ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
- goto done;
- }
-
- ret = gnutls_pkcs12_bag_decrypt (bag, password);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
- }
-
- elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
- if (elements_in_bag < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- for (i = 0; i < elements_in_bag; i++)
- {
- int type;
- gnutls_datum_t data;
-
- type = gnutls_pkcs12_bag_get_type (bag, i);
- if (type < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- switch (type)
- {
- case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
- if (password == NULL)
- {
- ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
- goto done;
- }
-
- case GNUTLS_BAG_PKCS8_KEY:
- if (*key != NULL) /* too simple to continue */
- {
- gnutls_assert ();
- break;
- }
-
- ret = gnutls_x509_privkey_init (key);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_x509_privkey_import_pkcs8
- (*key, &data, GNUTLS_X509_FMT_DER, password,
- type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- key_id_size = sizeof (key_id);
- ret =
- gnutls_x509_privkey_get_key_id (*key, 0, key_id,
- &key_id_size);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- privkey_ok = 1; /* break */
- break;
- default:
- break;
- }
- }
-
- idx++;
- gnutls_pkcs12_bag_deinit (bag);
-
- if (privkey_ok != 0) /* private key was found */
- break;
- }
-
- if (privkey_ok == 0) /* no private key */
- {
- gnutls_assert ();
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
- }
-
- /* now find the corresponding certificate
- */
- idx = 0;
- bag = NULL;
- for (;;)
- {
- int elements_in_bag;
- int i;
-
- ret = gnutls_pkcs12_bag_init (&bag);
- if (ret < 0)
- {
- bag = NULL;
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_pkcs12_get_bag (p12, idx, bag);
- if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
- break;
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_pkcs12_bag_get_type (bag, 0);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- if (ret == GNUTLS_BAG_ENCRYPTED)
- {
- ret = gnutls_pkcs12_bag_decrypt (bag, password);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
- }
-
- elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
- if (elements_in_bag < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- for (i = 0; i < elements_in_bag; i++)
- {
- int type;
- gnutls_datum_t data;
- gnutls_x509_crt_t this_cert;
-
- type = gnutls_pkcs12_bag_get_type (bag, i);
- if (type < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- switch (type)
- {
- case GNUTLS_BAG_CERTIFICATE:
- ret = gnutls_x509_crt_init (&this_cert);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- ret =
- gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER);
- if (ret < 0)
- {
- gnutls_assert ();
- gnutls_x509_crt_deinit (this_cert);
- goto done;
- }
-
- /* check if the key id match */
- cert_id_size = sizeof (cert_id);
- ret =
- gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size);
- if (ret < 0)
- {
- gnutls_assert ();
- gnutls_x509_crt_deinit (this_cert);
- goto done;
- }
-
- if (memcmp (cert_id, key_id, cert_id_size) != 0)
- { /* they don't match - skip the certificate */
- if (extra_certs)
- {
- void *tmp = _extra_certs;
- _extra_certs = gnutls_realloc (_extra_certs,
- sizeof(_extra_certs[0]) *
- ++_extra_certs_len);
- if (!_extra_certs)
- {
- gnutls_assert ();
- gnutls_free(tmp);
- ret = GNUTLS_E_MEMORY_ERROR;
- goto done;
- }
- _extra_certs[_extra_certs_len - 1] = this_cert;
- this_cert = NULL;
- }
- else
- {
- gnutls_x509_crt_deinit (this_cert);
- }
- }
- else
- {
- if (_chain_len == 0)
- {
- _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len));
- if (!_chain)
- {
- gnutls_assert ();
- ret = GNUTLS_E_MEMORY_ERROR;
- goto done;
- }
- _chain[_chain_len - 1] = this_cert;
- this_cert = NULL;
- }
- else
- {
- gnutls_x509_crt_deinit (this_cert);
- }
- }
- break;
-
- case GNUTLS_BAG_CRL:
- if (crl == NULL || *crl != NULL)
- {
- gnutls_assert ();
- break;
- }
-
- ret = gnutls_x509_crl_init (crl);
- if (ret < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
- ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER);
- if (ret < 0)
- {
- gnutls_assert ();
- gnutls_x509_crl_deinit (*crl);
- goto done;
- }
- break;
-
- case GNUTLS_BAG_ENCRYPTED:
- /* XXX Bother to recurse one level down? Unlikely to
- use the same password anyway. */
- case GNUTLS_BAG_EMPTY:
- default:
- break;
- }
- }
-
- idx++;
- gnutls_pkcs12_bag_deinit (bag);
- }
-
- if (_chain_len != 1)
- {
- ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
- goto done;
- }
-
- ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len);
- if (ret < 0)
- {
- gnutls_assert();
- goto done;
- }
-
- ret = 0;
-
-done:
- if (bag)
- gnutls_pkcs12_bag_deinit (bag);
-
- if (ret < 0)
- {
- if (*key)
- gnutls_x509_privkey_deinit(*key);
- if (_extra_certs_len && _extra_certs != NULL)
- {
- unsigned int i;
- for (i = 0; i < _extra_certs_len; i++)
- gnutls_x509_crt_deinit(_extra_certs[i]);
- gnutls_free(_extra_certs);
- }
- if (_chain_len && _chain != NULL)
- {
- unsigned int i;
- for (i = 0; i < _chain_len; i++)
- gnutls_x509_crt_deinit(_chain[i]);
- gnutls_free(_chain);
- }
- }
- else
- {
- if (extra_certs)
- {
- *extra_certs = _extra_certs;
- *extra_certs_len = _extra_certs_len;
- }
-
- *chain = _chain;
- *chain_len = _chain_len;
- }
-
- return ret;
-}
-
-#endif /* HAVE_GNUTLS_PKCS12_SIMPLE_PARSE */
From e42c1166e9e451eb5f9a99dfa0808636cd3db8d8 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 12:25:33 +0100
Subject: [PATCH 017/131] Kill HAVE_GNUTLS_CERTIFICATE_SET_KEY
Signed-off-by: David Woodhouse
---
configure.ac | 2 -
gnutls.c | 132 +++--------------------------------------
gnutls.h | 27 ---------
gnutls_tpm.c | 68 +--------------------
openconnect-internal.h | 9 ---
5 files changed, 9 insertions(+), 229 deletions(-)
diff --git a/configure.ac b/configure.ac
index fbc1a994..3e39ec1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -452,8 +452,6 @@ case "$ssl_library" in
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
esp=yes
dtls=yes
- AC_CHECK_FUNC(gnutls_certificate_set_key,
- [AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_SET_KEY, 1, [From GnuTLS 3.0.4])], [])
AC_CHECK_FUNC(gnutls_pk_to_sign,
[AC_DEFINE(HAVE_GNUTLS_PK_TO_SIGN, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_pubkey_export2,
diff --git a/gnutls.c b/gnutls.c
index 4f3c46e6..4b9bc956 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -27,12 +27,6 @@
#include
#include
-#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
-/* Shut up about gnutls_sign_callback_set() being deprecated. We only use it
- in the GnuTLS 2.12 case, and there just isn't another way of doing it. */
-#define GNUTLS_INTERNAL_BUILD 1
-#endif
-
#include
#include
#include
@@ -593,86 +587,9 @@ static int get_cert_name(gnutls_x509_crt_t cert, char *name, size_t namelen)
}
#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined (HAVE_GNUTLS_SYSTEM_KEYS)
-#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
-/* For GnuTLS 2.12 even if we *have* a privkey (as we do for PKCS#11), we
- can't register it. So we have to use the cert_callback function. This
- just hands out the certificate chain we prepared in load_certificate().
- If we have a pkey then return that too; otherwise leave the key NULL —
- we'll also have registered a sign_callback for the session, which will
- handle that. */
-static int gtls_cert_cb(gnutls_session_t sess, const gnutls_datum_t *req_ca_dn,
- int nreqs, const gnutls_pk_algorithm_t *pk_algos,
- int pk_algos_length, gnutls_retr2_st *st) {
-
- struct openconnect_info *vpninfo = gnutls_session_get_ptr(sess);
- int algo = GNUTLS_PK_RSA; /* TPM */
- int i;
-
-#ifdef HAVE_P11KIT
- if (vpninfo->my_p11key) {
- st->key_type = GNUTLS_PRIVKEY_PKCS11;
- st->key.pkcs11 = vpninfo->my_p11key;
- algo = gnutls_pkcs11_privkey_get_pk_algorithm(vpninfo->my_p11key, NULL);
- };
-#endif
- for (i = 0; i < pk_algos_length; i++) {
- if (algo == pk_algos[i])
- break;
- }
- if (i == pk_algos_length)
- return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
-
- st->cert_type = GNUTLS_CRT_X509;
- st->cert.x509 = vpninfo->my_certs;
- st->ncerts = vpninfo->nr_my_certs;
- st->deinit_all = 0;
-
- return 0;
-}
-
-/* For GnuTLS 2.12, this has to set the cert_callback to the function
- above, which will return the pkey and certs on demand. Or in the
- case of TPM we can't make a suitable pkey, so we have to set a
- sign_callback too (which is done in openconnect_open_https() since
- it has to be done on the *session*). */
-static int assign_privkey(struct openconnect_info *vpninfo,
- gnutls_privkey_t pkey,
- gnutls_x509_crt_t *certs,
- unsigned int nr_certs,
- uint8_t *free_certs)
-{
- vpninfo->my_certs = gnutls_calloc(nr_certs, sizeof(*certs));
- if (!vpninfo->my_certs)
- return GNUTLS_E_MEMORY_ERROR;
-
- vpninfo->free_my_certs = gnutls_malloc(nr_certs);
- if (!vpninfo->free_my_certs) {
- gnutls_free(vpninfo->my_certs);
- vpninfo->my_certs = NULL;
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- memcpy(vpninfo->free_my_certs, free_certs, nr_certs);
- memcpy(vpninfo->my_certs, certs, nr_certs * sizeof(*certs));
- vpninfo->nr_my_certs = nr_certs;
-
- /* We are *keeping* the certs, unlike in GnuTLS 3 where our caller
- can free them after gnutls_certificate_set_key() has been called.
- So wipe the 'free_certs' array. */
- memset(free_certs, 0, nr_certs);
-
- gnutls_certificate_set_retrieve_function(vpninfo->https_cred,
- gtls_cert_cb);
- vpninfo->my_pkey = pkey;
-
- return 0;
-}
-#else /* !SET_KEY */
-
-/* For GnuTLS 3+ this is saner than the GnuTLS 2.12 version. But still we
- have to convert the array of X509 certificates to gnutls_pcert_st for
- ourselves. There's no function that takes a gnutls_privkey_t as the key
- and gnutls_x509_crt_t certificates. */
+/* We have to convert the array of X509 certificates to gnutls_pcert_st
+ for ourselves. There's no function that takes a gnutls_privkey_t as
+ the key and gnutls_x509_crt_t certificates. */
static int assign_privkey(struct openconnect_info *vpninfo,
gnutls_privkey_t pkey,
gnutls_x509_crt_t *certs,
@@ -708,17 +625,15 @@ static int assign_privkey(struct openconnect_info *vpninfo,
}
return err;
}
-#endif /* !SET_KEY */
static int verify_signed_data(gnutls_pubkey_t pubkey, gnutls_privkey_t privkey,
const gnutls_datum_t *data, const gnutls_datum_t *sig)
{
#ifdef HAVE_GNUTLS_PK_TO_SIGN
- gnutls_sign_algorithm_t algo = GNUTLS_SIGN_RSA_SHA1; /* TPM keys */
+ gnutls_sign_algorithm_t algo;
- if (privkey != OPENCONNECT_TPM_PKEY)
- algo = gnutls_pk_to_sign(gnutls_privkey_get_pk_algorithm(privkey, NULL),
- GNUTLS_DIG_SHA1);
+ algo = gnutls_pk_to_sign(gnutls_privkey_get_pk_algorithm(privkey, NULL),
+ GNUTLS_DIG_SHA1);
return gnutls_pubkey_verify_data2(pubkey, algo, 0, data, sig);
#else
@@ -1415,16 +1330,6 @@ static int load_certificate(struct openconnect_info *vpninfo)
ret = -EIO;
goto out;
}
-#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
- /* This can be set now and doesn't need to be separately freed.
- It goes with the pkey. This is a PITA; it would be better
- if there was a way to get the p11key *back* from a privkey
- that we *know* is based on one. In fact, since this is only
- for GnuTLS 2.12 and we *know* the gnutls_privkey_st won't
- ever change there, so we *could* do something evil... but
- we won't :) */
- vpninfo->my_p11key = p11key;
-#endif /* !SET_KEY */
goto match_cert;
}
#endif /* HAVE_P11KIT */
@@ -1618,7 +1523,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
fdata.size = 20;
}
- err = sign_dummy_data(vpninfo, pkey, &fdata, &pkey_sig);
+ err = gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA1, 0, &fdata, &pkey_sig);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Error signing test data with private key: %s\n"),
@@ -1882,7 +1787,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
gnutls_free(extra_certs);
#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
- if (pkey && pkey != OPENCONNECT_TPM_PKEY)
+ if (pkey)
gnutls_privkey_deinit(pkey);
/* If we support arbitrary privkeys, we might have abused fdata.data
just to point to something to hash. Don't free it in that case! */
@@ -2315,10 +2220,6 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
}
gnutls_init(&vpninfo->https_sess, GNUTLS_CLIENT);
gnutls_session_set_ptr(vpninfo->https_sess, (void *) vpninfo);
-#if defined(HAVE_TROUSERS) && !defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
- if (vpninfo->my_pkey == OPENCONNECT_TPM_PKEY)
- gnutls_sign_callback_set(vpninfo->https_sess, gtls2_tpm_sign_cb, vpninfo);
-#endif
/*
* For versions of GnuTLS older than 3.2.9, we try to avoid long
* packets by silently disabling extensions such as SNI.
@@ -2512,23 +2413,6 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
Tspi_Context_Close(vpninfo->tpm_context);
vpninfo->tpm_context = 0;
}
-#endif
-#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
- if (vpninfo->my_pkey && vpninfo->my_pkey != OPENCONNECT_TPM_PKEY) {
- gnutls_privkey_deinit(vpninfo->my_pkey);
- vpninfo->my_pkey = NULL;
- /* my_p11key went with it */
- }
- if (vpninfo->my_certs) {
- int i;
- for (i = 0; i < vpninfo->nr_my_certs; i++)
- if (vpninfo->free_my_certs[i])
- gnutls_x509_crt_deinit(vpninfo->my_certs[i]);
- gnutls_free(vpninfo->my_certs);
- gnutls_free(vpninfo->free_my_certs);
- vpninfo->my_certs = NULL;
- vpninfo->free_my_certs = NULL;
- }
#endif
}
}
diff --git a/gnutls.h b/gnutls.h
index 3c4e7909..5eeacb0f 100644
--- a/gnutls.h
+++ b/gnutls.h
@@ -24,33 +24,6 @@
#include "openconnect-internal.h"
-#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
-int gtls2_tpm_sign_cb(gnutls_session_t sess, void *_vpninfo,
- gnutls_certificate_type_t cert_type,
- const gnutls_datum_t *cert, const gnutls_datum_t *data,
- gnutls_datum_t *sig);
-int gtls2_tpm_sign_dummy_data(struct openconnect_info *vpninfo,
- const gnutls_datum_t *data,
- gnutls_datum_t *sig);
-#endif /* !HAVE_GNUTLS_CERTIFICATE_SET_KEY */
-
-/* In GnuTLS 2.12 this can't be a real private key; we have to use the sign_callback
- instead. But we want to set the 'pkey' variable to *something* non-NULL in order
- to indicate that we aren't just using an x509 key. */
-#define OPENCONNECT_TPM_PKEY ((void *)1UL)
-
-static inline int sign_dummy_data(struct openconnect_info *vpninfo,
- gnutls_privkey_t pkey,
- const gnutls_datum_t *data,
- gnutls_datum_t *sig)
-{
-#if defined(HAVE_TROUSERS) && !defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
- if (pkey == OPENCONNECT_TPM_PKEY)
- return gtls2_tpm_sign_dummy_data(vpninfo, data, sig);
-#endif
- return gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA1, 0, data, sig);
-}
-
int load_tpm_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig);
diff --git a/gnutls_tpm.c b/gnutls_tpm.c
index 070796f5..ed417d19 100644
--- a/gnutls_tpm.c
+++ b/gnutls_tpm.c
@@ -33,68 +33,6 @@
#ifdef HAVE_TROUSERS
/* Signing function for TPM privkeys, set with gnutls_privkey_import_ext() */
-static int tpm_sign_fn(gnutls_privkey_t key, void *_vpninfo,
- const gnutls_datum_t *data, gnutls_datum_t *sig);
-
-
-#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
-/* We *want* to use gnutls_privkey_import_ext() to create a privkey with our
- own signing function tpm_sign_fn(). But GnuTLS 2.12 doesn't support that,
- so instead we have to register this sign_callback function with the
- *session* */
-int gtls2_tpm_sign_cb(gnutls_session_t sess, void *_vpninfo,
- gnutls_certificate_type_t cert_type,
- const gnutls_datum_t *cert, const gnutls_datum_t *data,
- gnutls_datum_t *sig)
-{
- struct openconnect_info *vpninfo = _vpninfo;
-
- if (cert_type != GNUTLS_CRT_X509)
- return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
-
- return tpm_sign_fn(NULL, vpninfo, data, sig);
-}
-
-/* In GnuTLS 2.12 since we don't have a normal privkey and hence can't just
- use gnutls_privkey_sign_data() with it, we have to jump through hoops to
- prepare the hash in exactly the right way and call our internal TPM
- signing function. */
-int gtls2_tpm_sign_dummy_data(struct openconnect_info *vpninfo,
- const gnutls_datum_t *data,
- gnutls_datum_t *sig)
-{
- static const unsigned char ber_encode[15] = {
- 0x30, 0x21, /* SEQUENCE, length 31 */
- 0x30, 0x09, /* SEQUENCE, length 9 */
- 0x06, 0x05, /* OBJECT_ID, length 5 */
- 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* SHA1 OID: 1.3.14.3.2.26 */
- 0x05, 0x00, /* NULL (parameters) */
- 0x04, 0x14, /* OCTET_STRING, length 20 */
- /* followed by the 20-byte sha1 */
- };
- gnutls_datum_t hash;
- unsigned char digest[sizeof(ber_encode) + SHA1_SIZE];
- size_t shalen = SHA1_SIZE;
- int err;
-
- err = gnutls_fingerprint(GNUTLS_DIG_SHA1, data,
- &digest[sizeof(ber_encode)], &shalen);
- if (err) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Failed to SHA1 input data for signing: %s\n"),
- gnutls_strerror(err));
- return err;
- }
-
- memcpy(digest, ber_encode, sizeof(ber_encode));
-
- hash.data = digest;
- hash.size = sizeof(digest);
-
- return tpm_sign_fn(NULL, vpninfo, &hash, sig);
-}
-#endif /* !HAVE_GNUTLS_CERTIFICATE_SET_KEY */
-
static int tpm_sign_fn(gnutls_privkey_t key, void *_vpninfo,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
@@ -258,18 +196,14 @@ int load_tpm_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
goto out_srkpol;
}
-#ifdef HAVE_GNUTLS_CERTIFICATE_SET_KEY
gnutls_privkey_init(pkey);
/* This would be nicer if there was a destructor callback. I could
allocate a data structure with the TPM handles and the vpninfo
pointer, and destroy that properly when the key is destroyed. */
gnutls_privkey_import_ext(*pkey, GNUTLS_PK_RSA, vpninfo, tpm_sign_fn, NULL, 0);
-#else
- *pkey = OPENCONNECT_TPM_PKEY;
-#endif
retry_sign:
- err = sign_dummy_data(vpninfo, *pkey, fdata, pkey_sig);
+ err = gnutls_privkey_sign_data(*pkey, GNUTLS_DIG_SHA1, 0, fdata, pkey_sig);
if (err == GNUTLS_E_INSUFFICIENT_CREDENTIALS) {
if (!vpninfo->tpm_key_policy) {
err = Tspi_Context_CreateObject(vpninfo->tpm_context,
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 67b73f46..9d98590d 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -503,15 +503,6 @@ struct openconnect_info {
TSS_HKEY tpm_key;
TSS_HPOLICY tpm_key_policy;
#endif
-#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
-#ifdef HAVE_P11KIT
- gnutls_pkcs11_privkey_t my_p11key;
-#endif
- gnutls_privkey_t my_pkey;
- gnutls_x509_crt_t *my_certs;
- uint8_t *free_my_certs;
- unsigned int nr_my_certs;
-#endif
#endif /* OPENCONNECT_GNUTLS */
struct pin_cache *pin_cache;
struct keepalive_info ssl_times;
From c47fcd1fdea20d274611a035ca9b59b3d701696b Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 12:40:23 +0100
Subject: [PATCH 018/131] Kill HAVE_GNUTLS_PK_TO_SIGN
Signed-off-by: David Woodhouse
---
configure.ac | 2 --
gnutls.c | 4 ----
2 files changed, 6 deletions(-)
diff --git a/configure.ac b/configure.ac
index 3e39ec1e..138875a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -452,8 +452,6 @@ case "$ssl_library" in
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
esp=yes
dtls=yes
- AC_CHECK_FUNC(gnutls_pk_to_sign,
- [AC_DEFINE(HAVE_GNUTLS_PK_TO_SIGN, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_pubkey_export2,
[AC_DEFINE(HAVE_GNUTLS_PUBKEY_EXPORT2, 1, [From GnuTLS 3.1.3])], [])
AC_CHECK_FUNC(gnutls_x509_crt_set_pin_function,
diff --git a/gnutls.c b/gnutls.c
index 4b9bc956..78232e8c 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -629,16 +629,12 @@ static int assign_privkey(struct openconnect_info *vpninfo,
static int verify_signed_data(gnutls_pubkey_t pubkey, gnutls_privkey_t privkey,
const gnutls_datum_t *data, const gnutls_datum_t *sig)
{
-#ifdef HAVE_GNUTLS_PK_TO_SIGN
gnutls_sign_algorithm_t algo;
algo = gnutls_pk_to_sign(gnutls_privkey_get_pk_algorithm(privkey, NULL),
GNUTLS_DIG_SHA1);
return gnutls_pubkey_verify_data2(pubkey, algo, 0, data, sig);
-#else
- return gnutls_pubkey_verify_data(pubkey, 0, data, sig);
-#endif
}
#endif /* (P11KIT || TROUSERS || SYSTEM_KEYS) */
From 5370e6ffd381f77daad2485479d610f4590e9726 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 12:43:05 +0100
Subject: [PATCH 019/131] Kill HAVE_GNUTLS_PUBKEY_EXPORT2
Signed-off-by: David Woodhouse
---
configure.ac | 2 --
gnutls.c | 34 ++++------------------------------
2 files changed, 4 insertions(+), 32 deletions(-)
diff --git a/configure.ac b/configure.ac
index 138875a0..d3c0eaf4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -452,8 +452,6 @@ case "$ssl_library" in
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
esp=yes
dtls=yes
- AC_CHECK_FUNC(gnutls_pubkey_export2,
- [AC_DEFINE(HAVE_GNUTLS_PUBKEY_EXPORT2, 1, [From GnuTLS 3.1.3])], [])
AC_CHECK_FUNC(gnutls_x509_crt_set_pin_function,
[AC_DEFINE(HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_url_is_supported,
diff --git a/gnutls.c b/gnutls.c
index 78232e8c..6ee1c1f1 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -1838,37 +1838,11 @@ static int set_peer_cert_hash(struct openconnect_info *vpninfo)
return err;
err = gnutls_pubkey_import_x509(pkey, vpninfo->peer_cert, 0);
- if (err) {
- gnutls_pubkey_deinit(pkey);
- return err;
- }
-#ifdef HAVE_GNUTLS_PUBKEY_EXPORT2
- err = gnutls_pubkey_export2(pkey, GNUTLS_X509_FMT_DER, &d);
- if (err) {
- gnutls_pubkey_deinit(pkey);
- return err;
- }
-#else
- shalen = 0;
- err = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_DER, NULL, &shalen);
- if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
- gnutls_pubkey_deinit(pkey);
- return err;
- }
- d.size = shalen;
- d.data = gnutls_malloc(d.size);
- if (!d.data) {
- gnutls_pubkey_deinit(pkey);
- return -ENOMEM;
- }
- err = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_DER, d.data, &shalen);
- if (err) {
- gnutls_free(d.data);
- gnutls_pubkey_deinit(pkey);
- return err;
- }
-#endif
+ if (!err)
+ err = gnutls_pubkey_export2(pkey, GNUTLS_X509_FMT_DER, &d);
gnutls_pubkey_deinit(pkey);
+ if (err)
+ return err;
shalen = sizeof(vpninfo->peer_cert_sha256_raw);
err = gnutls_fingerprint(GNUTLS_DIG_SHA256, &d, vpninfo->peer_cert_sha256_raw, &shalen);
From 61cfb27bd868dfa411cc75b7bcf62b7efd32cd29 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 12:48:46 +0100
Subject: [PATCH 020/131] Kill HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
Signed-off-by: David Woodhouse
---
configure.ac | 2 --
gnutls.c | 99 ++++------------------------------------------------
2 files changed, 6 insertions(+), 95 deletions(-)
diff --git a/configure.ac b/configure.ac
index d3c0eaf4..dab503f6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -452,8 +452,6 @@ case "$ssl_library" in
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
esp=yes
dtls=yes
- AC_CHECK_FUNC(gnutls_x509_crt_set_pin_function,
- [AC_DEFINE(HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_url_is_supported,
[AC_DEFINE(HAVE_GNUTLS_URL_IS_SUPPORTED, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_system_key_add_x509,
diff --git a/gnutls.c b/gnutls.c
index 6ee1c1f1..59a44705 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -48,26 +48,6 @@
static int gnutls_pin_callback(void *priv, int attempt, const char *uri,
const char *token_label, unsigned int flags,
char *pin, size_t pin_max);
-
-#ifndef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
-/* If we don't have this (3.1.0+) then we'll use p11-kit callbacks instead
- * because the old GnuTLS callback was global rather than context-specific,
- * which makes it basically unusable from libopenconnect. The p11-kit
- * callback function is a simple wrapper around the GnuTLS native version. */
-typedef enum {
- GNUTLS_PIN_USER = (1 << 0),
- GNUTLS_PIN_SO = (1 << 1),
- GNUTLS_PIN_FINAL_TRY = (1 << 2),
- GNUTLS_PIN_COUNT_LOW = (1 << 3),
- GNUTLS_PIN_CONTEXT_SPECIFIC = (1 << 4),
- GNUTLS_PIN_WRONG = (1 << 5)
-} gnutls_pin_flag_t;
-
-static P11KitPin *p11kit_pin_callback(const char *pin_source, P11KitUri *pin_uri,
- const char *pin_description,
- P11KitPinFlags flags,
- void *_vpninfo);
-#endif /* !HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION */
#endif /* HAVE_P11KIT || HAVE_GNUTLS_SYSTEM_KEYS */
#include "gnutls.h"
@@ -987,12 +967,6 @@ static int load_certificate(struct openconnect_info *vpninfo)
CK_OBJECT_CLASS class;
CK_ATTRIBUTE attr;
P11KitUri *uri;
-#ifndef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
- char pin_source[40];
-
- sprintf(pin_source, "openconnect:%p", vpninfo);
- p11_kit_pin_register_callback(pin_source, p11kit_pin_callback, vpninfo, NULL);
-#endif
uri = p11_kit_uri_new();
attr.type = CKA_CLASS;
@@ -1003,10 +977,6 @@ static int load_certificate(struct openconnect_info *vpninfo)
both certificate and key URLs, unless they already exist. */
if (cert_is_p11 &&
!p11_kit_uri_parse(cert_url, P11_KIT_URI_FOR_ANY, uri)) {
-#ifndef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
- if (!p11_kit_uri_get_pin_source(uri))
- p11_kit_uri_set_pin_source(uri, pin_source);
-#endif
if (!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
class = CKO_CERTIFICATE;
p11_kit_uri_set_attribute(uri, &attr);
@@ -1016,10 +986,6 @@ static int load_certificate(struct openconnect_info *vpninfo)
if (key_is_p11 &&
!p11_kit_uri_parse(key_url, P11_KIT_URI_FOR_ANY, uri)) {
-#ifndef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
- if (!p11_kit_uri_get_pin_source(uri))
- p11_kit_uri_set_pin_source(uri, pin_source);
-#endif
if (vpninfo->sslkey == vpninfo->cert ||
!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
class = CKO_PRIVATE_KEY;
@@ -1044,9 +1010,9 @@ static int load_certificate(struct openconnect_info *vpninfo)
ret = -ENOMEM;
goto out;
}
-#ifdef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
+
gnutls_x509_crt_set_pin_function(cert, gnutls_pin_callback, vpninfo);
-#endif
+
/* Yes, even for *system* URLs the only API GnuTLS offers us is
...import_pkcs11_url(). */
err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url, 0);
@@ -1151,9 +1117,9 @@ static int load_certificate(struct openconnect_info *vpninfo)
ret = -EIO;
goto out;
}
-#ifdef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
+
gnutls_privkey_set_pin_function(pkey, gnutls_pin_callback, vpninfo);
-#endif
+
err = gnutls_privkey_import_url(pkey, vpninfo->sslkey, 0);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
@@ -1178,9 +1144,9 @@ static int load_certificate(struct openconnect_info *vpninfo)
ret = -EIO;
goto out;
}
-#ifdef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
+
gnutls_pkcs11_privkey_set_pin_function(p11key, gnutls_pin_callback, vpninfo);
-#endif
+
err = gnutls_pkcs11_privkey_import_url(p11key, key_url, 0);
/* Annoyingly, some tokens don't even admit the *existence* of
@@ -2354,14 +2320,6 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
if (final && vpninfo->https_cred) {
gnutls_certificate_free_credentials(vpninfo->https_cred);
vpninfo->https_cred = NULL;
-#if defined(HAVE_P11KIT) && !defined(HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION)
- if ((vpninfo->cert && !strncmp(vpninfo->cert, "pkcs11:", 7)) ||
- (vpninfo->sslkey && !strncmp(vpninfo->sslkey, "pkcs11:", 7))) {
- char pin_source[40];
- sprintf(pin_source, "openconnect:%p", vpninfo);
- p11_kit_pin_unregister_callback(pin_source, p11kit_pin_callback, vpninfo);
- }
-#endif
#ifdef HAVE_TROUSERS
if (vpninfo->tpm_key_policy) {
Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key_policy);
@@ -2660,51 +2618,6 @@ static int gnutls_pin_callback(void *priv, int attempt, const char *uri,
return 0;
}
-
-#ifndef HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION
-static P11KitPin *p11kit_pin_callback(const char *pin_source, P11KitUri *pin_uri,
- const char *pin_description,
- P11KitPinFlags flags,
- void *_vpninfo)
-{
- struct openconnect_info *vpninfo = _vpninfo;
- char *uri;
- P11KitPin *pin = NULL;
- char pin_str[1024];
- unsigned gnutls_flags = 0;
- int attempt = 0;
-
- if (!vpninfo || !vpninfo->process_auth_form)
- return NULL;
-
- if (p11_kit_uri_format(pin_uri, P11_KIT_URI_FOR_TOKEN, &uri))
- return NULL;
-
- /*
- * In p11-kit <= 0.12, these flags are *odd*.
- * RETRY is 0xa, FINAL_TRY is 0x14 and MANY_TRIES is 0x28.
- * So don't treat it like a sane bitmask. Fixed in
- * http://cgit.freedesktop.org/p11-glue/p11-kit/commit/?id=59774b11
- */
- if ((flags & P11_KIT_PIN_FLAGS_RETRY) == P11_KIT_PIN_FLAGS_RETRY) {
- attempt = 1;
- gnutls_flags |= GNUTLS_PIN_WRONG;
- }
- if ((flags & P11_KIT_PIN_FLAGS_FINAL_TRY) == P11_KIT_PIN_FLAGS_FINAL_TRY)
- gnutls_flags |= GNUTLS_PIN_FINAL_TRY;
- if ((flags & P11_KIT_PIN_FLAGS_MANY_TRIES) == P11_KIT_PIN_FLAGS_MANY_TRIES)
- gnutls_flags |= GNUTLS_PIN_COUNT_LOW;
-
- if (!gnutls_pin_callback(vpninfo, attempt, uri, pin_description,
- gnutls_flags, pin_str, sizeof(pin_str)))
- pin = p11_kit_pin_new_for_string(pin_str);
-
- memset(pin_str, 0x5a, sizeof(pin_str));
- free(uri);
-
- return pin;
-}
-#endif /* !HAVE_GNUTLS_X509_CRT_SET_PIN_FUNCTION */
#endif /* HAVE_P11KIT || HAVE_GNUTLS_SYSTEM_KEYS */
#ifdef HAVE_LIBPCSCLITE
From ad094132249c64d3a1d36eab2ec4e1346b2d9a61 Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 12:50:01 +0100
Subject: [PATCH 021/131] Kill HAVE_GNUTLS_URL_IS_SUPPORTED
Signed-off-by: David Woodhouse
---
configure.ac | 2 --
gnutls.c | 6 ------
2 files changed, 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index dab503f6..e1137283 100644
--- a/configure.ac
+++ b/configure.ac
@@ -452,8 +452,6 @@ case "$ssl_library" in
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
esp=yes
dtls=yes
- AC_CHECK_FUNC(gnutls_url_is_supported,
- [AC_DEFINE(HAVE_GNUTLS_URL_IS_SUPPORTED, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_system_key_add_x509,
[AC_DEFINE(HAVE_GNUTLS_SYSTEM_KEYS, 1, [From GnuTLS 3.4.0])], [])
AC_CHECK_FUNC(gnutls_pkcs11_add_provider,
diff --git a/gnutls.c b/gnutls.c
index 59a44705..baf1cd14 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -938,15 +938,9 @@ static int load_certificate(struct openconnect_info *vpninfo)
key_is_p11 = !strncmp(vpninfo->sslkey, "pkcs11:", 7);
cert_is_p11 = !strncmp(vpninfo->cert, "pkcs11:", 7);
-#ifdef HAVE_GNUTLS_URL_IS_SUPPORTED
/* GnuTLS returns true for pkcs11:, tpmkey:, system:, and custom URLs. */
key_is_sys = !key_is_p11 && gnutls_url_is_supported(vpninfo->sslkey);
cert_is_sys = !cert_is_p11 && gnutls_url_is_supported(vpninfo->cert);
-#else
- /* Fallback for GnuTLS < 3.1.0. */
- key_is_sys = !strncmp(vpninfo->sslkey, "system:", 7);
- cert_is_sys = !strncmp(vpninfo->cert, "system:", 7);
-#endif
#ifndef HAVE_GNUTLS_SYSTEM_KEYS
if (key_is_sys || cert_is_sys) {
From 314dafa830c2a28a2411fa2a90efb199144e179f Mon Sep 17 00:00:00 2001
From: David Woodhouse
Date: Mon, 14 Aug 2017 13:21:18 +0100
Subject: [PATCH 022/131] Use LC_ALL for auth-nonascii test, not LC_CTYPE
Mike Miller points out that LC_ALL has precedence over LC_CTYPE, so the
test fails when LC_ALL is set to something different.
Signed-off-by: David Woodhouse
---
tests/auth-nonascii | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/auth-nonascii b/tests/auth-nonascii
index d930b117..1da8de25 100755
--- a/tests/auth-nonascii
+++ b/tests/auth-nonascii
@@ -34,7 +34,7 @@ set -x
for CHARSET in UTF-8 ISO8859-2; do
echo -n "Connecting to obtain cookie (with password charset ${CHARSET})... "
CERTARGS="-c ${KEY} --key-password $(cat ${srcdir}/pass-${CHARSET})"
- ( echo "test" | LC_CTYPE=cs_CZ.${CHARSET} LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT -q $ADDRESS:443 -u test $CERTARGS --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly --passwd-on-stdin ) ||
+ ( echo "test" | LC_ALL=cs_CZ.${CHARSET} LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT -q $ADDRESS:443 -u test $CERTARGS --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly --passwd-on-stdin ) ||
fail $PID "Could not connect with charset ${CHARSET}!"
done
From 76583bb434198dd35195a6a0a13bba15ac2e84c6 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 20 May 2017 15:43:22 -0700
Subject: [PATCH 023/131] factor out common dump_buf_hex() and free_optlist()
utility functions
These will be used in GlobalProtect protocol support, so it makes sense
to factor them out into shared utility functions rather than use slight
variants for each protocol.
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
cstp.c | 16 ++--------------
http.c | 16 ++++++++++++++++
library.c | 3 +--
oncp.c | 36 +++++++++++-------------------------
openconnect-internal.h | 2 ++
5 files changed, 32 insertions(+), 41 deletions(-)
diff --git a/cstp.c b/cstp.c
index 2fd7a62e..5477c5c8 100644
--- a/cstp.c
+++ b/cstp.c
@@ -609,20 +609,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
}
}
- while (old_dtls_opts) {
- struct oc_vpn_option *tmp = old_dtls_opts;
- old_dtls_opts = old_dtls_opts->next;
- free(tmp->value);
- free(tmp->option);
- free(tmp);
- }
- while (old_cstp_opts) {
- struct oc_vpn_option *tmp = old_cstp_opts;
- old_cstp_opts = old_cstp_opts->next;
- free(tmp->value);
- free(tmp->option);
- free(tmp);
- }
+ free_optlist(old_dtls_opts);
+ free_optlist(old_cstp_opts);
vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
vpn_progress(vpninfo, PRG_DEBUG, _("CSTP Ciphersuite: %s\n"),
diff --git a/http.c b/http.c
index 6166bb3a..59f93e50 100644
--- a/http.c
+++ b/http.c
@@ -781,6 +781,22 @@ void dump_buf(struct openconnect_info *vpninfo, char prefix, char *buf)
}
}
+void dump_buf_hex(struct openconnect_info *vpninfo, int loglevel, char prefix, unsigned char *buf, int len)
+{
+ char linebuf[80];
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0) {
+ if (i)
+ vpn_progress(vpninfo, loglevel, "%c %s\n", prefix, linebuf);
+ sprintf(linebuf, "%04x:", i);
+ }
+ sprintf(linebuf + strlen(linebuf), " %02x", buf[i]);
+ }
+ vpn_progress(vpninfo, loglevel, "%c %s\n", prefix, linebuf);
+}
+
/* Inputs:
* method: GET or POST
* vpninfo->hostname: Host DNS name
diff --git a/library.c b/library.c
index 2f0392b6..41e164a2 100644
--- a/library.c
+++ b/library.c
@@ -257,7 +257,7 @@ int openconnect_set_mobile_info(struct openconnect_info *vpninfo,
return 0;
}
-static void free_optlist(struct oc_vpn_option *opt)
+void free_optlist(struct oc_vpn_option *opt)
{
struct oc_vpn_option *next;
@@ -1127,4 +1127,3 @@ int process_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *for
return ret;
}
-
diff --git a/oncp.c b/oncp.c
index 0155f416..59cfa4be 100644
--- a/oncp.c
+++ b/oncp.c
@@ -110,22 +110,6 @@ static void buf_append_tlv_be32(struct oc_text_buf *buf, uint16_t val, uint32_t
buf_append_tlv(buf, val, 4, d);
}
-static void buf_hexdump(struct openconnect_info *vpninfo, unsigned char *d, int len)
-{
- char linebuf[80];
- int i;
-
- for (i = 0; i < len; i++) {
- if (i % 16 == 0) {
- if (i)
- vpn_progress(vpninfo, PRG_DEBUG, "%s\n", linebuf);
- sprintf(linebuf, "%04x:", i);
- }
- sprintf(linebuf + strlen(linebuf), " %02x", d[i]);
- }
- vpn_progress(vpninfo, PRG_DEBUG, "%s\n", linebuf);
-}
-
static const char authpkt_head[] = { 0x00, 0x04, 0x00, 0x00, 0x00 };
static const char authpkt_tail[] = { 0xbb, 0x01, 0x00, 0x00, 0x00, 0x00 };
@@ -503,7 +487,7 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
eparse:
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse KMP message\n"));
- buf_hexdump(vpninfo, bytes, pktlen);
+ dump_buf_hex(vpninfo, PRG_ERR, '<', bytes, pktlen);
return -EINVAL;
}
@@ -663,7 +647,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
ret = buf_error(reqbuf);
goto out;
}
- buf_hexdump(vpninfo, (void *)reqbuf->data, reqbuf->pos);
+ dump_buf_hex(vpninfo, PRG_DEBUG, '>', (void *)reqbuf->data, reqbuf->pos);
ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
if (ret != reqbuf->pos) {
if (ret >= 0) {
@@ -681,7 +665,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
goto out;
vpn_progress(vpninfo, PRG_TRACE,
_("Read %d bytes of SSL record\n"), ret);
-
+
if (ret != 3 || bytes[0] != 1 || bytes[1] != 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Unexpected response of size %d after hostname packet\n"),
@@ -709,7 +693,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
if (len < 0x16 || load_le16(bytes) + 2 != len) {
vpn_progress(vpninfo, PRG_ERR,
_("Invalid packet waiting for KMP 301\n"));
- buf_hexdump(vpninfo, bytes, len);
+ dump_buf_hex(vpninfo, PRG_ERR, '<', bytes, len);
ret = -EINVAL;
goto out;
}
@@ -814,7 +798,8 @@ int oncp_connect(struct openconnect_info *vpninfo)
/* Length at the start of the packet is little-endian */
store_le16(reqbuf->data, reqbuf->pos - 2);
- buf_hexdump(vpninfo, (void *)reqbuf->data, reqbuf->pos);
+ vpn_progress(vpninfo, PRG_DEBUG, _("oNCP negotiation request outgoing:\n"));
+ dump_buf_hex(vpninfo, PRG_DEBUG, '>', (void *)reqbuf->data, reqbuf->pos);
ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
if (ret == reqbuf->pos)
ret = 0;
@@ -1091,8 +1076,8 @@ int oncp_mainloop(struct openconnect_info *vpninfo, int *timeout)
unknown_pkt:
vpn_progress(vpninfo, PRG_ERR,
_("Unknown KMP message %d of size %d:\n"), kmp, kmplen);
- buf_hexdump(vpninfo, vpninfo->cstp_pkt->oncp.kmp,
- vpninfo->cstp_pkt->len);
+ dump_buf_hex(vpninfo, PRG_ERR, '<', vpninfo->cstp_pkt->oncp.kmp,
+ vpninfo->cstp_pkt->len);
if (kmplen + 20 != vpninfo->cstp_pkt->len)
vpn_progress(vpninfo, PRG_DEBUG,
_(".... + %d more bytes unreceived\n"),
@@ -1111,8 +1096,9 @@ int oncp_mainloop(struct openconnect_info *vpninfo, int *timeout)
unmonitor_write_fd(vpninfo, ssl);
vpn_progress(vpninfo, PRG_TRACE, _("Packet outgoing:\n"));
- buf_hexdump(vpninfo, vpninfo->current_ssl_pkt->oncp.rec,
- vpninfo->current_ssl_pkt->len + 22);
+ dump_buf_hex(vpninfo, PRG_TRACE, '>',
+ vpninfo->current_ssl_pkt->oncp.rec,
+ vpninfo->current_ssl_pkt->len + 22);
ret = ssl_nonblock_write(vpninfo,
vpninfo->current_ssl_pkt->oncp.rec,
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 9d98590d..f8f92492 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -995,6 +995,7 @@ int can_gen_tokencode(struct openconnect_info *vpninfo,
/* http.c */
struct oc_text_buf *buf_alloc(void);
void dump_buf(struct openconnect_info *vpninfo, char prefix, char *buf);
+void dump_buf_hex(struct openconnect_info *vpninfo, int loglevel, char prefix, unsigned char *buf, int len);
int buf_ensure_space(struct oc_text_buf *buf, int len);
void __attribute__ ((format (printf, 2, 3)))
buf_append(struct oc_text_buf *buf, const char *fmt, ...);
@@ -1045,6 +1046,7 @@ int digest_authorization(struct openconnect_info *vpninfo, int proxy, struct htt
/* library.c */
void nuke_opt_values(struct oc_form_opt *opt);
+void free_optlist(struct oc_vpn_option *opt);
int process_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *form);
/* This is private for now since we haven't yet worked out what the API will be */
void openconnect_set_juniper(struct openconnect_info *vpninfo);
From 342a85bf8b49165dddeb679a1d4abd55afca89e3 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 14 Jun 2017 15:54:56 -0700
Subject: [PATCH 024/131] relax requirements for Juniper hostname packet
response
This fixes the "Unexpected response of size 3 after hostname packet" or "Invalid packet waiting for KMP 301" errors
which I get intermittently when connecting to an old Juniper NC server:
$ openconnect --prot=nc -vvvv
...
NCP-Version: 2
...
> 0000: 18 00 00 04 00 00 00 0c 00 64 65 61 64 62 65 65
> 0010: 66 2d 31 32 33 bb 01 00 00 00 00
Read 3 bytes of SSL record
< 0000: d2 01 00
Read 465 bytes of SSL record
Here's what is going on: this server is (sometimes) concatenating the 3-byte
response packet together with the longer IP-configuration packet that
follows. When they are concatenated together, the server sends only a
single 2-byte length prefix for both (0x01d2 = 466).
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
oncp.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/oncp.c b/oncp.c
index 59cfa4be..38673c7c 100644
--- a/oncp.c
+++ b/oncp.c
@@ -540,7 +540,7 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
int oncp_connect(struct openconnect_info *vpninfo)
{
- int ret, len, kmp, kmplen, group;
+ int ret, len, kmp, kmplen, group, check_len;
struct oc_text_buf *reqbuf;
unsigned char bytes[16384];
@@ -661,12 +661,14 @@ int oncp_connect(struct openconnect_info *vpninfo)
/* Now we expect a three-byte response with what's presumably an
error code */
ret = vpninfo->ssl_read(vpninfo, (void *)bytes, 3);
+ check_len = load_le16(bytes);
if (ret < 0)
goto out;
vpn_progress(vpninfo, PRG_TRACE,
_("Read %d bytes of SSL record\n"), ret);
+ dump_buf_hex(vpninfo, PRG_TRACE, '<', (void *)bytes, ret);
- if (ret != 3 || bytes[0] != 1 || bytes[1] != 0) {
+ if (ret != 3 || check_len < 1) {
vpn_progress(vpninfo, PRG_ERR,
_("Unexpected response of size %d after hostname packet\n"),
ret);
@@ -681,8 +683,18 @@ int oncp_connect(struct openconnect_info *vpninfo)
goto out;
}
- /* And then a KMP message 301 with the IP configuration */
- len = vpninfo->ssl_read(vpninfo, (void *)bytes, sizeof(bytes));
+ /* And then a KMP message 301 with the IP configuration.
+ * Sometimes this arrives as a separate SSL record (with its own
+ * 2-byte length prefix), and sometimes concatenated with the
+ * previous 3-byte response).
+ */
+ if (check_len == 1) {
+ len = vpninfo->ssl_read(vpninfo, (void *)bytes, sizeof(bytes));
+ check_len = load_le16(bytes);
+ } else {
+ len = vpninfo->ssl_read(vpninfo, (void *)(bytes+2), sizeof(bytes)-2) + 2;
+ check_len--;
+ }
if (len < 0) {
ret = len;
goto out;
@@ -690,7 +702,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
vpn_progress(vpninfo, PRG_TRACE,
_("Read %d bytes of SSL record\n"), len);
- if (len < 0x16 || load_le16(bytes) + 2 != len) {
+ if (len < 0x16 || check_len + 2 != len) {
vpn_progress(vpninfo, PRG_ERR,
_("Invalid packet waiting for KMP 301\n"));
dump_buf_hex(vpninfo, PRG_ERR, '<', bytes, len);
From cc6af8dd5818bde5a8fbaf23677da6c6ddf63238 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 20 May 2017 15:43:25 -0700
Subject: [PATCH 025/131] tweak the dtls_state handling in preparation for
supporting GlobalProtect ESP
If a protocol wishes to have dtls_state set to DTLS_SLEEPING after closing
UDP, then it must now do so explicitly, because the mainloop will no longer
set it. This patch make both existing protocols set dtls_state explicitly
after closing the UDP connection. (The nc protocol already did so
explicitly, but the anyconnect protocol didn't.)
The previous behavior, wherein dtls_state was *always* set to DTLS_SLEEPING
after closing UDP, was incompatible with the GlobalProtect VPN.
Disconnecting and reconnecting GlobalProtect VPN doesn't just require
require reconnecting the UDP socket and resending probes; it actually
invalidates any previously-obtained ESP secret.
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
dtls.c | 1 +
mainloop.c | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/dtls.c b/dtls.c
index c97d14d1..80d6c05a 100644
--- a/dtls.c
+++ b/dtls.c
@@ -169,6 +169,7 @@ void dtls_close(struct openconnect_info *vpninfo)
vpninfo->dtls_ssl = NULL;
vpninfo->dtls_fd = -1;
}
+ vpninfo->dtls_state = DTLS_SLEEPING;
}
static int dtls_reconnect(struct openconnect_info *vpninfo)
diff --git a/mainloop.c b/mainloop.c
index cc80d0e2..41245096 100644
--- a/mainloop.c
+++ b/mainloop.c
@@ -258,7 +258,6 @@ int openconnect_mainloop(struct openconnect_info *vpninfo,
openconnect_close_https(vpninfo, 0);
if (vpninfo->dtls_state > DTLS_DISABLED) {
vpninfo->proto->udp_close(vpninfo);
- vpninfo->dtls_state = DTLS_SLEEPING;
vpninfo->new_dtls_started = 0;
}
From 5cd81d7524552f0ac315f0bd86c65dbdabcbebbf Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 20 May 2017 15:43:26 -0700
Subject: [PATCH 026/131] add vpn_proto member functions .udp_send_probes and
.udp_catch_probe in preparation for supporting GlobalProtect ESP
The existing Juniper ESP code can be almost entirely reused for
GlobalProtect ESP, except for the Juniper-specific code for sending and
recognizing the probe packets used for ESP initiation and DPD.
The Juniper-specific code is moved into functions names esp_send_probes
(sends Juniper probe packets) and esp_catch_probe (recognizes Juniper probe
packet responses), which are called via vpn_proto member functions.
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
esp.c | 35 +++++++++++++++++++++++------------
library.c | 2 ++
openconnect-internal.h | 8 ++++++++
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/esp.c b/esp.c
index 5b038c45..f705aa3e 100644
--- a/esp.c
+++ b/esp.c
@@ -71,7 +71,7 @@ int print_esp_keys(struct openconnect_info *vpninfo, const char *name, struct es
return 0;
}
-static int esp_send_probes(struct openconnect_info *vpninfo)
+int esp_send_probes(struct openconnect_info *vpninfo)
{
struct pkt *pkt;
int pktlen;
@@ -112,6 +112,11 @@ static int esp_send_probes(struct openconnect_info *vpninfo)
return 0;
};
+int esp_catch_probe(struct openconnect_info *vpninfo, struct pkt *pkt)
+{
+ return (pkt->len == 1 && pkt->data[0] == 0);
+}
+
int esp_setup(struct openconnect_info *vpninfo, int dtls_attempt_period)
{
if (vpninfo->dtls_state == DTLS_DISABLED ||
@@ -129,7 +134,8 @@ int esp_setup(struct openconnect_info *vpninfo, int dtls_attempt_period)
print_esp_keys(vpninfo, _("outgoing"), &vpninfo->esp_out);
vpn_progress(vpninfo, PRG_DEBUG, _("Send ESP probes\n"));
- esp_send_probes(vpninfo);
+ if (vpninfo->proto->udp_send_probes)
+ vpninfo->proto->udp_send_probes(vpninfo);
return 0;
}
@@ -146,7 +152,8 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
int when = vpninfo->new_dtls_started + vpninfo->dtls_attempt_period - time(NULL);
if (when <= 0 || vpninfo->dtls_need_reconnect) {
vpn_progress(vpninfo, PRG_DEBUG, _("Send ESP probes\n"));
- esp_send_probes(vpninfo);
+ if (vpninfo->proto->udp_send_probes)
+ vpninfo->proto->udp_send_probes(vpninfo);
when = vpninfo->dtls_attempt_period;
}
if (*timeout > when * 1000)
@@ -226,14 +233,16 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
}
vpninfo->dtls_times.last_rx = time(NULL);
- if (pkt->len == 1 && pkt->data[0] == 0) {
- if (vpninfo->dtls_state == DTLS_SLEEPING) {
- vpn_progress(vpninfo, PRG_INFO,
- _("ESP session established with server\n"));
- queue_esp_control(vpninfo, 1);
- vpninfo->dtls_state = DTLS_CONNECTING;
+ if (vpninfo->proto->udp_catch_probe) {
+ if (vpninfo->proto->udp_catch_probe(vpninfo, pkt)) {
+ if (vpninfo->dtls_state == DTLS_SLEEPING) {
+ vpn_progress(vpninfo, PRG_INFO,
+ _("ESP session established with server\n"));
+ queue_esp_control(vpninfo, 1);
+ vpninfo->dtls_state = DTLS_CONNECTING;
+ }
+ continue;
}
- continue;
}
if (pkt->data[len - 1] == 0x05) {
struct pkt *newpkt = malloc(sizeof(*pkt) + vpninfo->ip_info.mtu + vpninfo->pkt_trailer);
@@ -273,12 +282,14 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
vpn_progress(vpninfo, PRG_ERR, _("ESP detected dead peer\n"));
queue_esp_control(vpninfo, 0);
esp_close(vpninfo);
- esp_send_probes(vpninfo);
+ if (vpninfo->proto->udp_send_probes)
+ vpninfo->proto->udp_send_probes(vpninfo);
return 1;
case KA_DPD:
vpn_progress(vpninfo, PRG_DEBUG, _("Send ESP probes for DPD\n"));
- esp_send_probes(vpninfo);
+ if (vpninfo->proto->udp_send_probes)
+ vpninfo->proto->udp_send_probes(vpninfo);
work_done = 1;
break;
diff --git a/library.c b/library.c
index 41e164a2..daa1f01d 100644
--- a/library.c
+++ b/library.c
@@ -138,6 +138,8 @@ const struct vpn_proto openconnect_protos[] = {
.udp_mainloop = esp_mainloop,
.udp_close = esp_close,
.udp_shutdown = esp_shutdown,
+ .udp_send_probes = esp_send_probes,
+ .udp_catch_probe = esp_catch_probe,
#endif
},
{ /* NULL */ }
diff --git a/openconnect-internal.h b/openconnect-internal.h
index f8f92492..933f78c2 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -282,6 +282,12 @@ struct vpn_proto {
/* Close and destroy the (UDP) session */
void (*udp_shutdown)(struct openconnect_info *vpninfo);
+
+ /* Send probe packets to start or maintain the (UDP) session */
+ int (*udp_send_probes)(struct openconnect_info *vpninfo);
+
+ /* Catch probe packet confirming the (UDP) session */
+ int (*udp_catch_probe)(struct openconnect_info *vpninfo, struct pkt *p);
};
struct pkt_q {
@@ -895,6 +901,8 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout);
void esp_close(struct openconnect_info *vpninfo);
void esp_shutdown(struct openconnect_info *vpninfo);
int print_esp_keys(struct openconnect_info *vpninfo, const char *name, struct esp *esp);
+int esp_send_probes(struct openconnect_info *vpninfo);
+int esp_catch_probe(struct openconnect_info *vpninfo, struct pkt *pkt);
/* {gnutls,openssl}-esp.c */
int setup_esp_keys(struct openconnect_info *vpninfo);
From 0ca5974685c0d599e26805f0684ade19b0712718 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 20 May 2017 15:43:27 -0700
Subject: [PATCH 027/131] add new_keys argument to esp_setup_keys() in
preparation for supporting GlobalProtect ESP
The existing ESP key setup code can be almost entirely reused for
GlobalProtect ESP, except for the fact that esp_setup_keys() always
overwrites the secret keys with new random keys.
Since GlobalProtect ESP always uses keys provided by the server, a new
argument is added to esp_setup_keys() to make this behavior optional.
The Juniper-specific code in oncp.c calls it with new_keys=1 in order
to explicitly request it.
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
gnutls-esp.c | 23 ++++++++++++++---------
oncp.c | 4 ++--
openconnect-internal.h | 2 +-
openssl-esp.c | 27 ++++++++++++++++-----------
4 files changed, 33 insertions(+), 23 deletions(-)
diff --git a/gnutls-esp.c b/gnutls-esp.c
index f3fd499c..916cbc7c 100644
--- a/gnutls-esp.c
+++ b/gnutls-esp.c
@@ -72,7 +72,7 @@ static int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp,
return 0;
}
-int setup_esp_keys(struct openconnect_info *vpninfo)
+int setup_esp_keys(struct openconnect_info *vpninfo, int new_keys)
{
struct esp *esp_in;
gnutls_mac_algorithm_t macalg;
@@ -106,17 +106,22 @@ int setup_esp_keys(struct openconnect_info *vpninfo)
return -EINVAL;
}
- vpninfo->old_esp_maxseq = vpninfo->esp_in[vpninfo->current_esp_in].seq + 32;
- vpninfo->current_esp_in ^= 1;
+ if (new_keys) {
+ vpninfo->old_esp_maxseq = vpninfo->esp_in[vpninfo->current_esp_in].seq + 32;
+ vpninfo->current_esp_in ^= 1;
+ }
+
esp_in = &vpninfo->esp_in[vpninfo->current_esp_in];
- if ((ret = gnutls_rnd(GNUTLS_RND_NONCE, &esp_in->spi, sizeof(esp_in->spi))) ||
+ if (new_keys) {
+ if ((ret = gnutls_rnd(GNUTLS_RND_NONCE, &esp_in->spi, sizeof(esp_in->spi))) ||
(ret = gnutls_rnd(GNUTLS_RND_RANDOM, &esp_in->enc_key, vpninfo->enc_key_len)) ||
(ret = gnutls_rnd(GNUTLS_RND_RANDOM, &esp_in->hmac_key, vpninfo->hmac_key_len)) ) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Failed to generate random keys for ESP: %s\n"),
- gnutls_strerror(ret));
- return -EIO;
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Failed to generate random keys for ESP: %s\n"),
+ gnutls_strerror(ret));
+ return -EIO;
+ }
}
ret = init_esp_ciphers(vpninfo, &vpninfo->esp_out, macalg, encalg);
@@ -197,7 +202,7 @@ int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt)
pkt->data[pkt->len + i] = i + 1;
pkt->data[pkt->len + padlen] = padlen;
pkt->data[pkt->len + padlen + 1] = 0x04; /* Legacy IP */
-
+
gnutls_cipher_set_iv(vpninfo->esp_out.cipher, pkt->esp.iv, sizeof(pkt->esp.iv));
err = gnutls_cipher_encrypt(vpninfo->esp_out.cipher, pkt->data, pkt->len + padlen + 2);
if (err) {
diff --git a/oncp.c b/oncp.c
index 38673c7c..17853af9 100644
--- a/oncp.c
+++ b/oncp.c
@@ -789,7 +789,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
put_len16(reqbuf, kmp);
#ifdef HAVE_ESP
- if (!setup_esp_keys(vpninfo)) {
+ if (!setup_esp_keys(vpninfo, 1)) {
struct esp *esp = &vpninfo->esp_in[vpninfo->current_esp_in];
/* Since we'll want to do this in the oncp_mainloop too, where it's easier
* *not* to have an oc_text_buf and build it up manually, and since it's
@@ -843,7 +843,7 @@ static int oncp_receive_espkeys(struct openconnect_info *vpninfo, int len)
int ret;
ret = parse_conf_pkt(vpninfo, vpninfo->cstp_pkt->oncp.kmp, len + 20, 301);
- if (!ret && !setup_esp_keys(vpninfo)) {
+ if (!ret && !setup_esp_keys(vpninfo, 1)) {
struct esp *esp = &vpninfo->esp_in[vpninfo->current_esp_in];
unsigned char *p = vpninfo->cstp_pkt->oncp.kmp;
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 933f78c2..b70085d2 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -905,7 +905,7 @@ int esp_send_probes(struct openconnect_info *vpninfo);
int esp_catch_probe(struct openconnect_info *vpninfo, struct pkt *pkt);
/* {gnutls,openssl}-esp.c */
-int setup_esp_keys(struct openconnect_info *vpninfo);
+int setup_esp_keys(struct openconnect_info *vpninfo, int new_keys);
void destroy_esp_ciphers(struct esp *esp);
int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct pkt *pkt);
int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt);
diff --git a/openssl-esp.c b/openssl-esp.c
index 14228ef0..c3dff510 100644
--- a/openssl-esp.c
+++ b/openssl-esp.c
@@ -112,7 +112,7 @@ static int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp,
return 0;
}
-int setup_esp_keys(struct openconnect_info *vpninfo)
+int setup_esp_keys(struct openconnect_info *vpninfo, int new_keys)
{
struct esp *esp_in;
const EVP_CIPHER *encalg;
@@ -146,17 +146,22 @@ int setup_esp_keys(struct openconnect_info *vpninfo)
return -EINVAL;
}
- vpninfo->old_esp_maxseq = vpninfo->esp_in[vpninfo->current_esp_in].seq + 32;
- vpninfo->current_esp_in ^= 1;
+ if (new_keys) {
+ vpninfo->old_esp_maxseq = vpninfo->esp_in[vpninfo->current_esp_in].seq + 32;
+ vpninfo->current_esp_in ^= 1;
+ }
+
esp_in = &vpninfo->esp_in[vpninfo->current_esp_in];
- if (!RAND_bytes((void *)&esp_in->spi, sizeof(esp_in->spi)) ||
- !RAND_bytes((void *)&esp_in->enc_key, vpninfo->enc_key_len) ||
- !RAND_bytes((void *)&esp_in->hmac_key, vpninfo->hmac_key_len) ) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Failed to generate random keys for ESP:\n"));
- openconnect_report_ssl_errors(vpninfo);
- return -EIO;
+ if (new_keys) {
+ if (!RAND_bytes((void *)&esp_in->spi, sizeof(esp_in->spi)) ||
+ !RAND_bytes((void *)&esp_in->enc_key, vpninfo->enc_key_len) ||
+ !RAND_bytes((void *)&esp_in->hmac_key, vpninfo->hmac_key_len) ) {
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Failed to generate random keys for ESP:\n"));
+ openconnect_report_ssl_errors(vpninfo);
+ return -EIO;
+ }
}
ret = init_esp_ciphers(vpninfo, &vpninfo->esp_out, macalg, encalg, 0);
@@ -242,7 +247,7 @@ int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt)
pkt->data[pkt->len + i] = i + 1;
pkt->data[pkt->len + padlen] = padlen;
pkt->data[pkt->len + padlen + 1] = 0x04; /* Legacy IP */
-
+
if (!EVP_EncryptInit_ex(vpninfo->esp_out.cipher, NULL, NULL, NULL,
pkt->esp.iv)) {
vpn_progress(vpninfo, PRG_ERR,
From 91c81882673880e7a3c3cf009f354db6335d7a0e Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 21 Jun 2017 11:23:52 -0700
Subject: [PATCH 028/131] try alternate vpnc-script location (used by
Debian-based distros)
This patch checks for the vpnc-script in the location used by
the standard vpnc-script package on Debian- and Ubuntu-based
Linux systems, /usr/share/vpnc-scripts/vpnc-script, in addition
to the standard /etc/vpnc/vpnc-script.
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
configure.ac | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index e1137283..0762b06c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,10 +76,15 @@ AC_ARG_WITH([vpnc-script],
[default location of vpnc-script helper])])
if test "$with_vpnc_script" = "yes" || test "$with_vpnc_script" = ""; then
+ AC_MSG_CHECKING([for vpnc-script in standard locations])
if test "$have_win" = "yes"; then
with_vpnc_script=vpnc-script-win.js
else
- with_vpnc_script=/etc/vpnc/vpnc-script
+ for with_vpnc_script in /usr/share/vpnc-scripts/vpnc-script /etc/vpnc/vpnc-script; do
+ if test -x "$with_vpnc_script"; then
+ break
+ fi
+ done
if ! test -x "$with_vpnc_script"; then
AC_MSG_ERROR([${with_vpnc_script} does not seem to be executable.]
[OpenConnect will not function correctly without a vpnc-script.]
@@ -95,7 +100,9 @@ if test "$with_vpnc_script" = "yes" || test "$with_vpnc_script" = ""; then
[build OpenConnect to use the script from this location, even though it is]
[not present at the time you are building OpenConnect, pass the argument]
["--with-vpnc-script=${with_vpnc_script}"])
- fi
+ else
+ AC_MSG_RESULT([${with_vpnc_script}])
+ fi
fi
elif test "$with_vpnc_script" = "no"; then
AC_ERROR([You cannot disable vpnc-script.]
From 3f2c75398eacac1b6e4d1ee91c8551ff631eaf4b Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 14 Aug 2017 10:11:42 -0700
Subject: [PATCH 029/131] print password expiration, if sent by GlobalProtect
server
(great detective work by @kamazee in a follow-up to #50)
---
auth-globalprotect.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 29ea90b2..d6ca44cb 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -79,7 +79,7 @@ static const struct gp_login_arg gp_login_args[] = {
[10] = { .opt="unknown-arg10", .show=1 },
[11] = { .opt="unknown-arg11", .show=1 },
[12] = { .opt="connection-type", .err_missing=1, .check="tunnel" },
- [13] = { .opt="minus1", .err_missing=1 },
+ [13] = { .opt="password-expiration-days", .show=1 }, /* days until password expires, if not -1 */
[14] = { .opt="clientVer", .err_missing=1, .check="4100" },
[15] = { .opt="preferred-ip", .save=1 },
};
@@ -109,7 +109,7 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
goto err_out;
else {
value = (const char *)xmlNodeGetContent(xml_node);
- if (value && (!strlen(value) || !strcmp(value, "(null)"))) {
+ if (value && (!strlen(value) || !strcmp(value, "(null)") || !strcmp(value, "-1"))) {
free((void *)value);
value = NULL;
}
From a21e4fc821bf1b659f61c51f5d2e1fd5288e325b Mon Sep 17 00:00:00 2001
From: David Moss
Date: Thu, 7 Sep 2017 06:56:47 -0600
Subject: [PATCH 030/131] Update README.md for missing Linux build step
Update README.md to include missing "make install" step
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 24b50a17..69de4ea9 100644
--- a/README.md
+++ b/README.md
@@ -50,6 +50,7 @@ $ git checkout globalprotect
$ ./autogen.sh
$ ./configure
$ make
+$ make install
```
### Building on the Mac
From c49d46f0a69082d8f402c4a4675e021b481fbcad Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 3 Oct 2017 11:21:24 -0700
Subject: [PATCH 031/131] update README instructions for Deb/Ubuntu builds
based on @kozzztik's PR
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 69de4ea9..fe2d3fe3 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,9 @@ Please refer to the [build requirements for the official releases of OpenConnect
Under Debian-based or Ubuntu-based distributions, this should install the requirements:
```sh
-$ sudo apt-get install build-essential autoconf automake libgnutls-dev libproxy-dev libxml2-dev libtool vpnc-scripts
+$ sudo apt-get install build-essential gettext autoconf automake libproxy-dev libxml2-dev libtool vpnc-scripts \
+ libgnutls-dev # may be named libgnutls28-dev on some recent Debian/Ubuntu-based distros
+
```
Once you have all the build dependencies installed, checkout and build the `globalprotect` branch from this repository.
From 7b86b5f8024953ef006b653e126e2d6f568e2b75 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 11 Oct 2017 16:15:46 -0500
Subject: [PATCH 032/131] README: add ToC and remove obsolete PPA
---
README.md | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index fe2d3fe3..2ee366dc 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,15 @@
+# OpenConnect with PAN GlobalProtect support
+
+# Table of Contents
+
+ * [What is this?](#what-is-this)
+ * [Feedback and troubleshooting](#feedback-and-troubleshooting)
+ * [Installation](#installation)
+ * [Building from source on Linux](#building-from-source-on-linux)
+ * [Building on the Mac](#building-on-the-mac)
+ * [Connecting](#connecting)
+ * [Portal vs. gateway servers](#portal-vs-gateway-servers)
+
# What is this?
This is a modified version of the fantastic open-source VPN client
@@ -27,10 +39,6 @@ report.
## Installation
-### Ubuntu
-
-Ubuntu 16.04 users can install from [this PPA](https://launchpad.net/~lenski/+archive/ubuntu/openconnect-gp).
-
### Building from source on Linux
Please refer to the [build requirements for the official releases of OpenConnect](http://www.infradead.org/openconnect/building.html). **This version has the exact same build dependencies as OpenConnect v7.06**; modern versions of `autoconf`, `automake`, `gcc`, `libxml`, etc.
From 1431da173ba7aee596c0c3929ea6bc0603056769 Mon Sep 17 00:00:00 2001
From: Dan Lenski
Date: Wed, 25 Oct 2017 18:42:15 -0700
Subject: [PATCH 033/131] all right, adding `pkg-config` to Debian/Ubuntu build
dependencies
per comments by @ljani and @robertwessen on #3
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2ee366dc..1ccfdd47 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ Please refer to the [build requirements for the official releases of OpenConnect
Under Debian-based or Ubuntu-based distributions, this should install the requirements:
```sh
-$ sudo apt-get install build-essential gettext autoconf automake libproxy-dev libxml2-dev libtool vpnc-scripts \
+$ sudo apt-get install build-essential gettext autoconf automake libproxy-dev libxml2-dev libtool vpnc-scripts pkg-config \
libgnutls-dev # may be named libgnutls28-dev on some recent Debian/Ubuntu-based distros
```
From 5026439c6d66149817fdaecb1fe0bf59cce4e4d9 Mon Sep 17 00:00:00 2001
From: videlanicolas
Date: Tue, 31 Oct 2017 11:28:46 -0300
Subject: [PATCH 034/131] Create spoofer.py
Script to spoof hip reports.
---
spoofer.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 spoofer.py
diff --git a/spoofer.py b/spoofer.py
new file mode 100644
index 00000000..ca0eca0a
--- /dev/null
+++ b/spoofer.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+import argparse
+from requests import post
+
+class spoofer():
+ def __init__(self,gateway,cookie,user,portal,ip,computer):
+ self.gateway = gateway
+ self.cookie = cookie
+ self.user = user
+ self.portal = portal
+ self.ip = ip
+ self.computer = computer
+ self.headers = {
+ 'Accept' : '*/*',
+ 'Connection' : 'Keep-Alive',
+ 'Content-Type' : 'application/x-www-form-urlencoded',
+ 'User-Agent' : 'PAN GlobalProtect'
+ }
+ def send_hip_report(self,hip):
+ with open(hip) as f:
+ h = f.read()
+ data = {
+ 'user' : self.user,
+ 'domain' : 'ml',
+ 'portal' : self.portal,
+ 'authcookie' : self.cookie,
+ 'client-ip' : self.ip,
+ 'computer' : self.computer,
+ 'client-role' : 'global-protect-full',
+ 'report' : h
+ }
+ r = post('https://'+self.gateway+'/ssl-vpn/hipreport.esp',headers=self.headers,verify=False,data=data)
+ if 'success' in r.text:
+ return True
+ else:
+ print r.request.body
+ print r.text
+ return False
+ def check_hip(self,digest):
+ data = {
+ 'user' : self.user,
+ 'domain' : 'ml',
+ 'portal' : self.portal,
+ 'authcookie' : self.cookie,
+ 'client-ip' : self.ip,
+ 'computer' : self.computer,
+ 'client-role' : 'global-protect-full',
+ 'md5' : digest
+ }
+ r = post('https://'+self.gateway+'/ssl-vpn/hipreportcheck.esp',headers=self.headers,verify=False,data=data)
+ if 'success' in r.text:
+ return True
+ else:
+ print r.text
+ return False
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Globalprotect HIP spoofer.')
+ parser.add_argument('-c','--cookie', required=True, help='Cookie value(32 characters).')
+ parser.add_argument('-u','--user', required=True, help='User.')
+ parser.add_argument('-i','--ip', required=True, help='IP.')
+ parser.add_argument('-p','--computer', required=True, help='Computer.')
+ parser.add_argument('-o','--portal', required=True, help='Portal name.')
+ parser.add_argument('-g','--gateway', required=True, help='Gateway.')
+ parser.add_argument('-f','--hip', required=True, help='HIP file.')
+ args = parser.parse_args()
+ if len(args.cookie) != 32:
+ print "Cookie must have 32 characters!"
+ quit(1)
+ s = spoofer(gateway=args.gateway,cookie=args.cookie,user=args.user,portal=args.portal,ip=args.ip,computer=args.computer)
+ s.check_hip('1')
+ if s.send_hip_report(args.hip):
+ print "HIP spoofed!"
+ quit()
+ else:
+ print "Error spoofing HIP!"
+ quit(1)
From aa2a0510f260da28f11344194fe1c7085b76dd91 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 31 Oct 2017 21:30:08 -0700
Subject: [PATCH 035/131] add HIP report check as part of config process
---
digest.c | 2 +-
gpst.c | 73 ++++++++++++++++++++++++++++++++++++++++++
openconnect-internal.h | 1 +
3 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/digest.c b/digest.c
index 06dca75b..6a481cbf 100644
--- a/digest.c
+++ b/digest.c
@@ -64,7 +64,7 @@ static void buf_append_unq(struct oc_text_buf *buf, const char *str)
}
}
-static void buf_append_md5(struct oc_text_buf *buf, void *data, int len)
+void buf_append_md5(struct oc_text_buf *buf, void *data, int len)
{
unsigned char md5[16];
diff --git a/gpst.c b/gpst.c
index 44fec7eb..787f2238 100644
--- a/gpst.c
+++ b/gpst.c
@@ -612,6 +612,74 @@ static int gpst_connect(struct openconnect_info *vpninfo)
return ret;
}
+static int parse_hip_report_check(struct openconnect_info *vpninfo, xmlNode *xml_node)
+{
+ const char *s;
+
+ if (!xml_node || !xmlnode_is_named(xml_node, "response"))
+ return -EINVAL;
+
+ for (xml_node = xml_node->children; xml_node; xml_node=xml_node->next) {
+ if (!xmlnode_get_text(xml_node, "hip-report-needed", &s)) {
+ if (!strcmp(s, "no")) {
+ free((void *)s);
+ return 0;
+ } else if (!strcmp(s, "yes")) {
+ free((void *)s);
+ return -EAGAIN;
+ } else
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int gpst_hip_report_check(struct openconnect_info *vpninfo)
+{
+ int result;
+
+ struct oc_text_buf *request_body = buf_alloc();
+ const char *request_body_type = "application/x-www-form-urlencoded";
+ const char *method = "POST";
+ char *xml_buf=NULL, *orig_path, *orig_ua;
+
+ buf_truncate(request_body);
+
+ /* submit HIP report check (ssl-vpn/hipreportcheck.esp) request */
+ /* cookie gives us these fields: authcookie, portal, user, domain, and (maybe the unnecessary) preferred-ip */
+ buf_truncate(request_body);
+ buf_append(request_body, "%s", vpninfo->cookie);
+ append_opt(request_body, "computer", vpninfo->localname);
+ buf_append(request_body, "&client-role=global-protect-full&md5=");
+ buf_append_md5(request_body, request_body->data, request_body->pos); /* hash up everything we've got so far */
+ append_opt(request_body, "client-ip", vpninfo->ip_info.addr);
+
+ orig_path = vpninfo->urlpath;
+ orig_ua = vpninfo->useragent;
+ vpninfo->useragent = (char *)"PAN GlobalProtect";
+ vpninfo->urlpath = strdup("ssl-vpn/hipreportcheck.esp");
+ result = do_https_request(vpninfo, method, request_body_type, request_body,
+ &xml_buf, 0);
+ free(vpninfo->urlpath);
+ vpninfo->urlpath = orig_path;
+ vpninfo->useragent = orig_ua;
+
+ /* Result could be either a JavaScript challenge or XML */
+ result = gpst_xml_or_error(vpninfo, result, xml_buf, parse_hip_report_check, NULL, NULL);
+ if (result == -EAGAIN) {
+ vpn_progress(vpninfo, PRG_DEBUG,
+ _("Gateway says HIP report submission is needed.\n"));
+ result = 0; /* FIXME */
+ } else if (result == 0)
+ vpn_progress(vpninfo, PRG_DEBUG,
+ _("Gateway says no HIP report submission is needed.\n"));
+
+ buf_free(request_body);
+ free(xml_buf);
+ return result;
+}
+
int gpst_setup(struct openconnect_info *vpninfo)
{
int ret;
@@ -621,6 +689,11 @@ int gpst_setup(struct openconnect_info *vpninfo)
if (ret)
return ret;
+ /* Check HIP */
+ ret = gpst_hip_report_check(vpninfo);
+ if (ret)
+ return ret;
+
/* We do NOT actually start the HTTPS tunnel yet if we want to
* use ESP, because the ESP tunnel won't work if the HTTPS tunnel
* is connected! >:-(
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 3526ce6a..923d5a10 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -1071,6 +1071,7 @@ int socks_gssapi_auth(struct openconnect_info *vpninfo);
/* digest.c */
int digest_authorization(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state, struct oc_text_buf *buf);
+void buf_append_md5(struct oc_text_buf *buf, void *data, int len);
/* library.c */
void nuke_opt_values(struct oc_form_opt *opt);
From f4e8c982f0ed718bbe2c479cf4d345ff8e42153a Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 31 Oct 2017 21:31:22 -0700
Subject: [PATCH 036/131] make spoofer.py really dumb and simple like
get-globalprotect-config.py
---
spoofer.py | 131 ++++++++++++++++++++++++-----------------------------
1 file changed, 58 insertions(+), 73 deletions(-)
mode change 100644 => 100755 spoofer.py
diff --git a/spoofer.py b/spoofer.py
old mode 100644
new mode 100755
index ca0eca0a..920879e5
--- a/spoofer.py
+++ b/spoofer.py
@@ -1,77 +1,62 @@
#!/usr/bin/python
+
+from __future__ import print_function
+import requests
import argparse
-from requests import post
+import os
+from sys import stderr, exit
+
+p = argparse.ArgumentParser()
+#p.add_argument('-v','--verbose', default=0, action='count')
+#g = p.add_argument_group('Login credentials')
+p.add_argument('-c','--cookie', required=True, help='Cookie value(32 characters).')
+p.add_argument('-u','--user', required=True, help='User.')
+p.add_argument('-i','--ip', required=True, help='IP.')
+p.add_argument('-n','--hostname', required=True, help='Local hostname.')
+p.add_argument('-d','--domain', required=True, help='Domain.')
+p.add_argument('-p','--portal', required=True, help='Portal name.')
+p.add_argument('-g','--gateway', required=True, help='Gateway.')
+p.add_argument('-H','--hip', type=argparse.FileType('rb'), required=True, help='HIP file.')
+p.add_argument('-m','--md5', required=True, help='MD5 digest of HIP file.')
+args = p.parse_args()
+
+s = requests.Session()
+s.headers['User-Agent'] = 'PAN GlobalProtect'
+
+data = {
+ 'user': args.user,
+ 'domain' : args.domain,
+ 'portal' : args.portal,
+ 'authcookie' : args.cookie,
+ 'client-ip' : args.ip,
+ 'computer' : args.hostname,
+ 'md5' : args.md5,
+ 'client-role' : 'global-protect-full',
+}
+
+r = s.post('https://%s/ssl-vpn/hipreportcheck.esp' % args.gateway, data=data)
+
+needed = None
+if 'success' in r.text and 'no' in r.text:
+ print("No HIP report needed.", file=stderr)
+ needed = False
+elif 'success' in r.text and 'yes' in r.text:
+ print("Updated HIP report is needed.", file=stderr)
+ needed = True
+else:
+ print("HIP report check failed:", file=stderr)
+ print(r.text, file=stderr)
+ exit(1)
-class spoofer():
- def __init__(self,gateway,cookie,user,portal,ip,computer):
- self.gateway = gateway
- self.cookie = cookie
- self.user = user
- self.portal = portal
- self.ip = ip
- self.computer = computer
- self.headers = {
- 'Accept' : '*/*',
- 'Connection' : 'Keep-Alive',
- 'Content-Type' : 'application/x-www-form-urlencoded',
- 'User-Agent' : 'PAN GlobalProtect'
- }
- def send_hip_report(self,hip):
- with open(hip) as f:
- h = f.read()
- data = {
- 'user' : self.user,
- 'domain' : 'ml',
- 'portal' : self.portal,
- 'authcookie' : self.cookie,
- 'client-ip' : self.ip,
- 'computer' : self.computer,
- 'client-role' : 'global-protect-full',
- 'report' : h
- }
- r = post('https://'+self.gateway+'/ssl-vpn/hipreport.esp',headers=self.headers,verify=False,data=data)
- if 'success' in r.text:
- return True
- else:
- print r.request.body
- print r.text
- return False
- def check_hip(self,digest):
- data = {
- 'user' : self.user,
- 'domain' : 'ml',
- 'portal' : self.portal,
- 'authcookie' : self.cookie,
- 'client-ip' : self.ip,
- 'computer' : self.computer,
- 'client-role' : 'global-protect-full',
- 'md5' : digest
- }
- r = post('https://'+self.gateway+'/ssl-vpn/hipreportcheck.esp',headers=self.headers,verify=False,data=data)
- if 'success' in r.text:
- return True
- else:
- print r.text
- return False
+if needed:
+ with args.hip:
+ report = args.hip.read()
+ data['report'] = report
+ r = s.post('https://%s/ssl-vpn/hipreport.esp' % args.gateway, data=data)
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description='Globalprotect HIP spoofer.')
- parser.add_argument('-c','--cookie', required=True, help='Cookie value(32 characters).')
- parser.add_argument('-u','--user', required=True, help='User.')
- parser.add_argument('-i','--ip', required=True, help='IP.')
- parser.add_argument('-p','--computer', required=True, help='Computer.')
- parser.add_argument('-o','--portal', required=True, help='Portal name.')
- parser.add_argument('-g','--gateway', required=True, help='Gateway.')
- parser.add_argument('-f','--hip', required=True, help='HIP file.')
- args = parser.parse_args()
- if len(args.cookie) != 32:
- print "Cookie must have 32 characters!"
- quit(1)
- s = spoofer(gateway=args.gateway,cookie=args.cookie,user=args.user,portal=args.portal,ip=args.ip,computer=args.computer)
- s.check_hip('1')
- if s.send_hip_report(args.hip):
- print "HIP spoofed!"
- quit()
- else:
- print "Error spoofing HIP!"
- quit(1)
+ if 'success' in r.text:
+ print("HIP report submitted successfully.", file=stderr)
+ else:
+ print("HIP report submission failed:", file=stderr)
+ print(r.text, file=stderr)
+ exit(1)
From 4509c93227c047564dc1761fac667e752698a2fe Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 31 Oct 2017 21:36:53 -0700
Subject: [PATCH 037/131] =?UTF-8?q?spoofer.py=20=E2=86=92=20hipreport.py?=
=?UTF-8?q?=20(and=20don't=20bother=20checking=20if=20HIP=20report=20is=20?=
=?UTF-8?q?needed,=20by=20default)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
spoofer.py => hipreport.py | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
rename spoofer.py => hipreport.py (71%)
diff --git a/spoofer.py b/hipreport.py
similarity index 71%
rename from spoofer.py
rename to hipreport.py
index 920879e5..c633a499 100755
--- a/spoofer.py
+++ b/hipreport.py
@@ -9,6 +9,7 @@
p = argparse.ArgumentParser()
#p.add_argument('-v','--verbose', default=0, action='count')
#g = p.add_argument_group('Login credentials')
+p.add_argument('--check', action='store_true', help='Check if HIP report is needed before submitting it.')
p.add_argument('-c','--cookie', required=True, help='Cookie value(32 characters).')
p.add_argument('-u','--user', required=True, help='User.')
p.add_argument('-i','--ip', required=True, help='IP.')
@@ -34,19 +35,20 @@
'client-role' : 'global-protect-full',
}
-r = s.post('https://%s/ssl-vpn/hipreportcheck.esp' % args.gateway, data=data)
-
-needed = None
-if 'success' in r.text and 'no' in r.text:
- print("No HIP report needed.", file=stderr)
- needed = False
-elif 'success' in r.text and 'yes' in r.text:
- print("Updated HIP report is needed.", file=stderr)
+if not args.check:
needed = True
else:
- print("HIP report check failed:", file=stderr)
- print(r.text, file=stderr)
- exit(1)
+ r = s.post('https://%s/ssl-vpn/hipreportcheck.esp' % args.gateway, data=data)
+ if 'success' in r.text and 'no' in r.text:
+ print("No HIP report needed.", file=stderr)
+ needed = False
+ elif 'success' in r.text and 'yes' in r.text:
+ print("Updated HIP report is needed.", file=stderr)
+ needed = True
+ else:
+ print("HIP report check failed:", file=stderr)
+ print(r.text, file=stderr)
+ exit(1)
if needed:
with args.hip:
From 4104ab742ebfe46f73a71a4841ad86006654a926 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 31 Oct 2017 22:24:03 -0700
Subject: [PATCH 038/131] add --no-verify, and use absence/presence of --md5 as
a sign we need to check before submitting
---
hipreport.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/hipreport.py b/hipreport.py
index c633a499..d19e2110 100755
--- a/hipreport.py
+++ b/hipreport.py
@@ -9,7 +9,8 @@
p = argparse.ArgumentParser()
#p.add_argument('-v','--verbose', default=0, action='count')
#g = p.add_argument_group('Login credentials')
-p.add_argument('--check', action='store_true', help='Check if HIP report is needed before submitting it.')
+p.add_argument('--no-verify', action='store_true', dest='verify', default=True, help="Don't verify server certificates.")
+p.add_argument('-m','--md5', help='Check if HIP report is needed by submitting MD5 digest last HIP file.')
p.add_argument('-c','--cookie', required=True, help='Cookie value(32 characters).')
p.add_argument('-u','--user', required=True, help='User.')
p.add_argument('-i','--ip', required=True, help='IP.')
@@ -18,7 +19,6 @@
p.add_argument('-p','--portal', required=True, help='Portal name.')
p.add_argument('-g','--gateway', required=True, help='Gateway.')
p.add_argument('-H','--hip', type=argparse.FileType('rb'), required=True, help='HIP file.')
-p.add_argument('-m','--md5', required=True, help='MD5 digest of HIP file.')
args = p.parse_args()
s = requests.Session()
@@ -31,14 +31,14 @@
'authcookie' : args.cookie,
'client-ip' : args.ip,
'computer' : args.hostname,
- 'md5' : args.md5,
'client-role' : 'global-protect-full',
+ 'md5' : args.md5,
}
-if not args.check:
+if not args.md5:
needed = True
else:
- r = s.post('https://%s/ssl-vpn/hipreportcheck.esp' % args.gateway, data=data)
+ r = s.post('https://%s/ssl-vpn/hipreportcheck.esp' % args.gateway, data=data, verify=args.verify)
if 'success' in r.text and 'no' in r.text:
print("No HIP report needed.", file=stderr)
needed = False
@@ -54,7 +54,8 @@
with args.hip:
report = args.hip.read()
data['report'] = report
- r = s.post('https://%s/ssl-vpn/hipreport.esp' % args.gateway, data=data)
+ del data['md5'] # official client doesn't resubmit MD5
+ r = s.post('https://%s/ssl-vpn/hipreport.esp' % args.gateway, data=data, verify=args.verify)
if 'success' in r.text:
print("HIP report submitted successfully.", file=stderr)
From 89b4f414b75cf684f1d055f720b4686f603461f4 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 9 Nov 2017 04:56:56 +0200
Subject: [PATCH 039/131] I don't have time to teach everyone how to build this
---
.github/issue_template.md | 35 +++++++++++++++++++++++++++++++++++
README.md | 4 ++--
2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/.github/issue_template.md b/.github/issue_template.md
index 3c844b45..e156436e 100644
--- a/.github/issue_template.md
+++ b/.github/issue_template.md
@@ -1,3 +1,38 @@
+
+
# Problem description
1. I ran openconnect-gp as follows: `openconnect --protocol=gp `
diff --git a/README.md b/README.md
index 1ccfdd47..5d3b188b 100644
--- a/README.md
+++ b/README.md
@@ -39,10 +39,10 @@ report.
## Installation
-### Building from source on Linux
-
Please refer to the [build requirements for the official releases of OpenConnect](http://www.infradead.org/openconnect/building.html). **This version has the exact same build dependencies as OpenConnect v7.06**; modern versions of `autoconf`, `automake`, `gcc`, `libxml`, etc.
+### Building from source on Linux
+
Under Debian-based or Ubuntu-based distributions, this should install the requirements:
```sh
From ed6e35769b92f140fc8c8cfdc7964f47ca25e36b Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 28 Nov 2017 13:48:32 -0800
Subject: [PATCH 040/131] move error checking
---
gpst.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/gpst.c b/gpst.c
index 787f2238..d47b3d98 100644
--- a/gpst.c
+++ b/gpst.c
@@ -667,13 +667,6 @@ static int gpst_hip_report_check(struct openconnect_info *vpninfo)
/* Result could be either a JavaScript challenge or XML */
result = gpst_xml_or_error(vpninfo, result, xml_buf, parse_hip_report_check, NULL, NULL);
- if (result == -EAGAIN) {
- vpn_progress(vpninfo, PRG_DEBUG,
- _("Gateway says HIP report submission is needed.\n"));
- result = 0; /* FIXME */
- } else if (result == 0)
- vpn_progress(vpninfo, PRG_DEBUG,
- _("Gateway says no HIP report submission is needed.\n"));
buf_free(request_body);
free(xml_buf);
@@ -691,8 +684,13 @@ int gpst_setup(struct openconnect_info *vpninfo)
/* Check HIP */
ret = gpst_hip_report_check(vpninfo);
- if (ret)
- return ret;
+ if (ret == -EAGAIN) {
+ vpn_progress(vpninfo, PRG_DEBUG,
+ _("Gateway says HIP report submission is needed.\n"));
+ ret = 0; /* FIXME */
+ } else if (ret == 0)
+ vpn_progress(vpninfo, PRG_DEBUG,
+ _("Gateway says no HIP report submission is needed.\n"));
/* We do NOT actually start the HTTPS tunnel yet if we want to
* use ESP, because the ESP tunnel won't work if the HTTPS tunnel
From 746c10e7b2ad40d304f23643842712d82d5a4189 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 28 Nov 2017 14:01:25 -0800
Subject: [PATCH 041/131] use --csd-wrapper to submit a HIP report
---
auth-globalprotect.c | 28 +++++++++----
gpst.c | 77 +++++++++++++++++++++++++++++++++--
hipreport.py | 97 ++++++++++++++++++++++----------------------
3 files changed, 142 insertions(+), 60 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index d6ca44cb..6f651ec7 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -64,16 +64,16 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
* < 0, on error
* = 0, on success; *form is populated
*/
-struct gp_login_arg { const char *opt; int save:1; int show:1; int warn_missing:1; int err_missing:1; const char *check; };
+struct gp_login_arg { const char *opt; int save_cookie:1; int save_token:1; int show:1; int warn_missing:1; int err_missing:1; const char *check; };
static const struct gp_login_arg gp_login_args[] = {
[0] = { .opt="unknown-arg0", .show=1 },
- [1] = { .opt="authcookie", .save=1, .err_missing=1 },
+ [1] = { .opt="authcookie", .save_cookie=1, .err_missing=1 },
[2] = { .opt="persistent-cookie", .warn_missing=1 }, /* 40 hex digits; persists across sessions */
- [3] = { .opt="portal", .save=1, .warn_missing=1 },
- [4] = { .opt="user", .save=1, .err_missing=1 },
+ [3] = { .opt="portal", .save_cookie=1, .save_token=1, .warn_missing=1 },
+ [4] = { .opt="user", .save_cookie=1, .save_token=1, .err_missing=1 },
[5] = { .opt="authentication-source", .show=1 }, /* LDAP-auth, AUTH-RADIUS_RSA_OTP, etc. */
[6] = { .opt="configuration", .warn_missing=1 }, /* usually vsys1 (sometimes vsys2, etc.) */
- [7] = { .opt="domain", .save=1, .warn_missing=1 },
+ [7] = { .opt="domain", .save_cookie=1, .save_token=1, .warn_missing=1 },
[8] = { .opt="unknown-arg8", .show=1 },
[9] = { .opt="unknown-arg9", .show=1 },
[10] = { .opt="unknown-arg10", .show=1 },
@@ -81,15 +81,17 @@ static const struct gp_login_arg gp_login_args[] = {
[12] = { .opt="connection-type", .err_missing=1, .check="tunnel" },
[13] = { .opt="password-expiration-days", .show=1 }, /* days until password expires, if not -1 */
[14] = { .opt="clientVer", .err_missing=1, .check="4100" },
- [15] = { .opt="preferred-ip", .save=1 },
+ [15] = { .opt="preferred-ip", .save_cookie=1 },
};
const int gp_login_nargs = (sizeof(gp_login_args)/sizeof(*gp_login_args));
static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
{
- struct oc_text_buf *cookie = buf_alloc();
+ struct oc_text_buf *cookie = buf_alloc(), *token = buf_alloc();
const char *value = NULL;
const struct gp_login_arg *arg;
+ unsigned char md5[16];
+ int i;
if (!xmlnode_is_named(xml_node, "jnlp"))
goto err_out;
@@ -129,18 +131,28 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
_("GlobalProtect login returned %s=%s\n"), arg->opt, value);
}
- if (value && arg->save)
+ if (value && arg->save_cookie)
append_opt(cookie, arg->opt, value);
+ if (value && arg->save_token)
+ append_opt(token, arg->opt, value);
free((void *)value);
}
vpninfo->cookie = strdup(cookie->data);
+
+ openconnect_md5(md5, token->data, token->pos);
+ vpninfo->csd_token = malloc(MD5_SIZE * 2 + 1);
+ for (i=0; i < MD5_SIZE; i++)
+ sprintf(&vpninfo->csd_token[i*2], "%02x", md5[i]);
+
buf_free(cookie);
+ buf_free(token);
return 0;
err_out:
free((void *)value);
buf_free(cookie);
+ buf_free(token);
return -EINVAL;
}
diff --git a/gpst.c b/gpst.c
index d47b3d98..ad184a65 100644
--- a/gpst.c
+++ b/gpst.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#ifdef HAVE_LZ4
#include
@@ -651,9 +652,9 @@ static int gpst_hip_report_check(struct openconnect_info *vpninfo)
buf_truncate(request_body);
buf_append(request_body, "%s", vpninfo->cookie);
append_opt(request_body, "computer", vpninfo->localname);
- buf_append(request_body, "&client-role=global-protect-full&md5=");
- buf_append_md5(request_body, request_body->data, request_body->pos); /* hash up everything we've got so far */
append_opt(request_body, "client-ip", vpninfo->ip_info.addr);
+ append_opt(request_body, "client-role", "global-protect-full");
+ append_opt(request_body, "md5", vpninfo->csd_token);
orig_path = vpninfo->urlpath;
orig_ua = vpninfo->useragent;
@@ -673,6 +674,73 @@ static int gpst_hip_report_check(struct openconnect_info *vpninfo)
return result;
}
+static int run_hip_script(struct openconnect_info *vpninfo)
+{
+#if defined(_WIN32) || defined(__native_client__)
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Error: Running the 'HIP Report' script on this platform is not yet implemented.\n"));
+ return -EPERM;
+#else
+ pid_t child;
+
+ if (!vpninfo->csd_wrapper) {
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Error: Server asked us to submit HIP report.\n"
+ "You need to provide a --csd-wrapper argument with the HIP report submission script.\n"));
+ return -EINVAL;
+ }
+
+ child = fork();
+ if (child == -1) {
+ goto out;
+ } else if (child > 0) {
+ /* in parent: must reap child process */
+ int status;
+ waitpid(child, &status, 0);
+ if (status != 0)
+ vpn_progress(vpninfo, PRG_ERR,
+ _("HIP script returned non-zero status: %d\n"), status);
+ } else {
+ char *hip_argv[32];
+ char scertbuf[MD5_SIZE * 2 + 1];
+ int i = 0;
+ struct oc_text_buf *cookie_buf = buf_alloc();
+
+ /* in child: run HIP script */
+ /* Spurious stdout output from the HIP script will break both
+ the NM tool and the various cookieonly modes. */
+ dup2(2, 1);
+ hip_argv[i++] = openconnect_utf8_to_legacy(vpninfo,
+ vpninfo->csd_wrapper);
+
+ buf_append(cookie_buf, "%s", vpninfo->cookie);
+ append_opt(cookie_buf, "computer", vpninfo->localname);
+ append_opt(cookie_buf, "client-ip", vpninfo->ip_info.addr);
+ hip_argv[i++] = (char *)"--querystring";
+ hip_argv[i++] = cookie_buf->data;
+
+ scertbuf[0] = 0;
+ get_cert_md5_fingerprint(vpninfo, vpninfo->peer_cert, scertbuf);
+ hip_argv[i++] = (char *)"--servercert";
+ hip_argv[i++] = scertbuf;
+ hip_argv[i++] = (char *)"--gateway";
+ hip_argv[i++] = vpninfo->hostname;
+ hip_argv[i++] = (char *)"--md5";
+ hip_argv[i++] = vpninfo->csd_token;
+ hip_argv[i++] = NULL;
+
+ execv(hip_argv[0], hip_argv);
+
+ out:
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Failed to exec HIP script %s\n"), hip_argv[0]);
+ exit(1);
+ }
+
+ return 0;
+#endif /* !_WIN32 && !__native_client__ */
+}
+
int gpst_setup(struct openconnect_info *vpninfo)
{
int ret;
@@ -687,7 +755,9 @@ int gpst_setup(struct openconnect_info *vpninfo)
if (ret == -EAGAIN) {
vpn_progress(vpninfo, PRG_DEBUG,
_("Gateway says HIP report submission is needed.\n"));
- ret = 0; /* FIXME */
+ ret = run_hip_script(vpninfo);
+ if (ret != 0)
+ goto out;
} else if (ret == 0)
vpn_progress(vpninfo, PRG_DEBUG,
_("Gateway says no HIP report submission is needed.\n"));
@@ -710,6 +780,7 @@ int gpst_setup(struct openconnect_info *vpninfo)
vpninfo->ssl_times.last_rekey = 0;
}
+out:
return ret;
}
diff --git a/hipreport.py b/hipreport.py
index d19e2110..cc0a583b 100755
--- a/hipreport.py
+++ b/hipreport.py
@@ -1,65 +1,64 @@
#!/usr/bin/python
from __future__ import print_function
+from urlparse import parse_qsl
+from datetime import datetime
+import hashlib
import requests
import argparse
import os
-from sys import stderr, exit
+from sys import stdin, stderr, exit
+
+class FingerprintChecker(requests.adapters.HTTPAdapter):
+ def __init__(self, fingerprint, algorithm='md5', **kwargs):
+ self.fingerprint = fingerprint
+ self.algorithm = algorithm
+ super(FingerprintChecker, self).__init__(**kwargs)
+ def build_response(self, request, resp):
+ response = super(FingerprintChecker, self).build_response(request, resp)
+ try:
+ self.peercert = resp._connection.sock.getpeercert(binary_form=True)
+ self.peercertinfo = resp._connection.sock.getpeercert(binary_form=False)
+ except AttributeError:
+ pass
+ else:
+ checkfp = hashlib.new(self.algorithm, self.peercert).hexdigest()
+ if checkfp.strip().lower() != self.fingerprint.strip().lower():
+ raise requests.exceptions.SSLError("Server certificate fingerprint does not match expected %s:%s" % (self.algorithm, self.fingerprint))
+ return response
+ def cert_verify(self, conn, url, verify, cert):
+ super(FingerprintChecker, self).cert_verify(conn, url, False, cert)
p = argparse.ArgumentParser()
-#p.add_argument('-v','--verbose', default=0, action='count')
-#g = p.add_argument_group('Login credentials')
-p.add_argument('--no-verify', action='store_true', dest='verify', default=True, help="Don't verify server certificates.")
+p.add_argument('-q','--querystring', type=lambda s: dict(parse_qsl(s)),
+ help='URL-escaped query string with HIP parameters. It should contain these fields: user, domain, portal, authcookie, client-ip, computer.')
+p.add_argument('--servercert', help="Server's certificate MD5 fingerprint")
+p.add_argument('-r','--raw', action='store_true', help="Don't interpolate format strings in HIP file ({__NOW__}, {md5}, {user}, {domain}, {portal}, {client-ip}, {computer})")
+p.add_argument('-g','--gateway', required=True, help='GlobalProtect gateway server.')
+p.add_argument('-H','--hip', type=argparse.FileType('r'), default=stdin, help='HIP report file (default is stdin)')
p.add_argument('-m','--md5', help='Check if HIP report is needed by submitting MD5 digest last HIP file.')
-p.add_argument('-c','--cookie', required=True, help='Cookie value(32 characters).')
-p.add_argument('-u','--user', required=True, help='User.')
-p.add_argument('-i','--ip', required=True, help='IP.')
-p.add_argument('-n','--hostname', required=True, help='Local hostname.')
-p.add_argument('-d','--domain', required=True, help='Domain.')
-p.add_argument('-p','--portal', required=True, help='Portal name.')
-p.add_argument('-g','--gateway', required=True, help='Gateway.')
-p.add_argument('-H','--hip', type=argparse.FileType('rb'), required=True, help='HIP file.')
args = p.parse_args()
s = requests.Session()
s.headers['User-Agent'] = 'PAN GlobalProtect'
+if args.servercert:
+ s.mount('https://' + args.gateway, FingerprintChecker(args.servercert))
-data = {
- 'user': args.user,
- 'domain' : args.domain,
- 'portal' : args.portal,
- 'authcookie' : args.cookie,
- 'client-ip' : args.ip,
- 'computer' : args.hostname,
- 'client-role' : 'global-protect-full',
- 'md5' : args.md5,
-}
-
-if not args.md5:
- needed = True
-else:
- r = s.post('https://%s/ssl-vpn/hipreportcheck.esp' % args.gateway, data=data, verify=args.verify)
- if 'success' in r.text and 'no' in r.text:
- print("No HIP report needed.", file=stderr)
- needed = False
- elif 'success' in r.text and 'yes' in r.text:
- print("Updated HIP report is needed.", file=stderr)
- needed = True
- else:
- print("HIP report check failed:", file=stderr)
- print(r.text, file=stderr)
- exit(1)
+data = args.querystring
+data['client-role'] = 'global-protect-full'
+data['md5'] = args.md5
-if needed:
- with args.hip:
- report = args.hip.read()
- data['report'] = report
- del data['md5'] # official client doesn't resubmit MD5
- r = s.post('https://%s/ssl-vpn/hipreport.esp' % args.gateway, data=data, verify=args.verify)
+with args.hip:
+ report = args.hip.read()
+ if not args.raw:
+ report = report.format(__NOW__=datetime.now().strftime('%d/%m/%Y %H:%M:%S'), **data)
+data['report'] = report
+del data['md5'] # official client doesn't resubmit MD5
+r = s.post('https://%s/ssl-vpn/hipreport.esp' % args.gateway, data=data)
- if 'success' in r.text:
- print("HIP report submitted successfully.", file=stderr)
- else:
- print("HIP report submission failed:", file=stderr)
- print(r.text, file=stderr)
- exit(1)
+if 'success' in r.text:
+ print("HIP report submitted successfully.", file=stderr)
+else:
+ print("HIP report submission failed:", file=stderr)
+ print(r.text, file=stderr)
+ exit(1)
From 60f61705f9ccf5000ef0bdea2bc1c6908b650952 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 28 Nov 2017 20:32:54 -0800
Subject: [PATCH 042/131] ignore HIP submission failure; many GP VPNs work
without it despite requesting it
---
gpst.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/gpst.c b/gpst.c
index ad184a65..0f7b2990 100644
--- a/gpst.c
+++ b/gpst.c
@@ -685,9 +685,11 @@ static int run_hip_script(struct openconnect_info *vpninfo)
if (!vpninfo->csd_wrapper) {
vpn_progress(vpninfo, PRG_ERR,
- _("Error: Server asked us to submit HIP report.\n"
- "You need to provide a --csd-wrapper argument with the HIP report submission script.\n"));
- return -EINVAL;
+ _("Error: Server asked us to submit HIP report with md5sum %s.\n"
+ "You need to provide a --csd-wrapper argument with the HIP report submission script.\n"),
+ vpninfo->csd_token);
+ /* Many GlobalProtect VPNs work fine despite allegedly requiring HIP report submission */
+ return 0;
}
child = fork();
From 2d77040a870851a625de16938fcdda6a5494d7ed Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 29 Nov 2017 00:49:16 -0800
Subject: [PATCH 043/131] Loop when sending HTTP requests larger than the 16KiB
SSL record max
A single SSL record can't contain >16KiB, so the HTTPS request buffer
may not get fully written if it's larger than this.
I discovered this frustrating bug while working on GlobalProtect HIP
support, which requires sending giant blobs of XML to the gateway.
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
http.c | 21 +++++++++++++--------
openconnect-internal.h | 3 +++
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/http.c b/http.c
index 59f93e50..e53f3fce 100644
--- a/http.c
+++ b/http.c
@@ -818,7 +818,7 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method,
int result;
int rq_retry;
int rlen, pad;
- int auth = 0;
+ int i, auth = 0;
int max_redirects = 10;
if (request_body_type && buf_error(request_body))
@@ -913,17 +913,22 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method,
if (vpninfo->dump_http_traffic)
dump_buf(vpninfo, '>', buf->data);
- result = vpninfo->ssl_write(vpninfo, buf->data, buf->pos);
- if (rq_retry && result < 0) {
- openconnect_close_https(vpninfo, 0);
- goto retry;
+ for (i = 0; i < buf->pos; i += 16384) {
+ result = vpninfo->ssl_write(vpninfo, buf->data + i, MIN(buf->pos - i, 16384) );
+ if (result < 0) {
+ if (rq_retry) {
+ /* Retry if we failed to send the request on
+ an already-open connection */
+ openconnect_close_https(vpninfo, 0);
+ goto retry;
+ }
+ /* We'll already have complained about whatever offended us */
+ goto out;
+ }
}
- if (result < 0)
- goto out;
result = process_http_response(vpninfo, 0, http_auth_hdrs, buf);
if (result < 0) {
- /* We'll already have complained about whatever offended us */
goto out;
}
if (vpninfo->dump_http_traffic && buf->pos)
diff --git a/openconnect-internal.h b/openconnect-internal.h
index b70085d2..5b9a8d6c 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -122,6 +122,9 @@
#ifndef MAX
#define MAX(x,y) ((x)>(y))?(x):(y)
#endif
+#ifndef MIN
+#define MIN(x,y) ((x)<(y))?(x):(y)
+#endif
/****************************************************************************/
struct pkt {
From 41aca6e73b427f140c31a24ef98295e3b5c63bd9 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 29 Nov 2017 08:49:16 -0800
Subject: [PATCH 044/131] Loop when sending HTTP requests larger than the 16KiB
SSL record max
A single SSL record can't contain >16KiB, so the HTTPS request buffer
may not get fully written if it's larger than this.
I discovered this frustrating bug while working on GlobalProtect HIP
support, which requires sending giant blobs of XML to the gateway.
Signed-off-by: Daniel Lenski
Signed-off-by: David Woodhouse
---
http.c | 21 +++++++++++++--------
openconnect-internal.h | 3 +++
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/http.c b/http.c
index 812e0023..5307d824 100644
--- a/http.c
+++ b/http.c
@@ -818,7 +818,7 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method,
int result;
int rq_retry;
int rlen, pad;
- int auth = 0;
+ int i, auth = 0;
int max_redirects = 10;
if (request_body_type && buf_error(request_body))
@@ -913,17 +913,22 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method,
if (vpninfo->dump_http_traffic)
dump_buf(vpninfo, '>', buf->data);
- result = vpninfo->ssl_write(vpninfo, buf->data, buf->pos);
- if (rq_retry && result < 0) {
- openconnect_close_https(vpninfo, 0);
- goto retry;
+ for (i = 0; i < buf->pos; i += 16384) {
+ result = vpninfo->ssl_write(vpninfo, buf->data + i, MIN(buf->pos - i, 16384) );
+ if (result < 0) {
+ if (rq_retry) {
+ /* Retry if we failed to send the request on
+ an already-open connection */
+ openconnect_close_https(vpninfo, 0);
+ goto retry;
+ }
+ /* We'll already have complained about whatever offended us */
+ goto out;
+ }
}
- if (result < 0)
- goto out;
result = process_http_response(vpninfo, 0, http_auth_hdrs, buf);
if (result < 0) {
- /* We'll already have complained about whatever offended us */
goto out;
}
if (vpninfo->dump_http_traffic && buf->pos)
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 923d5a10..02716fd6 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -122,6 +122,9 @@
#ifndef MAX
#define MAX(x,y) ((x)>(y))?(x):(y)
#endif
+#ifndef MIN
+#define MIN(x,y) ((x)<(y))?(x):(y)
+#endif
/****************************************************************************/
struct pkt {
From 598758b9dde921cc9bfd947392df84b39b4e9040 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 29 Nov 2017 00:52:51 -0800
Subject: [PATCH 045/131] simpler: do HIP submission in openconnect itself, so
that the script only needs to output the HIP report
---
gpst.c | 82 ++++++++++++++++++++++++++++++----------------------
hipreport.py | 64 ----------------------------------------
2 files changed, 48 insertions(+), 98 deletions(-)
delete mode 100755 hipreport.py
diff --git a/gpst.c b/gpst.c
index 0f7b2990..91c4d9dd 100644
--- a/gpst.c
+++ b/gpst.c
@@ -636,7 +636,8 @@ static int parse_hip_report_check(struct openconnect_info *vpninfo, xmlNode *xml
return -EINVAL;
}
-static int gpst_hip_report_check(struct openconnect_info *vpninfo)
+/* check if HIP report is needed (to ssl-vpn/hipreportcheck.esp) or submit HIP report contents (to ssl-vpn/hipreport.esp) */
+static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const char *report)
{
int result;
@@ -647,27 +648,29 @@ static int gpst_hip_report_check(struct openconnect_info *vpninfo)
buf_truncate(request_body);
- /* submit HIP report check (ssl-vpn/hipreportcheck.esp) request */
/* cookie gives us these fields: authcookie, portal, user, domain, and (maybe the unnecessary) preferred-ip */
buf_truncate(request_body);
buf_append(request_body, "%s", vpninfo->cookie);
append_opt(request_body, "computer", vpninfo->localname);
append_opt(request_body, "client-ip", vpninfo->ip_info.addr);
append_opt(request_body, "client-role", "global-protect-full");
- append_opt(request_body, "md5", vpninfo->csd_token);
+ if (report) {
+ buf_ensure_space(request_body, strlen(report)*5);
+ append_opt(request_body, "report", report);
+ } else
+ append_opt(request_body, "md5", vpninfo->csd_token);
orig_path = vpninfo->urlpath;
orig_ua = vpninfo->useragent;
vpninfo->useragent = (char *)"PAN GlobalProtect";
- vpninfo->urlpath = strdup("ssl-vpn/hipreportcheck.esp");
+ vpninfo->urlpath = strdup(report ? "ssl-vpn/hipreport.esp" : "ssl-vpn/hipreportcheck.esp");
result = do_https_request(vpninfo, method, request_body_type, request_body,
&xml_buf, 0);
free(vpninfo->urlpath);
vpninfo->urlpath = orig_path;
vpninfo->useragent = orig_ua;
- /* Result could be either a JavaScript challenge or XML */
- result = gpst_xml_or_error(vpninfo, result, xml_buf, parse_hip_report_check, NULL, NULL);
+ result = gpst_xml_or_error(vpninfo, result, xml_buf, report ? NULL : parse_hip_report_check, NULL, NULL);
buf_free(request_body);
free(xml_buf);
@@ -681,6 +684,8 @@ static int run_hip_script(struct openconnect_info *vpninfo)
_("Error: Running the 'HIP Report' script on this platform is not yet implemented.\n"));
return -EPERM;
#else
+ int pipefd[2];
+ int ret;
pid_t child;
if (!vpninfo->csd_wrapper) {
@@ -692,45 +697,55 @@ static int run_hip_script(struct openconnect_info *vpninfo)
return 0;
}
+ if (pipe(pipefd) == -1)
+ goto out;
child = fork();
if (child == -1) {
goto out;
} else if (child > 0) {
- /* in parent: must reap child process */
- int status;
+ /* in parent: read report from child */
+ struct oc_text_buf *report_buf = buf_alloc();
+ char b[256];
+ int i, status;
+ close(pipefd[1]);
+
+ buf_truncate(report_buf);
+ while ((i = read(pipefd[0], b, sizeof(b))) > 0)
+ buf_append_bytes(report_buf, b, i);
+
waitpid(child, &status, 0);
- if (status != 0)
+ if (status != 0) {
vpn_progress(vpninfo, PRG_ERR,
_("HIP script returned non-zero status: %d\n"), status);
+ ret = -EINVAL;
+ } else {
+ ret = check_or_submit_hip_report(vpninfo, report_buf->data);
+ if (ret < 0)
+ vpn_progress(vpninfo, PRG_ERR, _("HIP report submission failed.\n"));
+ else {
+ vpn_progress(vpninfo, PRG_INFO, _("HIP report submitted successfully.\n"));
+ ret = 0;
+ }
+ }
+ buf_free(report_buf);
+ return ret;
} else {
+ /* in child: run HIP script */
char *hip_argv[32];
- char scertbuf[MD5_SIZE * 2 + 1];
int i = 0;
- struct oc_text_buf *cookie_buf = buf_alloc();
-
- /* in child: run HIP script */
- /* Spurious stdout output from the HIP script will break both
- the NM tool and the various cookieonly modes. */
- dup2(2, 1);
- hip_argv[i++] = openconnect_utf8_to_legacy(vpninfo,
- vpninfo->csd_wrapper);
-
- buf_append(cookie_buf, "%s", vpninfo->cookie);
- append_opt(cookie_buf, "computer", vpninfo->localname);
- append_opt(cookie_buf, "client-ip", vpninfo->ip_info.addr);
- hip_argv[i++] = (char *)"--querystring";
- hip_argv[i++] = cookie_buf->data;
-
- scertbuf[0] = 0;
- get_cert_md5_fingerprint(vpninfo, vpninfo->peer_cert, scertbuf);
- hip_argv[i++] = (char *)"--servercert";
- hip_argv[i++] = scertbuf;
- hip_argv[i++] = (char *)"--gateway";
- hip_argv[i++] = vpninfo->hostname;
+ close(pipefd[0]);
+ dup2(pipefd[1], 1);
+
+ hip_argv[i++] = openconnect_utf8_to_legacy(vpninfo, vpninfo->csd_wrapper);
+ hip_argv[i++] = (char *)"--cookie";
+ hip_argv[i++] = vpninfo->cookie;
+ hip_argv[i++] = (char *)"--computer";
+ hip_argv[i++] = vpninfo->localname;
+ hip_argv[i++] = (char *)"--client-ip";
+ hip_argv[i++] = (char *)vpninfo->ip_info.addr;
hip_argv[i++] = (char *)"--md5";
hip_argv[i++] = vpninfo->csd_token;
hip_argv[i++] = NULL;
-
execv(hip_argv[0], hip_argv);
out:
@@ -739,7 +754,6 @@ static int run_hip_script(struct openconnect_info *vpninfo)
exit(1);
}
- return 0;
#endif /* !_WIN32 && !__native_client__ */
}
@@ -753,7 +767,7 @@ int gpst_setup(struct openconnect_info *vpninfo)
return ret;
/* Check HIP */
- ret = gpst_hip_report_check(vpninfo);
+ ret = check_or_submit_hip_report(vpninfo, NULL);
if (ret == -EAGAIN) {
vpn_progress(vpninfo, PRG_DEBUG,
_("Gateway says HIP report submission is needed.\n"));
diff --git a/hipreport.py b/hipreport.py
deleted file mode 100755
index cc0a583b..00000000
--- a/hipreport.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import print_function
-from urlparse import parse_qsl
-from datetime import datetime
-import hashlib
-import requests
-import argparse
-import os
-from sys import stdin, stderr, exit
-
-class FingerprintChecker(requests.adapters.HTTPAdapter):
- def __init__(self, fingerprint, algorithm='md5', **kwargs):
- self.fingerprint = fingerprint
- self.algorithm = algorithm
- super(FingerprintChecker, self).__init__(**kwargs)
- def build_response(self, request, resp):
- response = super(FingerprintChecker, self).build_response(request, resp)
- try:
- self.peercert = resp._connection.sock.getpeercert(binary_form=True)
- self.peercertinfo = resp._connection.sock.getpeercert(binary_form=False)
- except AttributeError:
- pass
- else:
- checkfp = hashlib.new(self.algorithm, self.peercert).hexdigest()
- if checkfp.strip().lower() != self.fingerprint.strip().lower():
- raise requests.exceptions.SSLError("Server certificate fingerprint does not match expected %s:%s" % (self.algorithm, self.fingerprint))
- return response
- def cert_verify(self, conn, url, verify, cert):
- super(FingerprintChecker, self).cert_verify(conn, url, False, cert)
-
-p = argparse.ArgumentParser()
-p.add_argument('-q','--querystring', type=lambda s: dict(parse_qsl(s)),
- help='URL-escaped query string with HIP parameters. It should contain these fields: user, domain, portal, authcookie, client-ip, computer.')
-p.add_argument('--servercert', help="Server's certificate MD5 fingerprint")
-p.add_argument('-r','--raw', action='store_true', help="Don't interpolate format strings in HIP file ({__NOW__}, {md5}, {user}, {domain}, {portal}, {client-ip}, {computer})")
-p.add_argument('-g','--gateway', required=True, help='GlobalProtect gateway server.')
-p.add_argument('-H','--hip', type=argparse.FileType('r'), default=stdin, help='HIP report file (default is stdin)')
-p.add_argument('-m','--md5', help='Check if HIP report is needed by submitting MD5 digest last HIP file.')
-args = p.parse_args()
-
-s = requests.Session()
-s.headers['User-Agent'] = 'PAN GlobalProtect'
-if args.servercert:
- s.mount('https://' + args.gateway, FingerprintChecker(args.servercert))
-
-data = args.querystring
-data['client-role'] = 'global-protect-full'
-data['md5'] = args.md5
-
-with args.hip:
- report = args.hip.read()
- if not args.raw:
- report = report.format(__NOW__=datetime.now().strftime('%d/%m/%Y %H:%M:%S'), **data)
-data['report'] = report
-del data['md5'] # official client doesn't resubmit MD5
-r = s.post('https://%s/ssl-vpn/hipreport.esp' % args.gateway, data=data)
-
-if 'success' in r.text:
- print("HIP report submitted successfully.", file=stderr)
-else:
- print("HIP report submission failed:", file=stderr)
- print(r.text, file=stderr)
- exit(1)
From b324d7ec072c03634aa52c2da7955ed93eef13d9 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 29 Nov 2017 00:54:12 -0800
Subject: [PATCH 046/131] unneeded
---
digest.c | 2 +-
openconnect-internal.h | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/digest.c b/digest.c
index 6a481cbf..06dca75b 100644
--- a/digest.c
+++ b/digest.c
@@ -64,7 +64,7 @@ static void buf_append_unq(struct oc_text_buf *buf, const char *str)
}
}
-void buf_append_md5(struct oc_text_buf *buf, void *data, int len)
+static void buf_append_md5(struct oc_text_buf *buf, void *data, int len)
{
unsigned char md5[16];
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 02716fd6..ca90ff48 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -1074,7 +1074,6 @@ int socks_gssapi_auth(struct openconnect_info *vpninfo);
/* digest.c */
int digest_authorization(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state, struct oc_text_buf *buf);
-void buf_append_md5(struct oc_text_buf *buf, void *data, int len);
/* library.c */
void nuke_opt_values(struct oc_form_opt *opt);
From f8a7a2edc819f9316915fa1fced964fe085bef54 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 29 Nov 2017 01:01:27 -0800
Subject: [PATCH 047/131] example HIP report generator/spoofer script
invoke with:
openconnect --protocol=gp --csd-wrapper=hipreport.sh globalprotect.company.com
---
hipreport.sh | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 151 insertions(+)
create mode 100755 hipreport.sh
diff --git a/hipreport.sh b/hipreport.sh
new file mode 100755
index 00000000..8e957a9d
--- /dev/null
+++ b/hipreport.sh
@@ -0,0 +1,151 @@
+#!/bin/bash
+COOKIE=
+COMPUTER=
+IP=
+MD5=
+NOW=$(date +'%m/%d/%Y %H:%M:%S')
+USER="username"
+DOMAIN="domain"
+
+while [ "$1" ]; do
+ if [ "$1" == "--cookie" ]; then shift; COOKIE="$1"; fi
+ if [ "$1" == "--computer" ]; then shift; COMPUTER="$1"; fi
+ if [ "$1" == "--client-ip" ]; then shift; IP="$1"; fi
+ if [ "$1" == "--md5" ]; then shift; MD5="$1"; fi
+ shift
+done
+
+cat <
+ $MD5
+ $USER
+ $DOMAIN
+ $COMPUTER
+ deadbeef-dead-beef-dead-beefdeadbeef
+ $IP
+
+ $NOW
+
+
+ 4.0.2-19
+ Microsoft Windows 10 Pro , 64-bit
+ Microsoft
+ $DOMAIN.internal
+ $COMPUTER
+ deadbeef-dead-beef-dead-beefdeadbeef
+
+
+ PANGP Virtual Ethernet Adapter #2
+ 01-02-03-00-00-01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ yes
+ 10/11/2017 15:23:41
+
+
+
+
+
+
+ no
+ n/a
+
+
+
+
+
+
+
+
+
+
+ yes
+ 10/11/2017 15:23:41
+
+
+
+
+
+
+ no
+ n/a
+
+
+
+
+
+
+
+
+
+
+ n/a
+
+
+
+
+
+
+
+
+
+
+
+
+ C:
+ full
+
+
+
+
+
+
+
+
+
+
+
+
+ yes
+
+
+
+
+
+
+
+
+
+
+ yes
+
+
+
+
+
+
+ yes
+
+
+
+
+
+
+
+
+
+
+EOF
From 459448620cce5029116a2e2b40bf5617b0c8e442 Mon Sep 17 00:00:00 2001
From: Peter Mescalchin
Date: Wed, 6 Dec 2017 15:40:51 +1100
Subject: [PATCH 048/131] URI fixes in README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 5d3b188b..8c2c9396 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
# What is this?
This is a modified version of the fantastic open-source VPN client
-[OpenConnect](https://infradead.org/openconnect) which supports the
+[OpenConnect](https://www.infradead.org/openconnect) which supports the
PAN GlobalProtect VPN in its native modes (SSL and
[ESP](http://wikipedia.org/wiki/Encapsulating_Security_Payload))—with
no assistance or cooperation needed from your VPN administrators.
@@ -39,7 +39,7 @@ report.
## Installation
-Please refer to the [build requirements for the official releases of OpenConnect](http://www.infradead.org/openconnect/building.html). **This version has the exact same build dependencies as OpenConnect v7.06**; modern versions of `autoconf`, `automake`, `gcc`, `libxml`, etc.
+Please refer to the [build requirements for the official releases of OpenConnect](https://www.infradead.org/openconnect/building.html). **This version has the exact same build dependencies as OpenConnect v7.06**; modern versions of `autoconf`, `automake`, `gcc`, `libxml`, etc.
### Building from source on Linux
From fdaba772b27d66f92a3d035d18d7b4e15292f6b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grenier?=
Date: Thu, 12 Jan 2017 20:25:12 -0500
Subject: [PATCH 049/131] juniper: Support 'username' form input type
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://bugzilla.redhat.com/show_bug.cgi?id=1412021
Signed-off-by: François Grenier
Signed-off-by: David Woodhouse
---
auth-juniper.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/auth-juniper.c b/auth-juniper.c
index 4b889d6b..eee85d2f 100644
--- a/auth-juniper.c
+++ b/auth-juniper.c
@@ -122,6 +122,13 @@ static int parse_input_node(struct openconnect_info *vpninfo, struct oc_auth_for
ret = -ENOMEM;
goto out;
}
+ } else if (!strcasecmp(type, "username")) {
+ opt->type = OC_FORM_OPT_TEXT;
+ xmlnode_get_prop(node, "name", &opt->name);
+ if (asprintf(&opt->label, "%s:", opt->name) == -1) {
+ ret = -ENOMEM;
+ goto out;
+ }
} else if (!strcasecmp(type, "submit")) {
xmlnode_get_prop(node, "name", &opt->name);
if (opt->name && (!strcmp(opt->name, submit_button) ||
From 42ec887cd31d514b72c5212d284785b4ddc7eb8b Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 14 Dec 2017 17:19:03 -0800
Subject: [PATCH 050/131] Improve GPST/ESP not-stepping-on-toes tap dance
In preparation for adding re-key support, stop misusing ssl_times.last_rekey.
(This seems to fix a weird frantic mainloop-invoking bug I was running into as well.)
---
gpst.c | 19 +++----------------
mainloop.c | 2 +-
openconnect-internal.h | 1 +
3 files changed, 5 insertions(+), 17 deletions(-)
diff --git a/gpst.c b/gpst.c
index 91c4d9dd..d50edf31 100644
--- a/gpst.c
+++ b/gpst.c
@@ -605,7 +605,7 @@ static int gpst_connect(struct openconnect_info *vpninfo)
monitor_fd_new(vpninfo, ssl);
monitor_read_fd(vpninfo, ssl);
monitor_except_fd(vpninfo, ssl);
- vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
+ vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
if (vpninfo->dtls_state != DTLS_DISABLED)
vpninfo->dtls_state = DTLS_NOSECRET;
}
@@ -784,17 +784,6 @@ int gpst_setup(struct openconnect_info *vpninfo)
*/
if (vpninfo->dtls_state == DTLS_DISABLED || vpninfo->dtls_state == DTLS_NOSECRET)
ret = gpst_connect(vpninfo);
- else {
- /* We want to prevent the mainloop timers from frantically
- * calling the GPST mainloop.
- */
- vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
-
- /* Using (abusing?) last_rekey as the time when the SSL tunnel
- * was brought up.
- */
- vpninfo->ssl_times.last_rekey = 0;
- }
out:
return ret;
@@ -820,12 +809,10 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
return 0;
case DTLS_SECRET:
case DTLS_SLEEPING:
- if (time(NULL) < vpninfo->dtls_times.last_rekey + 5) {
+ if (!ka_check_deadline(timeout, time(NULL), vpninfo->dtls_times.last_rekey + 5)) {
/* Allow 5 seconds after configuration for ESP to start */
- if (*timeout > 5000)
- *timeout = 5000;
return 0;
- } else if (!vpninfo->ssl_times.last_rekey) {
+ } else {
/* ... before we switch to HTTPS instead */
vpn_progress(vpninfo, PRG_ERR,
_("Failed to connect ESP tunnel; using HTTPS instead.\n"));
diff --git a/mainloop.c b/mainloop.c
index 754d7d4f..6c125c31 100644
--- a/mainloop.c
+++ b/mainloop.c
@@ -315,7 +315,7 @@ int openconnect_mainloop(struct openconnect_info *vpninfo,
return ret < 0 ? ret : -EIO;
}
-static int ka_check_deadline(int *timeout, time_t now, time_t due)
+int ka_check_deadline(int *timeout, time_t now, time_t due)
{
if (now >= due)
return 1;
diff --git a/openconnect-internal.h b/openconnect-internal.h
index ca90ff48..0c0b7d4f 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -964,6 +964,7 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout);
int queue_new_packet(struct pkt_q *q, void *buf, int len);
int keepalive_action(struct keepalive_info *ka, int *timeout);
int ka_stalled_action(struct keepalive_info *ka, int *timeout);
+int ka_check_deadline(int *timeout, time_t now, time_t due);
/* xml.c */
ssize_t read_file_into_string(struct openconnect_info *vpninfo, const char *fname,
From 7274c12dcf3fe3fd770b8343c9a64e36af8e8c22 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 14 Dec 2017 17:19:20 -0800
Subject: [PATCH 051/131] Add support for tunnel-based rekey for GlobalProtect
This simply means re-pulling the getconfig.esp tunnel configuration
and thereby acquiring new ESP keys and extending the lifetime of the
authentication cookie, before the elapses.
---
gpst.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/gpst.c b/gpst.c
index d50edf31..726ee3e7 100644
--- a/gpst.c
+++ b/gpst.c
@@ -381,6 +381,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
vpninfo->ip_info.domain = NULL;
vpninfo->ip_info.mtu = 0;
vpninfo->esp_magic = inet_addr(vpninfo->ip_info.gateway_addr);
+ vpninfo->ssl_times.rekey_method = REKEY_NONE;
vpninfo->cstp_options = NULL;
for (ii = 0; ii < 3; ii++)
@@ -396,6 +397,13 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
else if (!xmlnode_get_text(xml_node, "mtu", &s)) {
vpninfo->ip_info.mtu = atoi(s);
free((void *)s);
+ } else if (!xmlnode_get_text(xml_node, "timeout", &s)) {
+ int sec = atoi(s);
+ vpn_progress(vpninfo, PRG_INFO, _("Tunnel timeout (rekey interval) is %d minutes.\n"), sec/60);
+ vpninfo->ssl_times.last_rekey = time(NULL);
+ vpninfo->ssl_times.rekey = sec - 60;
+ vpninfo->ssl_times.rekey_method = REKEY_TUNNEL;
+ free((void *)s);
} else if (!xmlnode_get_text(xml_node, "gw-address", &s)) {
/* As remarked in oncp.c, "this is a tunnel; having a
* gateway is meaningless." See esp_send_probes_gp for the
@@ -806,6 +814,9 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
_("ESP tunnel connected; exiting HTTPS mainloop.\n"));
vpninfo->dtls_state = DTLS_CONNECTED;
case DTLS_CONNECTED:
+ /* Rekey if needed */
+ if (keepalive_action(&vpninfo->ssl_times, timeout) == KA_REKEY)
+ goto do_rekey;
return 0;
case DTLS_SECRET:
case DTLS_SLEEPING:
@@ -928,6 +939,8 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
goto do_reconnect;
else if (!ret) {
switch (ka_stalled_action(&vpninfo->ssl_times, timeout)) {
+ case KA_REKEY:
+ goto do_rekey;
case KA_DPD_DEAD:
goto peer_dead;
case KA_NONE:
@@ -950,6 +963,11 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
}
switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
+ case KA_REKEY:
+ do_rekey:
+ vpn_progress(vpninfo, PRG_INFO, _("GlobalProtect rekey due\n"));
+ goto do_reconnect;
+
case KA_DPD_DEAD:
peer_dead:
vpn_progress(vpninfo, PRG_ERR,
From 0084d18b6dacc6d9fd6058387257ce7381e11caf Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 15 Dec 2017 17:27:11 -0800
Subject: [PATCH 052/131] improve comments and basic Bourne-shell compatibility
in hipreport.sh template
---
hipreport.sh | 51 +++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 41 insertions(+), 10 deletions(-)
diff --git a/hipreport.sh b/hipreport.sh
index 8e957a9d..afc30679 100755
--- a/hipreport.sh
+++ b/hipreport.sh
@@ -1,27 +1,58 @@
-#!/bin/bash
+#!/bin/sh
+
+# Read required variables from command line:
+#
+# --cookie: a URL-encoded string, as output by openconnect
+# --authenticate --protocol=gp, which includes parameters
+# --from the /ssl-vpn/login.esp response
+#
+# --computer: local hostname, which can be overriden with
+# --openconnect local-hostname=HOSTNAME
+#
+# --client-ip: IPv4 address allocated by the GlobalProtect VPN for
+# this client (included in /ssl-vpn/getconfig.esp
+# response)
+#
+# --md5: The md5 digest to encode into this HIP report. I'm not sure
+# exactly what this is the md5 digest *of*, but all that
+# really matters is that the value in the HIP report
+# submission should match the value in the HIP report check.
+
COOKIE=
COMPUTER=
IP=
MD5=
-NOW=$(date +'%m/%d/%Y %H:%M:%S')
-USER="username"
-DOMAIN="domain"
while [ "$1" ]; do
- if [ "$1" == "--cookie" ]; then shift; COOKIE="$1"; fi
- if [ "$1" == "--computer" ]; then shift; COMPUTER="$1"; fi
- if [ "$1" == "--client-ip" ]; then shift; IP="$1"; fi
- if [ "$1" == "--md5" ]; then shift; MD5="$1"; fi
+ if [ "$1" = "--cookie" ]; then shift; COOKIE="$1"; fi
+ if [ "$1" = "--computer" ]; then shift; COMPUTER="$1"; fi
+ if [ "$1" = "--client-ip" ]; then shift; IP="$1"; fi
+ if [ "$1" = "--md5" ]; then shift; MD5="$1"; fi
shift
done
+if [ -z "$COOKIE" -o -z "$COMPUTER" -o -z "$IP" -o -z "$MD5" ]; then
+ echo "Parameters --cookie, --computer, --client-ip, and --md5 are required" >&2
+ exit 1;
+fi
+
+# Extract username and domain from cookie
+USER=$(echo "$COOKIE" | sed -rn 's/(.+&|^)user=([^&]+)(&.+|$)/\2/p')
+DOMAIN=$(echo "$COOKIE" | sed -rn 's/(.+&|^)domain=([^&]+)(&.+|$)/\2/p')
+
+# Timestamp in the format expected by GlobalProtect server
+NOW=$(date +'%m/%d/%Y %H:%M:%S')
+
+# This value may need to be extracted from the official HIP report, if a made-up value is not accepted.
+HOSTID="deadbeef-dead-beef-dead-beefdeadbeef"
+
cat <
$MD5
$USER
$DOMAIN
$COMPUTER
- deadbeef-dead-beef-dead-beefdeadbeef
+ $HOSTID
$IP
$NOW
@@ -32,7 +63,7 @@ cat <Microsoft
$DOMAIN.internal
$COMPUTER
- deadbeef-dead-beef-dead-beefdeadbeef
+ $HOSTID
PANGP Virtual Ethernet Adapter #2
From 488635f2522acd2ff78846fcf53f3a497cf25d32 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 16 Dec 2017 11:16:48 -0800
Subject: [PATCH 053/131] document HIP report support
---
gpst.c | 7 ++--
www/Makefile.am | 4 +-
www/features.xml | 2 +-
www/globalprotect.xml | 7 ++++
www/hip.xml | 89 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 103 insertions(+), 6 deletions(-)
create mode 100644 www/hip.xml
diff --git a/gpst.c b/gpst.c
index 726ee3e7..154061cc 100644
--- a/gpst.c
+++ b/gpst.c
@@ -698,9 +698,10 @@ static int run_hip_script(struct openconnect_info *vpninfo)
if (!vpninfo->csd_wrapper) {
vpn_progress(vpninfo, PRG_ERR,
- _("Error: Server asked us to submit HIP report with md5sum %s.\n"
- "You need to provide a --csd-wrapper argument with the HIP report submission script.\n"),
- vpninfo->csd_token);
+ _("WARNING: Server asked us to submit HIP report with md5sum %s.\n"
+ "VPN connectivity may be disabled or limited without HIP report submission.\n"
+ "You need to provide a --csd-wrapper argument with the HIP report submission script.\n"),
+ vpninfo->csd_token);
/* Many GlobalProtect VPNs work fine despite allegedly requiring HIP report submission */
return 0;
}
diff --git a/www/Makefile.am b/www/Makefile.am
index f791a004..225a20ac 100644
--- a/www/Makefile.am
+++ b/www/Makefile.am
@@ -3,8 +3,8 @@
SUBDIRS = styles inc images
CONV = "$(srcdir)/html.py"
-FTR_PAGES = csd.html charset.html token.html pkcs11.html tpm.html features.html gui.html nonroot.html
-START_PAGES = building.html connecting.html manual.html vpnc-script.html
+FTR_PAGES = csd.html charset.html token.html pkcs11.html tpm.html features.html gui.html nonroot.html hip.html
+START_PAGES = building.html connecting.html manual.html vpnc-script.html
INDEX_PAGES = changelog.html download.html index.html packages.html platforms.html
PROTO_PAGES = anyconnect.html juniper.html globalprotect.html
TOPLEVEL_PAGES = contribute.html mail.html
diff --git a/www/features.xml b/www/features.xml
index 92457dc4..cbe91447 100644
--- a/www/features.xml
+++ b/www/features.xml
@@ -24,7 +24,7 @@
- Automatic update of VPN server list / configuration.
- Roaming support, allowing reconnection when the local IP address changes.
- Run without root privileges (see here).
- - "Cisco Secure Desktop" support (see here).
+ - Support for "Cisco Secure Desktop" (see here) and "GlobalProtect HIP report" (see here).
- Graphical connection tools for various environments (see here).
diff --git a/www/globalprotect.xml b/www/globalprotect.xml
index ee458199..655db9a2 100644
--- a/www/globalprotect.xml
+++ b/www/globalprotect.xml
@@ -16,15 +16,22 @@
href="https://tools.ietf.org/html/rfc3948">ESP, with routing and
configuration information distributed in XML format.
+Authentication
+
To authenticate, you connect to the secure web server (POST
/ssl-vpn/login.esp), provide a username, password, and (optionally) a
certificate, and receive an authcookie. The username, authcookie, and a
couple other bits of information obtained at login are combined into the
OpenConnect cookie.
+Tunnel configuration
+
To connect to the secure tunnel, the cookie is used to read routing and
tunnel configuration information (POST /ssl-vpn/getconfig.esp).
+Next, a HIP report (security scanner report) is
+generated by the client and submitted to the server, if required.
+
Finally, either an HTTPS-based or ESP-based tunnel is setup:
diff --git a/www/hip.xml b/www/hip.xml
new file mode 100644
index 00000000..0009c320
--- /dev/null
+++ b/www/hip.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+PAN GlobalProtect HIP
+
+The HIP ('Host Integrity Protection') mechanism is a security
+scanner for the PAN GlobalProtect
+VPNs, in the same vein as Cisco's CSD and Juniper's Host Checker (tncc.jar).
+
+How it works
+
+It is somewhat less intrusive than CSD or TNCC, because it
+does not appear to work by downloading a trojan binary from the VPN
+server. Instead, it runs a HIP report generator (built-in as part of
+the official GlobalProtect VPN client software), which generates an
+"HIP report" XML file.
+
+HIP flow used in the official clients:
+
+ - Client authenticates and fetches the tunnel configuration from the GlobalProtect gateway.
+ - Client runs HIP report generator and computes MD5 digest of report.
+ - Client checks whether a HIP report is required (
/ssl-vpn/hipreportcheck.esp), including its MD5 digest and gateway-assigned IP address in the report.
+ - Gateway responds whether or not a HIP report is required (normally, it doesn't require a new one if a report with the same MD5 digest and same IP address have been submitted recently).
+ - Client uploads the complete HIP report to (
/ssl-vpn/hipreport.esp).
+ - Server confirms acceptance of HIP report with a success message.
+
+
+If all goes well, the client should have the expected level of
+access to resources on the network after these steps are
+complete. However, two things can go wrong:
+
+
+ - Many GlobalProtect servers report that they require HIP reports
+ (#3 above), but don't actually enforce this requirement. (For this
+ reason, OpenConnect does not currently fail if a HIP report is
+ required but no HIP report script is provided.)
+ - Many GlobalProtect servers will claim that the HIP report was
+ accepted successfully (#6 above) but silently fail to enable the
+ expected network access, presumably because some aspect of the
+ HIP report contents were not approved.
+
+
+HIP support in openconnect
+
+OpenConnect supports HIP report generation and submission by passing the --csd-wrapper=SCRIPT argument with a shell script to generate a HIP report in the format expected by the
+server. This shell script must output the HIP report to standard output and exit successfully (status code 0). The HIP script is called with the following command-line arguments:
+
+
+ --cookie: a URL-encoded string, as output by openconnect
+ --authenticate --protocol=gp, which includes parameters
+ --from the /ssl-vpn/login.esp response
+
+ --computer: local hostname, which can be overriden with
+ --openconnect local-hostname=HOSTNAME
+
+ --client-ip: IPv4 address allocated by the GlobalProtect VPN for
+ this client (included in /ssl-vpn/getconfig.esp
+ response)
+
+ --md5: The md5 digest to encode into this HIP report. All that
+ really matters is that the value in the HIP report
+ submission should match the value in the HIP report check.
+
+
+Generating/spoofing a HIP report
+
+An example hipreport.sh script is included in the
+openconnect distribution.
+
+Depending on how picky your GlobalProtect
+VPN is, it may be necessary to spoof or alter some of the parameters
+of the HIP report to match the output of one of the official
+clients. In order to capture the contents of the official Windows
+client's HIP reports, enable the highest logging level for the "PanGPS
+Service", and then sift through the giant PanGPS.log file
+(which should be in the same directory as the executables, normally
+c:\Program Files\PaloAlto Networks\GlobalProtect) to find
+the HIP report submission.
+
+
+
From 30ad09838d2210245300cf35b0bb8acda662c8b3 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 17 Dec 2017 12:14:22 -0800
Subject: [PATCH 054/131] add per-protocol override for HTTP User-Agent
---
auth-globalprotect.c | 10 ++--------
gpst.c | 10 ++--------
http.c | 2 +-
library.c | 1 +
openconnect-internal.h | 1 +
5 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 6f651ec7..5604d37c 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -268,7 +268,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
struct oc_text_buf *request_body = buf_alloc();
const char *request_body_type = "application/x-www-form-urlencoded";
const char *method = "POST";
- char *xml_buf=NULL, *orig_path, *orig_ua;
+ char *xml_buf=NULL, *orig_path;
char *prompt=_("Please enter your username and password"), *auth_id=NULL;
#ifdef HAVE_LIBSTOKEN
@@ -312,14 +312,11 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
append_form_opts(vpninfo, form, request_body);
orig_path = vpninfo->urlpath;
- orig_ua = vpninfo->useragent;
- vpninfo->useragent = (char *)"PAN GlobalProtect";
vpninfo->urlpath = strdup(portal ? "global-protect/getconfig.esp" : "ssl-vpn/login.esp");
result = do_https_request(vpninfo, method, request_body_type, request_body,
&xml_buf, 0);
free(vpninfo->urlpath);
vpninfo->urlpath = orig_path;
- vpninfo->useragent = orig_ua;
/* Result could be either a JavaScript challenge or XML */
result = gpst_xml_or_error(vpninfo, result, xml_buf,
@@ -370,7 +367,7 @@ int gpst_obtain_cookie(struct openconnect_info *vpninfo)
int gpst_bye(struct openconnect_info *vpninfo, const char *reason)
{
- char *orig_path, *orig_ua;
+ char *orig_path;
int result;
struct oc_text_buf *request_body = buf_alloc();
const char *request_body_type = "application/x-www-form-urlencoded";
@@ -396,15 +393,12 @@ int gpst_bye(struct openconnect_info *vpninfo, const char *reason)
* logout.
*/
orig_path = vpninfo->urlpath;
- orig_ua = vpninfo->useragent;
- vpninfo->useragent = (char *)"PAN GlobalProtect";
vpninfo->urlpath = strdup("ssl-vpn/logout.esp");
openconnect_close_https(vpninfo, 0);
result = do_https_request(vpninfo, method, request_body_type, request_body,
&xml_buf, 0);
free(vpninfo->urlpath);
vpninfo->urlpath = orig_path;
- vpninfo->useragent = orig_ua;
/* logout.esp returns HTTP status 200 and when
* successful, and all manner of malformed junk when unsuccessful.
diff --git a/gpst.c b/gpst.c
index 154061cc..cbc7e548 100644
--- a/gpst.c
+++ b/gpst.c
@@ -484,7 +484,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
static int gpst_get_config(struct openconnect_info *vpninfo)
{
- char *orig_path, *orig_ua;
+ char *orig_path;
int result;
struct oc_text_buf *request_body = buf_alloc();
struct oc_vpn_option *old_cstp_opts = vpninfo->cstp_options;
@@ -504,14 +504,11 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
buf_append(request_body, "&%s", vpninfo->cookie);
orig_path = vpninfo->urlpath;
- orig_ua = vpninfo->useragent;
- vpninfo->useragent = (char *)"PAN GlobalProtect";
vpninfo->urlpath = strdup("ssl-vpn/getconfig.esp");
result = do_https_request(vpninfo, method, request_body_type, request_body,
&xml_buf, 0);
free(vpninfo->urlpath);
vpninfo->urlpath = orig_path;
- vpninfo->useragent = orig_ua;
if (result < 0)
goto out;
@@ -652,7 +649,7 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
struct oc_text_buf *request_body = buf_alloc();
const char *request_body_type = "application/x-www-form-urlencoded";
const char *method = "POST";
- char *xml_buf=NULL, *orig_path, *orig_ua;
+ char *xml_buf=NULL, *orig_path;
buf_truncate(request_body);
@@ -669,14 +666,11 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
append_opt(request_body, "md5", vpninfo->csd_token);
orig_path = vpninfo->urlpath;
- orig_ua = vpninfo->useragent;
- vpninfo->useragent = (char *)"PAN GlobalProtect";
vpninfo->urlpath = strdup(report ? "ssl-vpn/hipreport.esp" : "ssl-vpn/hipreportcheck.esp");
result = do_https_request(vpninfo, method, request_body_type, request_body,
&xml_buf, 0);
free(vpninfo->urlpath);
vpninfo->urlpath = orig_path;
- vpninfo->useragent = orig_ua;
result = gpst_xml_or_error(vpninfo, result, xml_buf, report ? NULL : parse_hip_report_check, NULL, NULL);
diff --git a/http.c b/http.c
index 5307d824..29602966 100644
--- a/http.c
+++ b/http.c
@@ -1472,7 +1472,7 @@ void http_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
buf_append(buf, "Host: %s\r\n", vpninfo->hostname);
else
buf_append(buf, "Host: %s:%d\r\n", vpninfo->hostname, vpninfo->port);
- buf_append(buf, "User-Agent: %s\r\n", vpninfo->useragent);
+ buf_append(buf, "User-Agent: %s\r\n", vpninfo->proto->override_useragent ? : vpninfo->useragent);
if (vpninfo->cookies) {
buf_append(buf, "Cookie: ");
diff --git a/library.c b/library.c
index 46ab659f..39973631 100644
--- a/library.c
+++ b/library.c
@@ -145,6 +145,7 @@ const struct vpn_proto openconnect_protos[] = {
.name = "gp",
.pretty_name = N_("Palo Alto Networks GlobalProtect"),
.description = N_("Compatible with Palo Alto Networks (PAN) GlobalProtect SSL VPN"),
+ .override_useragent = "PAN GlobalProtect",
.flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
.vpn_close_session = gpst_bye,
.tcp_connect = gpst_setup,
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 0c0b7d4f..a1931513 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -263,6 +263,7 @@ struct vpn_proto {
const char *name;
const char *pretty_name;
const char *description;
+ const char *override_useragent;
unsigned int flags;
int (*vpn_close_session)(struct openconnect_info *vpninfo, const char *reason);
From f9c36b4afcf29098989b9138272b40f60cc4acd5 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 18 Dec 2017 08:56:57 -0800
Subject: [PATCH 055/131] bug fixes for HIP support (#70) backported from gpst
branch
Most importantly:
Unlike CSD, the HIP security checker runs during the connection
phase, not during the authentication phase. Therefore we need to
build the CSD token (an MD5 digest identifying the client) without
relying on the authentication phase having run in the same process.
We build it from the cookie containing authentication information,
but exclude the volatile authcookie field which changes from session
to session.
---
auth-globalprotect.c | 28 ++++++++------------------
gpst.c | 47 +++++++++++++++++++++++++++++++++-----------
2 files changed, 43 insertions(+), 32 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 5604d37c..1449d8cd 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -64,16 +64,16 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
* < 0, on error
* = 0, on success; *form is populated
*/
-struct gp_login_arg { const char *opt; int save_cookie:1; int save_token:1; int show:1; int warn_missing:1; int err_missing:1; const char *check; };
+struct gp_login_arg { const char *opt; int save:1; int show:1; int warn_missing:1; int err_missing:1; const char *check; };
static const struct gp_login_arg gp_login_args[] = {
[0] = { .opt="unknown-arg0", .show=1 },
- [1] = { .opt="authcookie", .save_cookie=1, .err_missing=1 },
+ [1] = { .opt="authcookie", .save=1, .err_missing=1 },
[2] = { .opt="persistent-cookie", .warn_missing=1 }, /* 40 hex digits; persists across sessions */
- [3] = { .opt="portal", .save_cookie=1, .save_token=1, .warn_missing=1 },
- [4] = { .opt="user", .save_cookie=1, .save_token=1, .err_missing=1 },
+ [3] = { .opt="portal", .save=1, .warn_missing=1 },
+ [4] = { .opt="user", .save=1, .err_missing=1 },
[5] = { .opt="authentication-source", .show=1 }, /* LDAP-auth, AUTH-RADIUS_RSA_OTP, etc. */
[6] = { .opt="configuration", .warn_missing=1 }, /* usually vsys1 (sometimes vsys2, etc.) */
- [7] = { .opt="domain", .save_cookie=1, .save_token=1, .warn_missing=1 },
+ [7] = { .opt="domain", .save=1, .warn_missing=1 },
[8] = { .opt="unknown-arg8", .show=1 },
[9] = { .opt="unknown-arg9", .show=1 },
[10] = { .opt="unknown-arg10", .show=1 },
@@ -81,17 +81,15 @@ static const struct gp_login_arg gp_login_args[] = {
[12] = { .opt="connection-type", .err_missing=1, .check="tunnel" },
[13] = { .opt="password-expiration-days", .show=1 }, /* days until password expires, if not -1 */
[14] = { .opt="clientVer", .err_missing=1, .check="4100" },
- [15] = { .opt="preferred-ip", .save_cookie=1 },
+ [15] = { .opt="preferred-ip", .save=1 },
};
const int gp_login_nargs = (sizeof(gp_login_args)/sizeof(*gp_login_args));
static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
{
- struct oc_text_buf *cookie = buf_alloc(), *token = buf_alloc();
+ struct oc_text_buf *cookie = buf_alloc();
const char *value = NULL;
const struct gp_login_arg *arg;
- unsigned char md5[16];
- int i;
if (!xmlnode_is_named(xml_node, "jnlp"))
goto err_out;
@@ -131,28 +129,18 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
_("GlobalProtect login returned %s=%s\n"), arg->opt, value);
}
- if (value && arg->save_cookie)
+ if (value && arg->save)
append_opt(cookie, arg->opt, value);
- if (value && arg->save_token)
- append_opt(token, arg->opt, value);
free((void *)value);
}
vpninfo->cookie = strdup(cookie->data);
-
- openconnect_md5(md5, token->data, token->pos);
- vpninfo->csd_token = malloc(MD5_SIZE * 2 + 1);
- for (i=0; i < MD5_SIZE; i++)
- sprintf(&vpninfo->csd_token[i*2], "%02x", md5[i]);
-
buf_free(cookie);
- buf_free(token);
return 0;
err_out:
free((void *)value);
buf_free(cookie);
- buf_free(token);
return -EINVAL;
}
diff --git a/gpst.c b/gpst.c
index cbc7e548..9b8b3c6a 100644
--- a/gpst.c
+++ b/gpst.c
@@ -620,25 +620,27 @@ static int gpst_connect(struct openconnect_info *vpninfo)
static int parse_hip_report_check(struct openconnect_info *vpninfo, xmlNode *xml_node)
{
- const char *s;
+ char *s;
+ int result = -EINVAL;
if (!xml_node || !xmlnode_is_named(xml_node, "response"))
- return -EINVAL;
+ goto out;
for (xml_node = xml_node->children; xml_node; xml_node=xml_node->next) {
if (!xmlnode_get_text(xml_node, "hip-report-needed", &s)) {
- if (!strcmp(s, "no")) {
- free((void *)s);
- return 0;
- } else if (!strcmp(s, "yes")) {
- free((void *)s);
- return -EAGAIN;
- } else
- return -EINVAL;
+ if (!strcmp(s, "no"))
+ result = 0;
+ else if (!strcmp(s, "yes"))
+ result = -EAGAIN;
+ else
+ result = -EINVAL;
+ free(s);
+ goto out;
}
}
- return -EINVAL;
+out:
+ return result;
}
/* check if HIP report is needed (to ssl-vpn/hipreportcheck.esp) or submit HIP report contents (to ssl-vpn/hipreport.esp) */
@@ -696,7 +698,7 @@ static int run_hip_script(struct openconnect_info *vpninfo)
"VPN connectivity may be disabled or limited without HIP report submission.\n"
"You need to provide a --csd-wrapper argument with the HIP report submission script.\n"),
vpninfo->csd_token);
- /* Many GlobalProtect VPNs work fine despite allegedly requiring HIP report submission */
+ /* XXX: Many GlobalProtect VPNs work fine despite allegedly requiring HIP report submission */
return 0;
}
@@ -769,6 +771,27 @@ int gpst_setup(struct openconnect_info *vpninfo)
if (ret)
return ret;
+ /* Unlike CSD, the HIP security checker runs during the connection
+ phase, not during the authentication phase. Therefore we need
+ to build the CSD token (an MD5 digest identifying the client)
+ without relying on the authentication phase having run in the
+ same process. We build it from the cookie containing
+ authentication information, but exclude the volatile authcookie
+ field which changes from session to session. */
+ if (!vpninfo->csd_token) {
+ unsigned char md5[16];
+ int i;
+ char *excl_authcookie = strncmp(vpninfo->cookie, "authcookie=", 11) ? vpninfo->cookie : strchr(vpninfo->cookie, '&');
+ openconnect_md5(md5, excl_authcookie, strlen(excl_authcookie));
+ vpninfo->csd_token = malloc(MD5_SIZE * 2 + 1);
+ if (!vpninfo->csd_token) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ for (i=0; i < MD5_SIZE; i++)
+ sprintf(&vpninfo->csd_token[i*2], "%02x", md5[i]);
+ }
+
/* Check HIP */
ret = check_or_submit_hip_report(vpninfo, NULL);
if (ret == -EAGAIN) {
From b2096ba01aa53aa9e04703afe13ccd5bf7a28af3 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 20 Dec 2017 22:09:28 -0800
Subject: [PATCH 056/131] Protocols should explicitly request the same IPv4
address on reconnect, since they will abort if new addresses are sent by the
server.
This behavior is supported by AnyConnect (CONNECT with X-CSTP-Address header)
and by GlobalProtect (POST /ssl-vpn/getconfig.esp with preferred-ip form field).
There does not appear to be any obvious way for Juniper/NC to follow this behavior.
gpst.c already followed this behavior out of necessity, because GlobalProtect
servers tend to provide different IPv4 addresses upon reconnect, after even a brief
disconnection.
This patch reproduces this behavior in cstp.c; I did not make the corresponding
change for IPv6 because I have no way to test it.
---
cstp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/cstp.c b/cstp.c
index 5477c5c8..a22c66ed 100644
--- a/cstp.c
+++ b/cstp.c
@@ -262,6 +262,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
buf_append(reqbuf, "X-CSTP-MTU: %d\r\n", mtu);
buf_append(reqbuf, "X-CSTP-Address-Type: %s\r\n",
vpninfo->disable_ipv6 ? "IPv4" : "IPv6,IPv4");
+ /* Explicitly request the same IPv4 address on reconnect */
+ if (old_addr)
+ buf_append(reqbuf, "X-CSTP-Address: %s\r\n", old_addr);
if (!vpninfo->disable_ipv6)
buf_append(reqbuf, "X-CSTP-Full-IPv6-Capability: true\r\n");
#ifdef HAVE_DTLS
From 24bc277ebdbd438aa3020a06374f0cdb7cb1327e Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 20 Dec 2017 22:03:20 -0800
Subject: [PATCH 057/131] add --request-ip option to explicitly request a
specific IPv4 addresses
This behavior is supported by AnyConnect (CONNECT with X-CSTP-Address header)
and by GlobalProtect (POST /ssl-vpn/getconfig.esp with preferred-ip form field).
Currently, this option is only a request. OpenConnect will print an error
message, but will not abort, if the server assigns a different IPv4 address.
I did not implement the corresponding behavior for IPv6 because I do not
have a way to test it right now.
---
auth-globalprotect.c | 2 ++
cstp.c | 23 +++++++++++++++++------
gpst.c | 19 ++++++++++++++-----
main.c | 6 ++++++
openconnect.8.in | 6 ++++++
5 files changed, 45 insertions(+), 11 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 1449d8cd..dd3cb0da 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -295,6 +295,8 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
buf_append(request_body, "jnlpReady=jnlpReady&ok=Login&direct=yes&clientVer=4100&prot=https:");
append_opt(request_body, "server", vpninfo->hostname);
append_opt(request_body, "computer", vpninfo->localname);
+ if (vpninfo->ip_info.addr)
+ append_opt(request_body, "preferred-ip", vpninfo->ip_info.addr);
if (form->auth_id && form->auth_id[0]!='_')
append_opt(request_body, "inputStr", form->auth_id);
append_form_opts(vpninfo, form, request_body);
diff --git a/cstp.c b/cstp.c
index a22c66ed..3c35d05a 100644
--- a/cstp.c
+++ b/cstp.c
@@ -262,7 +262,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
buf_append(reqbuf, "X-CSTP-MTU: %d\r\n", mtu);
buf_append(reqbuf, "X-CSTP-Address-Type: %s\r\n",
vpninfo->disable_ipv6 ? "IPv4" : "IPv6,IPv4");
- /* Explicitly request the same IPv4 address on reconnect */
+ /* Explicitly request the same IPv4 address on reconnect (or on
+ * initial connection if specified with the --request-ip option)
+ */
if (old_addr)
buf_append(reqbuf, "X-CSTP-Address: %s\r\n", old_addr);
if (!vpninfo->disable_ipv6)
@@ -580,11 +582,20 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
mtu);
}
if (old_addr) {
- if (strcmp(old_addr, vpninfo->ip_info.addr)) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Reconnect gave different Legacy IP address (%s != %s)\n"),
- vpninfo->ip_info.addr, old_addr);
- return -EINVAL;
+ /* XXX: if --request-ip option is used, we'll have old_addr!=NULL even on the
+ first connection attempt, but if old_netmask is also non-NULL then we know
+ it's a reconnect. */
+ if (vpninfo->ip_info.addr==NULL || strcmp(old_addr, vpninfo->ip_info.addr)) {
+ if (!old_netmask)
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Legacy IP address %s was requested, but server provided %s\n"),
+ old_addr, vpninfo->ip_info.addr);
+ else {
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Reconnect gave different Legacy IP address (%s != %s)\n"),
+ vpninfo->ip_info.addr, old_addr);
+ return -EINVAL;
+ }
}
}
if (old_netmask) {
diff --git a/gpst.c b/gpst.c
index 9b8b3c6a..36652613 100644
--- a/gpst.c
+++ b/gpst.c
@@ -532,12 +532,21 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
goto out;
}
if (old_addr) {
+ /* XXX: if --request-ip option is used, we'll have old_addr!=NULL even on the
+ first connection attempt, but if old_netmask is also non-NULL then we know
+ it's a reconnect. */
if (strcmp(old_addr, vpninfo->ip_info.addr)) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Reconnect gave different Legacy IP address (%s != %s)\n"),
- vpninfo->ip_info.addr, old_addr);
- result = -EINVAL;
- goto out;
+ if (!old_netmask)
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Legacy IP address %s was requested, but server provided %s\n"),
+ old_addr, vpninfo->ip_info.addr);
+ else {
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Reconnect gave different Legacy IP address (%s != %s)\n"),
+ vpninfo->ip_info.addr, old_addr);
+ result = -EINVAL;
+ goto out;
+ }
}
}
if (old_netmask) {
diff --git a/main.c b/main.c
index 815c2206..b2fb10ab 100644
--- a/main.c
+++ b/main.c
@@ -188,6 +188,7 @@ enum {
OPT_LOCAL_HOSTNAME,
OPT_PROTOCOL,
OPT_PASSTOS,
+ OPT_REQUEST_IP,
};
#ifdef __sun__
@@ -269,6 +270,7 @@ static const struct option long_options[] = {
OPTION("dump-http-traffic", 0, OPT_DUMP_HTTP),
OPTION("no-system-trust", 0, OPT_NO_SYSTEM_TRUST),
OPTION("protocol", 1, OPT_PROTOCOL),
+ OPTION("request-ip", 1, OPT_REQUEST_IP),
#ifdef OPENCONNECT_GNUTLS
OPTION("gnutls-debug", 1, OPT_GNUTLS_DEBUG),
#endif
@@ -860,6 +862,7 @@ static void usage(void)
printf(" --resolve=HOST:IP %s\n", _("Use IP when connecting to HOST"));
printf(" --os=STRING %s\n", _("OS type (linux,linux-64,win,...) to report"));
printf(" --dtls-local-port=PORT %s\n", _("Set local port for DTLS datagrams"));
+ printf(" --request-ip=IP %s\n", _("Request a specific IPv4 address"));
print_supported_protocols_usage();
printf("\n");
@@ -1270,6 +1273,9 @@ int main(int argc, char **argv)
case OPT_AUTHGROUP:
authgroup = keep_config_arg();
break;
+ case OPT_REQUEST_IP:
+ vpninfo->ip_info.addr = keep_config_arg();
+ break;
case 'C':
vpninfo->cookie = dup_config_arg();
break;
diff --git a/openconnect.8.in b/openconnect.8.in
index 9f46b305..65b26f3c 100644
--- a/openconnect.8.in
+++ b/openconnect.8.in
@@ -66,6 +66,7 @@ openconnect \- Multi-protocol VPN client, for Cisco AnyConnect VPNs and others
.OP \-\-useragent string
.OP \-\-local-hostname string
.OP \-\-os string
+.OP \-\-request-ip ip
.B [https://]\fIserver\fB[:\fIport\fB][/\fIgroup\fB]
.YS
@@ -523,6 +524,11 @@ applied to the VPN session. If the gateway requires CSD, it will also cause
the corresponding CSD trojan binary to be downloaded, so you may need to use
.B \-\-csd\-wrapper
if this code is not executable on the local machine.
+.TP
+.B \-\-request-ip=IP
+Request a specific IPv4 address from the gateway. Currently, OpenConnect
+will print a warning but will not abort if the gateway provides a different
+IPv4 address.
.SH SIGNALS
In the data phase of the connection, the following signals are handled:
.TP
From eae475f28ffac946ac221af639a7b56003d2a4c9 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 20 Dec 2017 23:50:23 -0800
Subject: [PATCH 058/131] tap-dance around duplicate preferred-ip values
---
gpst.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/gpst.c b/gpst.c
index 36652613..92a3ebd9 100644
--- a/gpst.c
+++ b/gpst.c
@@ -491,7 +491,7 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
const char *old_addr = vpninfo->ip_info.addr, *old_netmask = vpninfo->ip_info.netmask;
const char *request_body_type = "application/x-www-form-urlencoded";
const char *method = "POST";
- char *xml_buf=NULL;
+ char *xml_buf=NULL, *p=NULL;
/* submit getconfig request */
buf_append(request_body, "client-type=1&protocol-version=p1&app-version=3.0.1-10");
@@ -499,9 +499,21 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
append_opt(request_body, "clientos", vpninfo->platname);
append_opt(request_body, "hmac-algo", "sha1,md5");
append_opt(request_body, "enc-algo", "aes-128-cbc,aes-256-cbc");
- if (old_addr)
+ if (old_addr) {
append_opt(request_body, "preferred-ip", old_addr);
- buf_append(request_body, "&%s", vpninfo->cookie);
+
+ /* XXX: our cookie might also contain a preferred-ip
+ * value. This could be a different value. We want
+ * to skip over it if we already set one.
+ */
+ if (p=strstr(vpninfo->cookie, "&preferred-ip="))
+ *p = 0;
+ buf_append(request_body, "&%s", vpninfo->cookie);
+ *p = '&';
+ if (p=strchr(p+1, '&'))
+ buf_append(request_body, "%s", p);
+ } else
+ buf_append(request_body, "&%s", vpninfo->cookie);
orig_path = vpninfo->urlpath;
vpninfo->urlpath = strdup("ssl-vpn/getconfig.esp");
From af838db4ade12ae500ed0cf2b22cc21064fe1439 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 1 Jan 2018 20:34:00 -0800
Subject: [PATCH 059/131] tweak comment (as suggested on #75)
---
hipreport.sh | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hipreport.sh b/hipreport.sh
index afc30679..a25cf139 100755
--- a/hipreport.sh
+++ b/hipreport.sh
@@ -1,6 +1,8 @@
#!/bin/sh
-# Read required variables from command line:
+# openconnect will call this script with the follow command-line
+# arguments, which are needed to populate the contents of the
+# HIP report:
#
# --cookie: a URL-encoded string, as output by openconnect
# --authenticate --protocol=gp, which includes parameters
@@ -18,6 +20,7 @@
# really matters is that the value in the HIP report
# submission should match the value in the HIP report check.
+# Read command line arguments into variables
COOKIE=
COMPUTER=
IP=
From 78fc32e5c378d7ab8c96b7afce6c1b78c7153dc8 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 7 Jan 2018 13:17:16 -0800
Subject: [PATCH 060/131] fix a very dumb string-handling bug (seen in #76)
FIXME: need a more consistent approach for the cases where we must keep or discard fields from the cookie
---
gpst.c | 26 +++++++++++---------------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/gpst.c b/gpst.c
index 92a3ebd9..4650e3e1 100644
--- a/gpst.c
+++ b/gpst.c
@@ -491,7 +491,7 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
const char *old_addr = vpninfo->ip_info.addr, *old_netmask = vpninfo->ip_info.netmask;
const char *request_body_type = "application/x-www-form-urlencoded";
const char *method = "POST";
- char *xml_buf=NULL, *p=NULL;
+ char *xml_buf=NULL;
/* submit getconfig request */
buf_append(request_body, "client-type=1&protocol-version=p1&app-version=3.0.1-10");
@@ -499,22 +499,18 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
append_opt(request_body, "clientos", vpninfo->platname);
append_opt(request_body, "hmac-algo", "sha1,md5");
append_opt(request_body, "enc-algo", "aes-128-cbc,aes-256-cbc");
- if (old_addr) {
+ /* XXX: If this is a reconnect *and* there was a preferred-ip
+ * specified on the initial connection (via --request-ip or the
+ * server caching our preferred IP), then our cookie might also
+ * contain a preferred-ip value--which could be different. We
+ * need to make sure the value from old_addr comes *after* the
+ * value from the cookie, so that it will override the value from
+ * the cookie.
+ */
+ buf_append(request_body, "&%s", vpninfo->cookie);
+ if (old_addr)
append_opt(request_body, "preferred-ip", old_addr);
- /* XXX: our cookie might also contain a preferred-ip
- * value. This could be a different value. We want
- * to skip over it if we already set one.
- */
- if (p=strstr(vpninfo->cookie, "&preferred-ip="))
- *p = 0;
- buf_append(request_body, "&%s", vpninfo->cookie);
- *p = '&';
- if (p=strchr(p+1, '&'))
- buf_append(request_body, "%s", p);
- } else
- buf_append(request_body, "&%s", vpninfo->cookie);
-
orig_path = vpninfo->urlpath;
vpninfo->urlpath = strdup("ssl-vpn/getconfig.esp");
result = do_https_request(vpninfo, method, request_body_type, request_body,
From 14b338e648efff40f199c023727c7fa5dac91646 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 7 Jan 2018 14:36:50 -0800
Subject: [PATCH 061/131] factor out and clean up build_csd_token(), and clean
up check_or_submit_hip_report()
---
gpst.c | 89 ++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 58 insertions(+), 31 deletions(-)
diff --git a/gpst.c b/gpst.c
index 4650e3e1..c7278cc7 100644
--- a/gpst.c
+++ b/gpst.c
@@ -637,7 +637,7 @@ static int gpst_connect(struct openconnect_info *vpninfo)
static int parse_hip_report_check(struct openconnect_info *vpninfo, xmlNode *xml_node)
{
- char *s;
+ const char *s;
int result = -EINVAL;
if (!xml_node || !xmlnode_is_named(xml_node, "response"))
@@ -651,7 +651,7 @@ static int parse_hip_report_check(struct openconnect_info *vpninfo, xmlNode *xml
result = -EAGAIN;
else
result = -EINVAL;
- free(s);
+ free((void *)s);
goto out;
}
}
@@ -660,6 +660,52 @@ static int parse_hip_report_check(struct openconnect_info *vpninfo, xmlNode *xml
return result;
}
+/* Unlike CSD, the HIP security checker runs during the connection
+ * phase, not during the authentication phase.
+ *
+ * The HIP security checker will (probably) ask us to resubmit the
+ * HIP report if either of the following changes:
+ * - Client IP address
+ * - Client HIP report md5sum
+ *
+ * I'm not sure what the md5sum is computed over in the official
+ * client, but it doesn't really matter.
+ *
+ * We just need an identifier for the combination of the local host
+ * and the VPN gateway which won't change when our IP address
+ * or authcookie are changed.
+ */
+static int build_csd_token(struct openconnect_info *vpninfo)
+{
+ struct oc_text_buf *buf;
+ unsigned char md5[16];
+ char *p, *endp;
+ int i;
+
+ if (vpninfo->csd_token)
+ return 0;
+
+ vpninfo->csd_token = malloc(MD5_SIZE * 2 + 1);
+ if (!vpninfo->csd_token)
+ return -ENOMEM;
+
+ /* use localname and cookie (excluding volatile authcookie and preferred-ip) to build md5sum */
+ buf = buf_alloc();
+ append_opt(buf, "computer", vpninfo->localname);
+ for (p=vpninfo->cookie; *p; p=(*endp) ? endp+1 : endp) {
+ endp = strchr(p, '&') ? : p+strlen(p);
+ if (strncmp(p, "authcookie=", 11) && strncmp(p, "preferred-ip=", 13))
+ buf_append(buf, "&%.*s", (int)(endp-p), p);
+ }
+
+ /* save as csd_token */
+ openconnect_md5(md5, buf->data, buf->pos);
+ for (i=0; i < MD5_SIZE; i++)
+ sprintf(&vpninfo->csd_token[i*2], "%02x", md5[i]);
+
+ return buf_free(buf);
+}
+
/* check if HIP report is needed (to ssl-vpn/hipreportcheck.esp) or submit HIP report contents (to ssl-vpn/hipreport.esp) */
static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const char *report)
{
@@ -670,19 +716,20 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
const char *method = "POST";
char *xml_buf=NULL, *orig_path;
- buf_truncate(request_body);
-
/* cookie gives us these fields: authcookie, portal, user, domain, and (maybe the unnecessary) preferred-ip */
- buf_truncate(request_body);
- buf_append(request_body, "%s", vpninfo->cookie);
+ buf_append(request_body, "client-role=global-protect-full&%s", vpninfo->cookie);
append_opt(request_body, "computer", vpninfo->localname);
append_opt(request_body, "client-ip", vpninfo->ip_info.addr);
- append_opt(request_body, "client-role", "global-protect-full");
if (report) {
- buf_ensure_space(request_body, strlen(report)*5);
+ /* XML report contains many characters requiring URL-encoding (%xx) */
+ buf_ensure_space(request_body, strlen(report)*3);
append_opt(request_body, "report", report);
- } else
+ } else {
+ result = build_csd_token(vpninfo);
+ if (result)
+ goto out;
append_opt(request_body, "md5", vpninfo->csd_token);
+ }
orig_path = vpninfo->urlpath;
vpninfo->urlpath = strdup(report ? "ssl-vpn/hipreport.esp" : "ssl-vpn/hipreportcheck.esp");
@@ -693,6 +740,7 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
result = gpst_xml_or_error(vpninfo, result, xml_buf, report ? NULL : parse_hip_report_check, NULL, NULL);
+out:
buf_free(request_body);
free(xml_buf);
return result;
@@ -786,28 +834,7 @@ int gpst_setup(struct openconnect_info *vpninfo)
/* Get configuration */
ret = gpst_get_config(vpninfo);
if (ret)
- return ret;
-
- /* Unlike CSD, the HIP security checker runs during the connection
- phase, not during the authentication phase. Therefore we need
- to build the CSD token (an MD5 digest identifying the client)
- without relying on the authentication phase having run in the
- same process. We build it from the cookie containing
- authentication information, but exclude the volatile authcookie
- field which changes from session to session. */
- if (!vpninfo->csd_token) {
- unsigned char md5[16];
- int i;
- char *excl_authcookie = strncmp(vpninfo->cookie, "authcookie=", 11) ? vpninfo->cookie : strchr(vpninfo->cookie, '&');
- openconnect_md5(md5, excl_authcookie, strlen(excl_authcookie));
- vpninfo->csd_token = malloc(MD5_SIZE * 2 + 1);
- if (!vpninfo->csd_token) {
- ret = -ENOMEM;
- goto out;
- }
- for (i=0; i < MD5_SIZE; i++)
- sprintf(&vpninfo->csd_token[i*2], "%02x", md5[i]);
- }
+ goto out;
/* Check HIP */
ret = check_or_submit_hip_report(vpninfo, NULL);
From 0db7ce05a5863e227c1690b2f3b133156bb97154 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 7 Jan 2018 15:57:41 -0800
Subject: [PATCH 062/131] cleanup cookie handling with filter_opts()
---
gpst.c | 52 +++++++++++++++++++++++++++++++++++-----------------
1 file changed, 35 insertions(+), 17 deletions(-)
diff --git a/gpst.c b/gpst.c
index c7278cc7..3849fec8 100644
--- a/gpst.c
+++ b/gpst.c
@@ -97,6 +97,33 @@ static const char *add_option(struct openconnect_info *vpninfo, const char *opt,
return new->value;
}
+
+static int filter_opts(struct oc_text_buf *buf, const char *query, const char *incexc, int include)
+{
+ const char *f, *endf, *eq;
+ const char *found, *comma;
+
+ for (f = query; *f; f=(*endf) ? endf+1 : endf) {
+ endf = strchr(f, '&') ? : f+strlen(f);
+ eq = strchr(f, '=');
+ if (!eq || eq > endf)
+ eq = endf;
+
+ for (found = incexc; *found; found=(*comma) ? comma+1 : comma) {
+ comma = strchr(found, ',') ? : found+strlen(found);
+ if (!strncmp(found, f, MAX(comma-found, eq-f)))
+ break;
+ }
+
+ if ((include && *found) || (!include && !*found)) {
+ if (buf->pos && buf->data[buf->pos-1] != '?' && buf->data[buf->pos-1] != '&')
+ buf_append(buf, "&");
+ buf_append_bytes(buf, f, (int)(endf-f));
+ }
+ }
+ return buf_error(buf);
+}
+
/* Parse this JavaScript-y mess:
"var respStatus = \"Challenge|Error\";\n"
@@ -499,17 +526,11 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
append_opt(request_body, "clientos", vpninfo->platname);
append_opt(request_body, "hmac-algo", "sha1,md5");
append_opt(request_body, "enc-algo", "aes-128-cbc,aes-256-cbc");
- /* XXX: If this is a reconnect *and* there was a preferred-ip
- * specified on the initial connection (via --request-ip or the
- * server caching our preferred IP), then our cookie might also
- * contain a preferred-ip value--which could be different. We
- * need to make sure the value from old_addr comes *after* the
- * value from the cookie, so that it will override the value from
- * the cookie.
- */
- buf_append(request_body, "&%s", vpninfo->cookie);
- if (old_addr)
+ if (old_addr) {
append_opt(request_body, "preferred-ip", old_addr);
+ filter_opts(request_body, vpninfo->cookie, "preferred-ip", 0);
+ } else
+ buf_append(request_body, "&%s", vpninfo->cookie);
orig_path = vpninfo->urlpath;
vpninfo->urlpath = strdup("ssl-vpn/getconfig.esp");
@@ -589,7 +610,9 @@ static int gpst_connect(struct openconnect_info *vpninfo)
return ret;
reqbuf = buf_alloc();
- buf_append(reqbuf, "GET /ssl-tunnel-connect.sslvpn?%s HTTP/1.1\r\n\r\n", vpninfo->cookie);
+ buf_append(reqbuf, "GET /ssl-tunnel-connect.sslvpn?");
+ filter_opts(reqbuf, vpninfo->cookie, "user,authcookie", 1);
+ buf_append(reqbuf, " HTTP/1.1\r\n\r\n");
if (vpninfo->dump_http_traffic)
dump_buf(vpninfo, '>', reqbuf->data);
@@ -679,7 +702,6 @@ static int build_csd_token(struct openconnect_info *vpninfo)
{
struct oc_text_buf *buf;
unsigned char md5[16];
- char *p, *endp;
int i;
if (vpninfo->csd_token)
@@ -692,11 +714,7 @@ static int build_csd_token(struct openconnect_info *vpninfo)
/* use localname and cookie (excluding volatile authcookie and preferred-ip) to build md5sum */
buf = buf_alloc();
append_opt(buf, "computer", vpninfo->localname);
- for (p=vpninfo->cookie; *p; p=(*endp) ? endp+1 : endp) {
- endp = strchr(p, '&') ? : p+strlen(p);
- if (strncmp(p, "authcookie=", 11) && strncmp(p, "preferred-ip=", 13))
- buf_append(buf, "&%.*s", (int)(endp-p), p);
- }
+ filter_opts(buf, vpninfo->cookie, "authcookie,preferred-ip", 0);
/* save as csd_token */
openconnect_md5(md5, buf->data, buf->pos);
From 270651d0ce1819c45d33b15c3617e1c0638d5ad5 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 7 Jan 2018 17:32:54 -0800
Subject: [PATCH 063/131] Save latest ESP sequence number even if replay
protection isn't in use
In the current source, incoming ESP sequence numbers
(vpninfo->esp_in[vpinfo->current_esp_in].seq) are not actually tracked at
all unless replay protection is in use.
At the time of a rekey, old_esp_maxseq is *set based on the current value of
the incoming seq* at the time of the switchover:
if (new_keys) {
vpninfo->old_esp_maxseq = vpninfo->esp_in[vpninfo->current_esp_in].seq + 32;
And then esp.c rejects packets with the old incoming SPI, unless seqp < old_esp_maxseq:
} else if (pkt->esp.spi == old_esp->spi &&
ntohl(pkt->esp.seq) + esp->seq < vpninfo->old_esp_maxseq) {
vpn_progress(vpninfo, PRG_TRACE,
_("Consider SPI 0x%x, seq %u against outgoing ESP setup\n"),
(unsigned)ntohl(old_esp->spi), (unsigned)ntohl(pkt->esp.seq));
if (decrypt_esp_packet(vpninfo, old_esp, pkt))
continue;
This code is supposed to allow a smooth handover from the old incoming SPI
to the new one after a rekey, so that in-flight packets from the old SPI
aren't totally dropped, but also aren't allowed to continue forever.
This patch tracks the latest sequence number even if ESP replay protection
isn't in use -- however inadvisable that may be -- allowing the handover to
work correctly.
This patch also improves the confusing trace message shown when a packet
from the old SPI is received.
---
esp.c | 2 +-
gnutls-esp.c | 2 ++
openssl-esp.c | 3 ++-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/esp.c b/esp.c
index 7876fd51..1b4b2275 100644
--- a/esp.c
+++ b/esp.c
@@ -299,7 +299,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
} else if (pkt->esp.spi == old_esp->spi &&
ntohl(pkt->esp.seq) + esp->seq < vpninfo->old_esp_maxseq) {
vpn_progress(vpninfo, PRG_TRACE,
- _("Consider SPI 0x%x, seq %u against outgoing ESP setup\n"),
+ _("Received ESP packet from old SPI 0x%x, seq %u\n"),
(unsigned)ntohl(old_esp->spi), (unsigned)ntohl(pkt->esp.seq));
if (decrypt_esp_packet(vpninfo, old_esp, pkt))
continue;
diff --git a/gnutls-esp.c b/gnutls-esp.c
index 916cbc7c..24d66201 100644
--- a/gnutls-esp.c
+++ b/gnutls-esp.c
@@ -166,6 +166,8 @@ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct
if (vpninfo->esp_replay_protect &&
verify_packet_seqno(vpninfo, esp, ntohl(pkt->esp.seq)))
return -EINVAL;
+ else
+ esp->seq = ntohl(pkt->esp.seq) + 1;
gnutls_cipher_set_iv(esp->cipher, pkt->esp.iv, sizeof(pkt->esp.iv));
diff --git a/openssl-esp.c b/openssl-esp.c
index c3dff510..8af838b9 100644
--- a/openssl-esp.c
+++ b/openssl-esp.c
@@ -204,7 +204,8 @@ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct
if (vpninfo->esp_replay_protect &&
verify_packet_seqno(vpninfo, esp, ntohl(pkt->esp.seq)))
return -EINVAL;
-
+ else
+ esp->seq = ntohl(pkt->esp.seq) + 1;
if (!EVP_DecryptInit_ex(esp->cipher, NULL, NULL, NULL,
pkt->esp.iv)) {
From 352aeb5d38c94142c651e4d9fbfa39b0e6457c47 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 8 Jan 2018 09:04:18 -0800
Subject: [PATCH 064/131] no good reason *not* to turn on ESP replay protection
for GP
(also, set old_esp_maxseq to ensure smooth handover when we rekey)
---
gpst.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/gpst.c b/gpst.c
index 3849fec8..6dc26484 100644
--- a/gpst.c
+++ b/gpst.c
@@ -408,6 +408,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
vpninfo->ip_info.domain = NULL;
vpninfo->ip_info.mtu = 0;
vpninfo->esp_magic = inet_addr(vpninfo->ip_info.gateway_addr);
+ vpninfo->esp_replay_protect = 1;
vpninfo->ssl_times.rekey_method = REKEY_NONE;
vpninfo->cstp_options = NULL;
@@ -470,6 +471,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
#ifdef HAVE_ESP
if (vpninfo->dtls_state != DTLS_DISABLED) {
int c = (vpninfo->current_esp_in ^= 1);
+ vpninfo->old_esp_maxseq = vpninfo->esp_in[c^1].seq + 32;
for (member = xml_node->children; member; member=member->next) {
s = NULL;
if (!xmlnode_get_text(member, "udp-port", &s)) udp_sockaddr(vpninfo, atoi(s));
From 6b01bc6298b025fec5ec68607ca176981a75dbcc Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 8 Jan 2018 19:02:48 -0800
Subject: [PATCH 065/131] Fix a really subtle bug causing 100% CPU utilization
after ESP failure and tunnel reconnect (this should fix #76)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Here's what was happening:
1. GlobalProtect connect, start ESP
-> dtls_state = DTLS_CONNECTED, dtls_fd is read-monitored
2. ESP tunnel fails and GP switches to HTTPS (due to network outage, dead peer?),
-> dtls_state = DTLS_NOSECRET, dtls_fd is still read-monitored (!!!)
3. Tunnel restarts (due to rekey or pause-and-reconnect signal, USR2) and
/ssl-vpn/getconfig.esp is repulled, including new ESP keys.
-> dtls_state = DTLS_SECRET, dtls_fd is still read-monitored (!!!)
4. ESP probes are sent out *once* in esp_setup(), but dtls_fd != -1, so the
dtls_state is *not* upgraded to DTLS_SLEEPING.
-> dtls_state = DTLS_SECRET, dtls_fd is still read-monitored (!!!)
As a result of the probes being sent out, ESP packets will subsequently arrive
and select() call in openconnect_mainloop() will wake up… but
udp_mainloop() will never be called to service it because…
if (vpninfo->dtls_state > DTLS_DISABLED) {
...
ret = vpninfo->proto->udp_mainloop(vpninfo, &timeout);
}
This patch fixes that by not just setting dtls_state = DTLS_SECRET when the
HTTPS tunnel connects, but actually calling esp_close_secret (which closes
dtls_fd, unmonitors it, and sets it to -1).
---
esp.c | 3 ++-
gpst.c | 3 +--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/esp.c b/esp.c
index 1b4b2275..7f10114f 100644
--- a/esp.c
+++ b/esp.c
@@ -458,7 +458,8 @@ void esp_close(struct openconnect_info *vpninfo)
void esp_close_secret(struct openconnect_info *vpninfo)
{
esp_close(vpninfo);
- vpninfo->dtls_state = DTLS_NOSECRET;
+ if (vpninfo->dtls_state > DTLS_DISABLED)
+ vpninfo->dtls_state = DTLS_NOSECRET;
}
void esp_shutdown(struct openconnect_info *vpninfo)
diff --git a/gpst.c b/gpst.c
index 6dc26484..0cabf0df 100644
--- a/gpst.c
+++ b/gpst.c
@@ -653,8 +653,7 @@ static int gpst_connect(struct openconnect_info *vpninfo)
monitor_read_fd(vpninfo, ssl);
monitor_except_fd(vpninfo, ssl);
vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
- if (vpninfo->dtls_state != DTLS_DISABLED)
- vpninfo->dtls_state = DTLS_NOSECRET;
+ esp_close_secret(vpninfo);
}
return ret;
From 86c2dea957bf2f397096b2f78bf2e4e2dd2aa2d9 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 8 Jan 2018 21:07:55 -0800
Subject: [PATCH 066/131] simplify esp.c by reusing ka_check_deadline()
function
---
esp.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/esp.c b/esp.c
index 7f10114f..a768f1bd 100644
--- a/esp.c
+++ b/esp.c
@@ -253,15 +253,12 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
int ret;
if (vpninfo->dtls_state == DTLS_SLEEPING) {
- int when = vpninfo->new_dtls_started + vpninfo->dtls_attempt_period - time(NULL);
- if (when <= 0 || vpninfo->dtls_need_reconnect) {
+ if (ka_check_deadline(timeout, time(NULL), vpninfo->new_dtls_started + vpninfo->dtls_attempt_period)
+ || vpninfo->dtls_need_reconnect) {
vpn_progress(vpninfo, PRG_DEBUG, _("Send ESP probes\n"));
if (vpninfo->proto->udp_send_probes)
vpninfo->proto->udp_send_probes(vpninfo);
- when = vpninfo->dtls_attempt_period;
}
- if (*timeout > when * 1000)
- *timeout = when * 1000;
}
if (vpninfo->dtls_fd == -1)
return 0;
From 9891d2dc3b9c79b1d31e0965b0ccd5f35e4e0cbb Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 8 Jan 2018 21:18:02 -0800
Subject: [PATCH 067/131] ensure openconnect will actually compile with
!defined(HAVE_ESP)
---
gpst.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/gpst.c b/gpst.c
index 0cabf0df..b717c2af 100644
--- a/gpst.c
+++ b/gpst.c
@@ -356,6 +356,7 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
return mtu;
}
+#ifdef HAVE_ESP
static int set_esp_algo(struct openconnect_info *vpninfo, const char *s, int hmac)
{
if (hmac) {
@@ -388,6 +389,7 @@ static int get_key_bits(xmlNode *xml_node, unsigned char *dest)
}
return (bits == 0) ? 0 : -EINVAL;
}
+#endif
/* Return value:
* < 0, on error
@@ -490,7 +492,8 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
if (setup_esp_keys(vpninfo, 0))
vpn_progress(vpninfo, PRG_ERR, "Failed to setup ESP keys.\n");
else
- vpninfo->dtls_times.last_rekey = time(NULL);
+ /* prevent race condition between esp_mainloop() and gpst_mainloop() timers */
+ vpninfo->dtls_times.last_rekey = time(&vpninfo->new_dtls_started);
}
#else
vpn_progress(vpninfo, PRG_DEBUG, _("Ignoring ESP keys since ESP support not available in this build\n"));
@@ -653,7 +656,8 @@ static int gpst_connect(struct openconnect_info *vpninfo)
monitor_read_fd(vpninfo, ssl);
monitor_except_fd(vpninfo, ssl);
vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
- esp_close_secret(vpninfo);
+ if (vpninfo->proto->udp_close)
+ vpninfo->proto->udp_close(vpninfo);
}
return ret;
@@ -901,7 +905,7 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
return 0;
case DTLS_SECRET:
case DTLS_SLEEPING:
- if (!ka_check_deadline(timeout, time(NULL), vpninfo->dtls_times.last_rekey + 5)) {
+ if (!ka_check_deadline(timeout, time(NULL), vpninfo->new_dtls_started + 5)) {
/* Allow 5 seconds after configuration for ESP to start */
return 0;
} else {
@@ -1060,7 +1064,8 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
vpninfo->quit_reason = "GPST reconnect failed";
return ret;
}
- esp_setup(vpninfo, vpninfo->dtls_attempt_period);
+ if (vpninfo->proto->udp_setup)
+ vpninfo->proto->udp_setup(vpninfo, vpninfo->dtls_attempt_period);
return 1;
case KA_KEEPALIVE:
From ea4307daa120ee82a724a97508dca4d2f7be9d2e Mon Sep 17 00:00:00 2001
From: Dan Lenski
Date: Wed, 10 Jan 2018 12:36:13 -0800
Subject: [PATCH 068/131] Update PAN_GlobalProtect_protocol_doc.md
---
PAN_GlobalProtect_protocol_doc.md | 66 +++++++++++++++++++++++++++----
1 file changed, 58 insertions(+), 8 deletions(-)
diff --git a/PAN_GlobalProtect_protocol_doc.md b/PAN_GlobalProtect_protocol_doc.md
index d1a19c52..3f88ecf9 100644
--- a/PAN_GlobalProtect_protocol_doc.md
+++ b/PAN_GlobalProtect_protocol_doc.md
@@ -1,4 +1,8 @@
-This is an anonymized log of the authentication, configuration, tunnel data transfer, and logout interactions between a [PAN](http://www.paloaltonetworks.com) GlobalProtect VPN server and client (Windows client, v3.0.1-10).
+This is an anonymized log of the authentication, configuration, tunnel data transfer, and logout interactions between a
+[PAN](http://www.paloaltonetworks.com) GlobalProtect VPN server and client. The logs below are based on the official Windows
+client, v3.0.1-10, with some updates from v4.0.5-8.
+
+Client version 4.0 [adds IPv6 support](https://live.paloaltonetworks.com/t5/Colossal-Event-Blog/New-GlobalProtect-4-0-announced-with-IPv6-support/ba-p/141593) and SAML authentication support.
The correct user-agent (`User-Agent: PAN Globalprotect`) is **required** for all HTTP interactions with the GlobalProtect VPN. It treats any other user-agent as a web browser, not a VPN client.
@@ -38,6 +42,20 @@ portal-prelogonuserauthcookie: empty
host-id: deadbeef-dead-beef-dead-beefdeadbeef
```
+New parameters sent by Windows client v4.0.5-8:
+
+```
+clientgpversion: 4.0.5-8
+prelogin-cookie:
+ipv6-support: yes
+client-ip: 34.56.78.90
+client-ipv6: .
+preferred-ipv6:
+```
+
+The `client-ip{,v6}` parameters refer to the client's _external_ internet-facing IP address, while `preferred-ip{,v6}` parameters
+refer to the expected/desired addresses within the VPN.
+
Successful login response
=========================
@@ -70,11 +88,20 @@ In order to handle the getconfig, tunnel-connect, and logon requests properly (d
tunnel
-1
4100
- preferred ip address as provided above
+ preferred IP address as sent in request
```
+Windows client v4.0.5-8 receives additional input-parroting arguments at the end:
+
+```xml
+ portal-userauthcookie as sent in request
+ prelogon-userauthcookie as sent in request
+ preferred IPv6 address as sent in request
+```
+
+
getconfig request
=================
@@ -108,6 +135,17 @@ enc-algo: aes-256-gcm,aes-128-gcm,aes-128-cbc,
hmac-algo: sha1,
```
+Windows client v4.0.5-8 adds additional parameters at the end:
+
+```xml
+app-version: 4.0.5-8
+addr1-v6-1: f00f::/16
+addr1-v6-2: f00f:dead:beef::dead:beef/128
+preferred-ipv6:
+hmac-algo: sha1,.
+```
+
+
Response #2 (getconfig)
=======================
@@ -190,14 +228,22 @@ In the back-and-forth flows shown below, `<` means sent by the gateway, `>` mean
### ESP-over-UDP
-Uses the keying information obtained in response to the `getconfig` request. In order to initiate the connection, the client sends 3 ESP-encapsulated ICMP request ("ping") packets to the gateway. They are sent _from_ the client's in-VPN IP address _to_ the IP address specified by the `` from the `getconfig` response (this is normally the same as the gateway's **public** IP address, but is sometimes a VPN-internal address ¯\\\_(ツ)\_/¯). These ICMP request packets include the following magic payload:
+Uses the keying information obtained in response to the `getconfig` request. In order to initiate the connection, the client sends 3 ICMP request ("ping") packets to the gateway.
- "monitor\x00\x00pan ha 0123456789:;<=>? !\"#$%&\'()*+,-./\x10\x11\x12\x13\x14\x15\x16\x18"
- "monitor\x00\x00pan ha " (first 16 bytes)
+* These packets are ESP-encapsulated
+* These packets are sent _from_ **the client's in-VPN IP address** _to_ **the IP address specified by the `` from
+ the `getconfig` response**.
+ * The destination address is usually the same as the gateway's **public** internet-facing IP address, but sometimes it is a
+ VPN-internal address ¯\\\_(ツ)\_/¯
+* These ICMP request packets include the following magic payload — though only the first 16 bytes of the payload appear
+ to be necessary to elicit a response from the gateway.
-Only the first 16 bytes of the payload appear to be necessary to elicit a response from the gateway. Once the gateway has responded with a corresponding ICMP reply, the client and server send and receive arbitrary ESP-encapsulated traffic.
+ "monitor\x00\x00pan ha 0123456789:;<=>? !\"#$%&\'()*+,-./\x10\x11\x12\x13\x14\x15\x16\x18"
+ "monitor\x00\x00pan ha " (first 16 bytes)
-The client continues to periodically send the "magic ping" packets as a keepalive.
+* Once the gateway has responded with a corresponding ICMP reply, the client and server send and receive arbitrary
+ ESP-encapsulated traffic.
+* The client continues to periodically send the same "magic ping" packets as a keepalive.
### SSL vpn tunnel
@@ -264,5 +310,9 @@ Successful logout response
company domain name
Myusername
DEADBEEF01
+
+
+
+
-```
\ No newline at end of file
+```
From 8b08f9f44a1bdf2bd33f2c21db3e0f777787c8b5 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 12 Jan 2018 00:04:48 -0800
Subject: [PATCH 069/131] add test login script
---
...t-config.py => test-globalprotect-login.py | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
rename get-globalprotect-config.py => test-globalprotect-login.py (59%)
diff --git a/get-globalprotect-config.py b/test-globalprotect-login.py
similarity index 59%
rename from get-globalprotect-config.py
rename to test-globalprotect-login.py
index 6eed9fae..db701482 100755
--- a/get-globalprotect-config.py
+++ b/test-globalprotect-login.py
@@ -1,6 +1,7 @@
#!/usr/bin/python
from __future__ import print_function
+from urlparse import urlparse
import requests
import argparse
import getpass
@@ -9,15 +10,20 @@
p = argparse.ArgumentParser()
p.add_argument('-v','--verbose', default=0, action='count')
-p.add_argument('portal', help='Hostname of GlobalProtect portal')
+p.add_argument('endpoint', help='GlobalProtect server; can append /ssl-vpn/login.esp (default) or /global-protect/getconfig.esp')
g = p.add_argument_group('Login credentials')
-g.add_argument('--user', help='Username (will prompt if unspecified)')
-g.add_argument('--password', help='Password (will prompt if unspecified)')
-g.add_argument('--cert', help='PEM file containing client certificate (and optionally private key)')
+g.add_argument('-u','--user', help='Username (will prompt if unspecified)')
+g.add_argument('-p','--password', help='Password (will prompt if unspecified)')
+g.add_argument('-c','--cert', help='PEM file containing client certificate (and optionally private key)')
g.add_argument('--key', help='PEM file containing client private key (if not included in same file as certificate)')
g.add_argument('--no-verify', dest='verify', action='store_false', default=True, help='Ignore invalid server certificate')
args = p.parse_args()
+endpoint = urlparse(('https://' if '//' not in args.endpoint else '') + args.endpoint, 'https:')
+if not endpoint.path:
+ print("Endpoint path unspecified: defaulting to /ssl-vpn/login.esp", file=stderr)
+ endpoint = endpoint._replace(path = '/ssl-vpn/login.esp')
+
if args.cert and args.key:
cert = (args.cert, args.key)
elif args.cert:
@@ -37,13 +43,15 @@
s.cert = cert
# same request params work for /global-protect/getconfig.esp as for /ssl-vpn/login.esp
-login = 'https://{}/global-protect/getconfig.esp'.format(args.portal)
-res = s.post(login, verify=args.verify, data=dict(user=args.user, passwd=args.password,
+res = s.post(endpoint.geturl(), verify=args.verify, data=dict(user=args.user, passwd=args.password,
# required
jnlpReady='jnlpReady', ok='Login', direct='yes',
# optional but might affect behavior
clientVer=4100, server=args.portal, prot='https:',
- computer='localhost'))
+ computer=os.uname()[1]))
+
+if args.verbose:
+ print("Request body:\n", res.request.content, file=stderr)
res.raise_for_status()
print(res.text)
From be074cd5f988a74c503dde2e6beccdb6c7a13dfa Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 11 Jan 2018 12:25:40 -0800
Subject: [PATCH 070/131] Smarter MTU calculation for GlobalProtect
- If we have no ESP support, ESP disabled, or no ESP keys received, then
we're definitely using the TLS tunne and we should calculate tunnel MTU
based on the TCP MSS, subtracting the TLS+GPST overhead (and only use the
base/wire MTU as a crude fallback if necessary).
- If we've got ESP enabled and ESP keys, then we should calculate tunnel
MTU based on the base/wire MTU, subtracting the IP+UDP+ESP overhead.
---
gpst.c | 43 ++++++++++++++++++++++++++++++-------------
1 file changed, 30 insertions(+), 13 deletions(-)
diff --git a/gpst.c b/gpst.c
index b717c2af..f017a66d 100644
--- a/gpst.c
+++ b/gpst.c
@@ -295,15 +295,17 @@ int gpst_xml_or_error(struct openconnect_info *vpninfo, int result, char *respon
1 /* pad length */ + 1 /* next header */ + \
16 /* max padding */ )
#define UDP_HEADER_SIZE 8
+#define TCP_HEADER_SIZE 20 /* with no options */
#define IPV4_HEADER_SIZE 20
#define IPV6_HEADER_SIZE 40
static int calculate_mtu(struct openconnect_info *vpninfo)
{
int mtu = vpninfo->reqmtu, base_mtu = vpninfo->basemtu;
+ int mss = 0;
#if defined(__linux__) && defined(TCP_INFO)
- if (!mtu || !base_mtu) {
+ if (!mtu) {
struct tcp_info ti;
socklen_t ti_size = sizeof(ti);
@@ -317,23 +319,19 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
base_mtu = ti.tcpi_pmtu;
}
- if (!base_mtu) {
- if (ti.tcpi_rcv_mss < ti.tcpi_snd_mss)
- base_mtu = ti.tcpi_rcv_mss - 13;
- else
- base_mtu = ti.tcpi_snd_mss - 13;
- }
+ /* XXX: GlobalProtect has no mechanism to inform the server about the
+ * desired MTU, so could just ignore the "incoming" MSS (tcpi_rcv_mss).
+ */
+ mss = MIN(ti.tcpi_rcv_mss, ti.tcpi_snd_mss);
}
}
#endif
#ifdef TCP_MAXSEG
- if (!base_mtu) {
- int mss;
+ if (!mtu && !mss) {
socklen_t mss_size = sizeof(mss);
if (!getsockopt(vpninfo->ssl_fd, IPPROTO_TCP, TCP_MAXSEG,
&mss, &mss_size)) {
vpn_progress(vpninfo, PRG_DEBUG, _("TCP_MAXSEG %d\n"), mss);
- base_mtu = mss - 13;
}
}
#endif
@@ -345,13 +343,32 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
if (base_mtu < 1280)
base_mtu = 1280;
- if (!mtu) {
- /* remove IP/UDP and ESP overhead from base MTU to calculate tunnel MTU */
- mtu = base_mtu - ESP_OVERHEAD - UDP_HEADER_SIZE;
+#ifdef HAVE_ESP
+ /* If we can use the ESP tunnel (got secrets in config),
+ * then we should pick the optimal MTU for ESP.
+ */
+ if (!mtu && vpninfo->dtls_state == DTLS_SECRET) {
if (vpninfo->peer_addr->sa_family == AF_INET6)
mtu -= IPV6_HEADER_SIZE;
else
mtu -= IPV4_HEADER_SIZE;
+
+ } else
+#endif
+
+ /* We are definitely using the TLS tunnel (no ESP secrets)
+ * so we should base our MTU on the TCP MSS.
+ */
+ if (!mtu) {
+ if (mss)
+ mtu = mss - 21;
+ else {
+ mtu = base_mtu - TCP_HEADER_SIZE - 21;
+ if (vpninfo->peer_addr->sa_family == AF_INET6)
+ mtu -= IPV6_HEADER_SIZE;
+ else
+ mtu -= IPV4_HEADER_SIZE;
+ }
}
return mtu;
}
From da1e0ab18b872c991a9b99f10a5d14e4bdb9422a Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 12 Jan 2018 02:08:40 -0800
Subject: [PATCH 071/131] properly handle alternate GPST tunnel path
---
gpst.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gpst.c b/gpst.c
index f017a66d..a2fa676e 100644
--- a/gpst.c
+++ b/gpst.c
@@ -444,6 +444,11 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
else if (!xmlnode_get_text(xml_node, "mtu", &s)) {
vpninfo->ip_info.mtu = atoi(s);
free((void *)s);
+ } else if (!xmlnode_get_text(xml_node, "ssl-tunnel-url", &s)) {
+ free(vpninfo->urlpath);
+ vpninfo->urlpath = (char *)s;
+ if (strcmp(s, "/ssl-tunnel-connect.sslvpn"))
+ vpn_progress(vpninfo, PRG_INFO, _("Non-standard SSL tunnel path: %s\n"), s);
} else if (!xmlnode_get_text(xml_node, "timeout", &s)) {
int sec = atoi(s);
vpn_progress(vpninfo, PRG_INFO, _("Tunnel timeout (rekey interval) is %d minutes.\n"), sec/60);
@@ -632,7 +637,7 @@ static int gpst_connect(struct openconnect_info *vpninfo)
return ret;
reqbuf = buf_alloc();
- buf_append(reqbuf, "GET /ssl-tunnel-connect.sslvpn?");
+ buf_append(reqbuf, "GET %s?", vpninfo->urlpath);
filter_opts(reqbuf, vpninfo->cookie, "user,authcookie", 1);
buf_append(reqbuf, " HTTP/1.1\r\n\r\n");
From 99734342702b531ec4beb8c0d8a7d46efcb655d4 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 12 Jan 2018 17:26:58 -0800
Subject: [PATCH 072/131] Replace static auth form for GlobalProtect portal
with a dynamic auth form
(Also adds more memory-allocation checks to the portal auth form)
---
auth-globalprotect.c | 120 +++++++++++++++++++++++++----------------
http.c | 13 +++++
openconnect-internal.h | 1 +
3 files changed, 87 insertions(+), 47 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index dd3cb0da..3c4ba99b 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -146,105 +146,131 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
static int parse_portal_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
{
- static struct oc_auth_form form = {.message=(char *)"Please select GlobalProtect gateway.", .auth_id=(char *)"_portal"};
-
- xmlNode *x;
+ struct oc_auth_form *form;
+ xmlNode *x = NULL;
struct oc_form_opt_select *opt;
- struct oc_text_buf *buf;
+ struct oc_text_buf *buf = NULL;
int max_choices = 0, result;
char *portal = NULL;
- opt = calloc(1, sizeof(*opt));
- if (!opt)
+ form = calloc(1, sizeof(*form));
+ if (!form)
return -ENOMEM;
+
+ form->message = strdup(_("Please select GlobalProtect gateway."));
+ form->auth_id = strdup("_portal");
+
+ opt = form->authgroup_opt = calloc(1, sizeof(*opt));
+ if (!opt) {
+ result = -ENOMEM;
+ goto out;
+ }
opt->form.type = OC_FORM_OPT_SELECT;
opt->form.name = strdup("gateway");
opt->form.label = strdup(_("GATEWAY:"));
+ form->opts = (void *)opt;
/* The portal contains a ton of stuff, but basically none of it is useful to a VPN client
* that wishes to give control to the client user, as opposed to the VPN administrator.
* The exception is the list of gateways in policy/gateways/external/list
*/
- if (xmlnode_is_named(xml_node, "policy"))
- for (xml_node = xml_node->children; xml_node; xml_node=xml_node->next)
- if (xmlnode_is_named(xml_node, "portal-name"))
- portal = (char *)xmlNodeGetContent(xml_node);
- else if (xmlnode_is_named(xml_node, "gateways"))
- for (xml_node = xml_node->children; xml_node; xml_node=xml_node->next)
- if (xmlnode_is_named(xml_node, "external"))
- for (xml_node = xml_node->children; xml_node; xml_node=xml_node->next)
- if (xmlnode_is_named(xml_node, "list"))
- goto gateways;
+ if (xmlnode_is_named(xml_node, "policy")) {
+ for (x = xml_node->children, xml_node = NULL; x; x = x->next) {
+ if (xmlnode_is_named(x, "portal-name"))
+ portal = (char *)xmlNodeGetContent(x);
+ else if (xmlnode_is_named(x, "gateways"))
+ xml_node = x;
+ }
+ }
+
+ if (xml_node) {
+ for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next)
+ if (xmlnode_is_named(xml_node, "external"))
+ for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next)
+ if (xmlnode_is_named(xml_node, "list"))
+ goto gateways;
+ }
result = -EINVAL;
- free(portal);
goto out;
gateways:
- buf = buf_alloc();
- buf_append(buf, "\n \n");
- if (portal) {
- buf_append(buf, " %s%s", portal, vpninfo->hostname);
- if (vpninfo->port!=443)
- buf_append(buf, ":%d", vpninfo->port);
- buf_append(buf, "/global-protect\n");
+ if (vpninfo->write_new_config) {
+ buf = buf_alloc();
+ buf_append(buf, "\n \n");
+ if (portal) {
+ buf_append(buf, " ");
+ buf_append_xmlescaped(buf, portal);
+ buf_append(buf, "%s", vpninfo->hostname);
+ if (vpninfo->port!=443)
+ buf_append(buf, ":%d", vpninfo->port);
+ buf_append(buf, "/global-protect\n");
+ }
}
- free(portal);
/* first, count the number of gateways */
- for (x = xml_node->children; x; x=x->next)
+ for (x = xml_node->children; x; x = x->next)
if (xmlnode_is_named(x, "entry"))
max_choices++;
- opt->choices = calloc(1, max_choices * sizeof(struct oc_choice *));
+ opt->choices = calloc(max_choices, sizeof(opt->choices[0]));
if (!opt->choices) {
- free_opt((struct oc_form_opt *)opt);
- return -ENOMEM;
+ result = -ENOMEM;
+ goto out;
}
/* each entry looks like Label */
vpn_progress(vpninfo, PRG_INFO, _("%d gateway servers available:\n"), max_choices);
- for (xml_node = xml_node->children; xml_node; xml_node=xml_node->next) {
+ for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
if (xmlnode_is_named(xml_node, "entry")) {
struct oc_choice *choice = calloc(1, sizeof(*choice));
if (!choice) {
- free_opt((struct oc_form_opt *)opt);
- return -ENOMEM;
+ result = -ENOMEM;
+ goto out;
}
xmlnode_get_prop(xml_node, "name", &choice->name);
for (x = xml_node->children; x; x=x->next)
- if (xmlnode_is_named(x, "description"))
- buf_append(buf, " %s%s/ssl-vpn\n",
- choice->label = (char *)xmlNodeGetContent(x),
- choice->name);
+ if (xmlnode_is_named(x, "description")) {
+ choice->label = (char *)xmlNodeGetContent(x);
+ if (vpninfo->write_new_config) {
+ buf_append(buf, " ");
+ buf_append_xmlescaped(buf, choice->label);
+ buf_append(buf, "%s/ssl-vpn\n",
+ choice->name);
+ }
+ }
opt->choices[opt->nr_choices++] = choice;
vpn_progress(vpninfo, PRG_INFO, _(" %s (%s)\n"),
- choice->label, choice->name);
+ choice->label, choice->name);
}
}
- buf_append(buf, " \n\n");
- if (vpninfo->write_new_config)
- result = vpninfo->write_new_config(vpninfo->cbdata, buf->data, buf->pos);
- buf_free(buf);
+ if (vpninfo->write_new_config) {
+ buf_append(buf, " \n\n");
+ if ((result = buf_error(buf)))
+ goto out;
+ if ((result = vpninfo->write_new_config(vpninfo, buf->data, buf->pos)))
+ goto out;
+ }
- /* process static auth form to select gateway */
- form.opts = (struct oc_form_opt *)(form.authgroup_opt = opt);
- result = process_auth_form(vpninfo, &form);
+ /* process auth form to select gateway */
+ result = process_auth_form(vpninfo, form);
if (result != OC_FORM_RESULT_NEWGROUP)
goto out;
/* redirect to the gateway (no-op if it's the same host) */
- if ((vpninfo->redirect_url = malloc(strlen(vpninfo->authgroup) + 9)) == NULL) {
+ free(vpninfo->redirect_url);
+ if (asprintf(&vpninfo->redirect_url, "https://%s", vpninfo->authgroup) == 0) {
result = -ENOMEM;
goto out;
}
- sprintf(vpninfo->redirect_url, "https://%s", vpninfo->authgroup);
result = handle_redirect(vpninfo);
out:
- free_opt((struct oc_form_opt *)opt);
+ buf_free(buf);
+ free(portal);
+ free_auth_form(form);
return result;
}
diff --git a/http.c b/http.c
index 29602966..35f5ae39 100644
--- a/http.c
+++ b/http.c
@@ -54,6 +54,19 @@ void buf_append_urlencoded(struct oc_text_buf *buf, const char *str)
}
}
+void buf_append_xmlescaped(struct oc_text_buf *buf, const char *str)
+{
+ while (str && *str) {
+ unsigned char c = *str;
+ if (c=='<' || c=='>' || c=='&' || c=='"' || c=='\'')
+ buf_append(buf, "%02x;", c);
+ else
+ buf_append_bytes(buf, str, 1);
+
+ str++;
+ }
+}
+
void buf_append_hex(struct oc_text_buf *buf, const void *str, unsigned len)
{
const unsigned char *data = str;
diff --git a/openconnect-internal.h b/openconnect-internal.h
index a1931513..f42d6ecf 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -1039,6 +1039,7 @@ int get_utf8char(const char **utf8);
void buf_append_from_utf16le(struct oc_text_buf *buf, const void *utf16);
void buf_truncate(struct oc_text_buf *buf);
void buf_append_urlencoded(struct oc_text_buf *buf, const char *str);
+void buf_append_xmlescaped(struct oc_text_buf *buf, const char *str);
int buf_error(struct oc_text_buf *buf);
int buf_free(struct oc_text_buf *buf);
char *openconnect_create_useragent(const char *base);
From a99b6e2281584d37a0475b0b0a2e381abd35f51b Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 12 Jan 2018 18:07:13 -0800
Subject: [PATCH 073/131] Check all oc_text_buf for errors (e.g. out-of-memory)
before using their contents
---
auth-globalprotect.c | 8 ++++++--
gpst.c | 26 +++++++++++++++++++-------
2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 3c4ba99b..17712c93 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -135,8 +135,7 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
}
vpninfo->cookie = strdup(cookie->data);
- buf_free(cookie);
- return 0;
+ return buf_free(cookie);
err_out:
free((void *)value);
@@ -326,6 +325,8 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
if (form->auth_id && form->auth_id[0]!='_')
append_opt(request_body, "inputStr", form->auth_id);
append_form_opts(vpninfo, form, request_body);
+ if ((result = buf_error(request_body)))
+ goto out;
orig_path = vpninfo->urlpath;
vpninfo->urlpath = strdup(portal ? "global-protect/getconfig.esp" : "ssl-vpn/login.esp");
@@ -403,6 +404,8 @@ int gpst_bye(struct openconnect_info *vpninfo, const char *reason)
*/
append_opt(request_body, "computer", vpninfo->localname);
buf_append(request_body, "&%s", vpninfo->cookie);
+ if ((result = buf_error(request_body)))
+ goto out;
/* We need to close and reopen the HTTPS connection (to kill
* the tunnel session) and submit a new HTTPS request to
@@ -425,6 +428,7 @@ int gpst_bye(struct openconnect_info *vpninfo, const char *reason)
else
vpn_progress(vpninfo, PRG_INFO, _("Logout successful\n"));
+out:
buf_free(request_body);
free(xml_buf);
return result;
diff --git a/gpst.c b/gpst.c
index a2fa676e..1a9e121e 100644
--- a/gpst.c
+++ b/gpst.c
@@ -558,6 +558,8 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
filter_opts(request_body, vpninfo->cookie, "preferred-ip", 0);
} else
buf_append(request_body, "&%s", vpninfo->cookie);
+ if ((result = buf_error(request_body)))
+ goto out;
orig_path = vpninfo->urlpath;
vpninfo->urlpath = strdup("ssl-vpn/getconfig.esp");
@@ -626,6 +628,7 @@ static int gpst_connect(struct openconnect_info *vpninfo)
{
int ret;
struct oc_text_buf *reqbuf;
+ const char start_tunnel[12] = "START_TUNNEL"; /* NOT zero-terminated */
char buf[256];
/* Connect to SSL VPN tunnel */
@@ -640,31 +643,33 @@ static int gpst_connect(struct openconnect_info *vpninfo)
buf_append(reqbuf, "GET %s?", vpninfo->urlpath);
filter_opts(reqbuf, vpninfo->cookie, "user,authcookie", 1);
buf_append(reqbuf, " HTTP/1.1\r\n\r\n");
+ if ((ret = buf_error(reqbuf)))
+ goto out;
if (vpninfo->dump_http_traffic)
dump_buf(vpninfo, '>', reqbuf->data);
vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
- buf_free(reqbuf);
if ((ret = vpninfo->ssl_read(vpninfo, buf, 12)) < 0) {
if (ret == -EINTR)
- return ret;
+ goto out;
vpn_progress(vpninfo, PRG_ERR,
_("Error fetching GET-tunnel HTTPS response.\n"));
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
- if (!strncmp(buf, "START_TUNNEL", 12)) {
+ if (!strncmp(buf, start_tunnel, sizeof(start_tunnel))) {
ret = 0;
} else if (ret==0) {
vpn_progress(vpninfo, PRG_ERR,
_("Gateway disconnected immediately after GET-tunnel request.\n"));
ret = -EPIPE;
} else {
- if (ret==12) {
- ret = vpninfo->ssl_gets(vpninfo, buf+12, 244);
- ret = (ret>0 ? ret : 0) + 12;
+ if (ret==sizeof(start_tunnel)) {
+ ret = vpninfo->ssl_gets(vpninfo, buf+sizeof(start_tunnel), sizeof(buf)-sizeof(start_tunnel));
+ ret = (ret>0 ? ret : 0) + sizeof(start_tunnel);
}
vpn_progress(vpninfo, PRG_ERR,
_("Got inappropriate HTTP GET-tunnel response: %.*s\n"), ret, buf);
@@ -682,6 +687,8 @@ static int gpst_connect(struct openconnect_info *vpninfo)
vpninfo->proto->udp_close(vpninfo);
}
+out:
+ buf_free(reqbuf);
return ret;
}
@@ -742,12 +749,15 @@ static int build_csd_token(struct openconnect_info *vpninfo)
buf = buf_alloc();
append_opt(buf, "computer", vpninfo->localname);
filter_opts(buf, vpninfo->cookie, "authcookie,preferred-ip", 0);
+ if (buf_error(buf))
+ goto out;
/* save as csd_token */
openconnect_md5(md5, buf->data, buf->pos);
for (i=0; i < MD5_SIZE; i++)
sprintf(&vpninfo->csd_token[i*2], "%02x", md5[i]);
+out:
return buf_free(buf);
}
@@ -775,6 +785,8 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
goto out;
append_opt(request_body, "md5", vpninfo->csd_token);
}
+ if ((result = buf_error(request_body)))
+ goto out;
orig_path = vpninfo->urlpath;
vpninfo->urlpath = strdup(report ? "ssl-vpn/hipreport.esp" : "ssl-vpn/hipreportcheck.esp");
From a390ef046b77e94309415fbab93bd9379167d2d2 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 13 Jan 2018 15:03:19 -0800
Subject: [PATCH 074/131] underp
---
test-globalprotect-login.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test-globalprotect-login.py b/test-globalprotect-login.py
index db701482..ee00a62d 100755
--- a/test-globalprotect-login.py
+++ b/test-globalprotect-login.py
@@ -47,7 +47,7 @@
# required
jnlpReady='jnlpReady', ok='Login', direct='yes',
# optional but might affect behavior
- clientVer=4100, server=args.portal, prot='https:',
+ clientVer=4100, server=endpoint.netloc, prot='https:',
computer=os.uname()[1]))
if args.verbose:
From dd4b8c6c0d4e2ac63143d14cd15f12f2b5e3be7d Mon Sep 17 00:00:00 2001
From: Janis Dzerins
Date: Mon, 15 Jan 2018 17:33:20 +0200
Subject: [PATCH 075/131] Fix ESP tunnel MTU calculation
---
gpst.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/gpst.c b/gpst.c
index 1a9e121e..e4b548bc 100644
--- a/gpst.c
+++ b/gpst.c
@@ -348,11 +348,10 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
* then we should pick the optimal MTU for ESP.
*/
if (!mtu && vpninfo->dtls_state == DTLS_SECRET) {
- if (vpninfo->peer_addr->sa_family == AF_INET6)
- mtu -= IPV6_HEADER_SIZE;
- else
- mtu -= IPV4_HEADER_SIZE;
-
+ if (vpninfo->peer_addr->sa_family == AF_INET6)
+ mtu = base_mtu - IPV6_HEADER_SIZE;
+ else
+ mtu = base_mtu - IPV4_HEADER_SIZE;
} else
#endif
From 8a44cd2c85c1fd032f341e4f24d7e4e4820aae17 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 15 Jan 2018 11:01:32 -0800
Subject: [PATCH 076/131] Revert "Merge pull request #80 from
jdz/globalprotect"
This reverts commit bf579e82267477e4d471af85cc913f16f985ad44, reversing
changes made to a390ef046b77e94309415fbab93bd9379167d2d2.
I merged this PR too quickly; it doesn't actually fix anything AFAICT.
---
gpst.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/gpst.c b/gpst.c
index e4b548bc..1a9e121e 100644
--- a/gpst.c
+++ b/gpst.c
@@ -348,10 +348,11 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
* then we should pick the optimal MTU for ESP.
*/
if (!mtu && vpninfo->dtls_state == DTLS_SECRET) {
- if (vpninfo->peer_addr->sa_family == AF_INET6)
- mtu = base_mtu - IPV6_HEADER_SIZE;
- else
- mtu = base_mtu - IPV4_HEADER_SIZE;
+ if (vpninfo->peer_addr->sa_family == AF_INET6)
+ mtu -= IPV6_HEADER_SIZE;
+ else
+ mtu -= IPV4_HEADER_SIZE;
+
} else
#endif
From 6b8e53d72c75798eb3dc02f223fed1c1c3ef4c76 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 15 Jan 2018 20:02:28 -0800
Subject: [PATCH 077/131] Close #80, fix #82 (I completely botched the
cherry-pick from the gpst branch in be074cd)
---
gpst.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/gpst.c b/gpst.c
index 1a9e121e..c1dd45d6 100644
--- a/gpst.c
+++ b/gpst.c
@@ -290,15 +290,19 @@ int gpst_xml_or_error(struct openconnect_info *vpninfo, int result, char *respon
return result;
}
-#define ESP_OVERHEAD (4 /* SPI */ + 4 /* sequence number */ + \
- 20 /* biggest supported MAC (SHA1) */ + 16 /* biggest supported IV (AES-128) */ + \
- 1 /* pad length */ + 1 /* next header */ + \
- 16 /* max padding */ )
+
+#define ESP_HEADER_SIZE (4 /* SPI */ + 4 /* sequence number */)
+#define ESP_FOOTER_SIZE (1 /* pad length */ + 1 /* next header */)
#define UDP_HEADER_SIZE 8
#define TCP_HEADER_SIZE 20 /* with no options */
#define IPV4_HEADER_SIZE 20
#define IPV6_HEADER_SIZE 40
+/* Based on cstp.c's calculate_mtu().
+ *
+ * With HTTPS tunnel, there are 21 bytes of overhead beyond the
+ * TCP MSS: 5 bytes for TLS and 16 for GPST.
+ */
static int calculate_mtu(struct openconnect_info *vpninfo)
{
int mtu = vpninfo->reqmtu, base_mtu = vpninfo->basemtu;
@@ -348,10 +352,18 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
* then we should pick the optimal MTU for ESP.
*/
if (!mtu && vpninfo->dtls_state == DTLS_SECRET) {
+ /* remove ESP, UDP, IP headers from base (wire) MTU */
+ mtu = ( base_mtu - UDP_HEADER_SIZE - ESP_HEADER_SIZE
+ - 12 /* both supported algos (SHA1 and MD5) have 96-bit MAC lengths (RFC2403 and RFC2404) */
+ - (vpninfo->enc_key_len ? : 32) /* biggest supported IV (AES-256) */ );
if (vpninfo->peer_addr->sa_family == AF_INET6)
mtu -= IPV6_HEADER_SIZE;
else
mtu -= IPV4_HEADER_SIZE;
+ /* round down to a multiple of blocksize */
+ mtu -= mtu % (vpninfo->enc_key_len ? : 32);
+ /* subtract ESP footer, which is included in the payload before padding to the blocksize */
+ mtu -= ESP_FOOTER_SIZE;
} else
#endif
From 3bb3c25ec849773b940580b1b6bc962c9fc7b7ec Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 15 Jan 2018 20:16:46 -0800
Subject: [PATCH 078/131] Let's try some CI
---
.travis.yml | 28 ++++++++++++++++++++++++++++
README.md | 2 ++
2 files changed, 30 insertions(+)
create mode 100644 .travis.yml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..dbae5bd1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,28 @@
+notifications:
+ email:
+ false
+
+dist: trusty
+sudo: false
+
+language: c
+compiler:
+ - gcc
+
+env:
+ global:
+ - MAKEFLAGS="-j 2"
+
+before_script:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq build-essential autoconf automake libtool pkg-config
+ vpnc-scripts
+ gettext libproxy-dev libxml2-dev liblz4-1 liblz4-dev libstoken-dev liboath-dev
+ libgnutls28-dev # actually GnuTLS 3.2.11 ¯\_(ツ)_/¯
+
+
+script: ./autogen.sh &&
+ ./configure &&
+ make VERBOSE=1 version.c &&
+ make &&
+ make VERBOSE=1 -j4 check
diff --git a/README.md b/README.md
index 8c2c9396..01f152b6 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# OpenConnect with PAN GlobalProtect support
+[](https://travis-ci.org/dlenski/openconnect)
+
# Table of Contents
* [What is this?](#what-is-this)
From ae4812142aa7673c22f2cfc2b4a1bcc15f2f5e64 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Mon, 15 Jan 2018 22:23:26 -0800
Subject: [PATCH 079/131] allow whitespace in login response
---
auth-globalprotect.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 17712c93..288727bc 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -95,6 +95,9 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
goto err_out;
xml_node = xml_node->children;
+ while (xml_node && xml_node->type != XML_ELEMENT_NODE)
+ xml_node = xml_node->next;
+
if (!xmlnode_is_named(xml_node, "application-desc"))
goto err_out;
@@ -103,6 +106,9 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
if (!arg->opt)
continue;
+ while (xml_node && xml_node->type != XML_ELEMENT_NODE)
+ xml_node = xml_node->next;
+
if (!xml_node)
value = NULL;
else if (!xmlnode_is_named(xml_node, "argument"))
From d408089ed02d6d17f747939af6e83f5f5932b776 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 22 Feb 2018 16:03:36 +0200
Subject: [PATCH 080/131] define esp_magic as uint32_t (equivalent to
in_addr_t) on Windows
---
openconnect-internal.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/openconnect-internal.h b/openconnect-internal.h
index f42d6ecf..e22e67e9 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -379,7 +379,11 @@ struct openconnect_info {
struct esp esp_out;
int enc_key_len;
int hmac_key_len;
+#ifdef _WIN32
+ uint32_t esp_magic; /* GlobalProtect magic ping address (network-endian) */
+#else
in_addr_t esp_magic; /* GlobalProtect magic ping address (network-endian) */
+#endif
int tncc_fd; /* For Juniper TNCC */
const char *csd_xmltag;
From d737e187734aa748a301de0de7085b23ef3e58e9 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 25 Feb 2018 09:43:22 +0200
Subject: [PATCH 081/131] don't #include on Win32, where it
doesn't exist (working towards #90)
---
gpst.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/gpst.c b/gpst.c
index c1dd45d6..5fd008ed 100644
--- a/gpst.c
+++ b/gpst.c
@@ -24,8 +24,10 @@
#include
#include
#include
-#include
#include
+#ifndef _WIN32
+#include
+#endif
#ifdef HAVE_LZ4
#include
#endif
From 42166de3f4e9844719d74dd3fe82f7df0bb4e134 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 25 Feb 2018 09:54:41 +0200
Subject: [PATCH 082/131] factor out Win32 IP/ICMP packet headers into a
separate win32-ipicmp.h (for #90)
---
esp.c | 7 +++
win32-ipcimp.h | 117 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 124 insertions(+)
create mode 100644 win32-ipcimp.h
diff --git a/esp.c b/esp.c
index a768f1bd..34c7eb52 100644
--- a/esp.c
+++ b/esp.c
@@ -27,8 +27,15 @@
#include
#include
#endif
+
+#ifdef _WIN32
+#include
+#include
+#include "win32-ipicmp.h"
+#else
#include
#include
+#endif
#include "openconnect-internal.h"
#include "lzo.h"
diff --git a/win32-ipcimp.h b/win32-ipcimp.h
new file mode 100644
index 00000000..ac7942c4
--- /dev/null
+++ b/win32-ipcimp.h
@@ -0,0 +1,117 @@
+/*
+ * OpenConnect (SSL + DTLS) VPN client
+ *
+ * Author: Daniel Lenski
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __OPENCONNECT_WIN32_IPICMP_H__
+#define __OPENCONNECT_WIN32_IPICMP_H__
+
+/* IPv4 header and flags used in esp.c */
+
+#define IP_DF 0x4000 /* dont fragment flag */
+#define IP_MF 0x2000 /* more fragments flag */
+
+struct ip {
+ u_char ip_hl:4; /* header length */
+ u_char ip_v:4; /* version */
+ u_char ip_tos; /* type of service */
+ short ip_len; /* total length */
+ u_short ip_id; /* identification */
+ short ip_off; /* fragment offset field */
+ u_char ip_ttl; /* time to live */
+ u_char ip_p; /* protocol */
+ u_short ip_sum; /* checksum */
+ struct in_addr ip_src,ip_dst; /* source and dest address */
+};
+
+/* ICMP header and flags used in esp.c */
+
+#define ICMP_MINLEN 8 /* abs minimum */
+#define ICMP_ECHO 8 /* Echo Request */
+
+#define icmp_pptr icmp_hun.ih_pptr
+#define icmp_gwaddr icmp_hun.ih_gwaddr
+#define icmp_id icmp_hun.ih_idseq.icd_id
+#define icmp_seq icmp_hun.ih_idseq.icd_seq
+#define icmp_void icmp_hun.ih_void
+#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
+#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
+#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
+#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
+#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
+
+#define icmp_otime icmp_dun.id_ts.its_otime
+#define icmp_rtime icmp_dun.id_ts.its_rtime
+#define icmp_ttime icmp_dun.id_ts.its_ttime
+#define icmp_ip icmp_dun.id_ip.idi_ip
+#define icmp_radv icmp_dun.id_radv
+#define icmp_mask icmp_dun.id_mask
+#define icmp_data icmp_dun.id_data
+
+struct icmp_ra_addr
+{
+ uint32_t ira_addr;
+ uint32_t ira_preference;
+};
+
+struct icmp
+{
+ uint8_t icmp_type; /* type of message, see below */
+ uint8_t icmp_code; /* type sub code */
+ uint16_t icmp_cksum; /* ones complement checksum of struct */
+ union
+ {
+ u_char ih_pptr; /* ICMP_PARAMPROB */
+ struct in_addr ih_gwaddr; /* gateway address */
+ struct ih_idseq /* echo datagram */
+ {
+ uint16_t icd_id;
+ uint16_t icd_seq;
+ } ih_idseq;
+ uint32_t ih_void;
+
+ /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+ struct ih_pmtu
+ {
+ uint16_t ipm_void;
+ uint16_t ipm_nextmtu;
+ } ih_pmtu;
+
+ struct ih_rtradv
+ {
+ uint8_t irt_num_addrs;
+ uint8_t irt_wpa;
+ uint16_t irt_lifetime;
+ } ih_rtradv;
+ } icmp_hun;
+
+ union
+ {
+ struct
+ {
+ uint32_t its_otime;
+ uint32_t its_rtime;
+ uint32_t its_ttime;
+ } id_ts;
+ struct
+ {
+ struct ip idi_ip;
+ /* options and then 64 bits of data */
+ } id_ip;
+ struct icmp_ra_addr id_radv;
+ uint32_t id_mask;
+ uint8_t id_data[1];
+ } icmp_dun;
+};
+
+#endif /* __OPENCONNECT_WIN32_IPICMP_H__ */
From 73f46bea9aa7d12f06fa63613846103c00165951 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 27 Feb 2018 11:37:14 +0200
Subject: [PATCH 083/131] set clientos and os-version when requesting
ssl-vpn/login.esp (apparently some servers require them; see #86)
---
auth-globalprotect.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 288727bc..1389fcd0 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -324,6 +324,8 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
/* submit gateway login (ssl-vpn/login.esp) or portal config (global-protect/getconfig.esp) request */
buf_truncate(request_body);
buf_append(request_body, "jnlpReady=jnlpReady&ok=Login&direct=yes&clientVer=4100&prot=https:");
+ append_opt(request_body, "os-version", vpninfo->platname);
+ append_opt(request_body, "clientos", vpninfo->platname);
append_opt(request_body, "server", vpninfo->hostname);
append_opt(request_body, "computer", vpninfo->localname);
if (vpninfo->ip_info.addr)
From a1f97f024cf865795dc02b33b54b7ad299c55fa3 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 27 Feb 2018 12:02:23 +0200
Subject: [PATCH 084/131] fix a bug leading to incorrect split-include netmasks
This bug was my fault. Introduced in 881eb286499baf78afbaeff4dbc5f055d23f1e4f on 15 Oct 2016 ("Correctly handle IPv4 route specified as either 10.1.2.0/255.255.255.0 or 10.1.2.0/24")
Left shift of >=32 bits is undefined on x86 (https://stackoverflow.com/a/7471843/20789), and it was causing split-includes of 0.0.0.0/0 to output inconsistent values to
the vpnc-script variables for split-includes:
CISCO_SPLIT_INC_12_MASKLEN=0
CISCO_SPLIT_INC_12_ADDR=0.0.0.0
CISCO_SPLIT_INC_12_MASK=255.255.255.255 # generated by netmaskbits() in script.c -- WRONG!
Caught due to an assertion failing in vpn-slice: https://github.com/dlenski/vpn-slice/issues/9
---
script.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/script.c b/script.c
index 4a78e67d..e0b92e58 100644
--- a/script.c
+++ b/script.c
@@ -81,7 +81,7 @@ static int netmasklen(struct in_addr addr)
static uint32_t netmaskbits(int masklen)
{
- return htonl((0xffffffff << (32-masklen)));
+ return htonl(masklen>0 ? (0xffffffff << (32-masklen)) : 0);
}
static int process_split_xxclude(struct openconnect_info *vpninfo,
From 0cc199aaa4cb643d34950df7f78502d9b0850cf6 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 27 Feb 2018 21:52:44 +0200
Subject: [PATCH 085/131] set clientos=Windows, as the official PAN GP client
does (ping #86)
---
auth-globalprotect.c | 6 ++++--
gpst.c | 5 ++++-
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 1389fcd0..bb019d7c 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -324,8 +324,10 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
/* submit gateway login (ssl-vpn/login.esp) or portal config (global-protect/getconfig.esp) request */
buf_truncate(request_body);
buf_append(request_body, "jnlpReady=jnlpReady&ok=Login&direct=yes&clientVer=4100&prot=https:");
- append_opt(request_body, "os-version", vpninfo->platname);
- append_opt(request_body, "clientos", vpninfo->platname);
+ if (!strcmp(vpninfo->platname, "win"))
+ append_opt(request_body, "clientos", "Windows");
+ else
+ append_opt(request_body, "clientos", vpninfo->platname);
append_opt(request_body, "server", vpninfo->hostname);
append_opt(request_body, "computer", vpninfo->localname);
if (vpninfo->ip_info.addr)
diff --git a/gpst.c b/gpst.c
index 5fd008ed..66d4c021 100644
--- a/gpst.c
+++ b/gpst.c
@@ -564,7 +564,10 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
/* submit getconfig request */
buf_append(request_body, "client-type=1&protocol-version=p1&app-version=3.0.1-10");
append_opt(request_body, "os-version", vpninfo->platname);
- append_opt(request_body, "clientos", vpninfo->platname);
+ if (!strcmp(vpninfo->platname, "win"))
+ append_opt(request_body, "clientos", "Windows");
+ else
+ append_opt(request_body, "clientos", vpninfo->platname);
append_opt(request_body, "hmac-algo", "sha1,md5");
append_opt(request_body, "enc-algo", "aes-128-cbc,aes-256-cbc");
if (old_addr) {
From 9c790be90daf7d3a0eae104d0323de7c40b94e78 Mon Sep 17 00:00:00 2001
From: Alessandro Tagliapietra
Date: Sat, 3 Mar 2018 21:01:03 -0800
Subject: [PATCH 086/131] Include automake into homebrew packages list
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If user doesn't have the `automake` package installed, aclocal isn't available:
```
➜ openconnect git:(globalprotect) ./autogen.sh
./autogen.sh: line 3: aclocal: command not found
```
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 01f152b6..c870d08e 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,7 @@ $ make install
[Homebrew](https://brew.sh) is required. To build and install into `/usr/local`:
```sh
-$ brew install pkg-config gettext gnutls lz4
+$ brew install pkg-config gettext gnutls lz4 automake
$ export LIBTOOLIZE=glibtoolize
$ ./autogen.sh
$ ./configure --prefix=/usr/local --with-vpnc-script=/usr/local/etc/vpnc-script --disable-nls
From b542e95f7e578b60a496ac54a0f6148ba91c533e Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 4 Mar 2018 09:50:07 +0200
Subject: [PATCH 087/131] typo in name
(thanks @bhank for catching this on #90)
---
win32-ipcimp.h => win32-ipicmp.h | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename win32-ipcimp.h => win32-ipicmp.h (100%)
diff --git a/win32-ipcimp.h b/win32-ipicmp.h
similarity index 100%
rename from win32-ipcimp.h
rename to win32-ipicmp.h
From e401991fd63535e1be7af77c10885fc4183b2ebe Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 4 Mar 2018 09:57:05 +0200
Subject: [PATCH 088/131] failure behavior on Windows (where HIP/CSD aren't
supported) should be that same when no --csd-wrapper script is specified
(thanks @bhank for highlighting this on #90)
---
gpst.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/gpst.c b/gpst.c
index 5fd008ed..91ac1f87 100644
--- a/gpst.c
+++ b/gpst.c
@@ -819,14 +819,11 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
static int run_hip_script(struct openconnect_info *vpninfo)
{
-#if defined(_WIN32) || defined(__native_client__)
- vpn_progress(vpninfo, PRG_ERR,
- _("Error: Running the 'HIP Report' script on this platform is not yet implemented.\n"));
- return -EPERM;
-#else
+#if !defined(_WIN32) && !defined(__native_client__)
int pipefd[2];
int ret;
pid_t child;
+#endif
if (!vpninfo->csd_wrapper) {
vpn_progress(vpninfo, PRG_ERR,
@@ -838,6 +835,11 @@ static int run_hip_script(struct openconnect_info *vpninfo)
return 0;
}
+#if defined(_WIN32) || defined(__native_client__)
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Error: Running the 'HIP Report' script on this platform is not yet implemented.\n"));
+ return -EPERM;
+#else
if (pipe(pipefd) == -1)
goto out;
child = fork();
From abb4ef3bf7023e6b52b17e875c0320a262a7f9a7 Mon Sep 17 00:00:00 2001
From: Dan Lenski
Date: Mon, 26 Mar 2018 21:39:39 -0700
Subject: [PATCH 089/131] allow receipt of oversize ESP packets, with 256 bytes
of headroom (ping #96)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Similar changes were previously made for GPST and ONCP packets:
* gpst.c → b700994403b5a755550645d8e6ad0f7b14e31493
* oncp.c → 9ac5e232214b728f675a44c43e61986ff9245b57
---
esp.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/esp.c b/esp.c
index 34c7eb52..9845701a 100644
--- a/esp.c
+++ b/esp.c
@@ -256,6 +256,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
struct esp *esp = &vpninfo->esp_in[vpninfo->current_esp_in];
struct esp *old_esp = &vpninfo->esp_in[vpninfo->current_esp_in ^ 1];
struct pkt *this;
+ int receive_mtu = MAX(2048, vpninfo->ip_info.mtu + 256);
int work_done = 0;
int ret;
@@ -271,7 +272,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
return 0;
while (1) {
- int len = vpninfo->ip_info.mtu + vpninfo->pkt_trailer;
+ int len = receive_mtu + vpninfo->pkt_trailer;
int i;
struct pkt *pkt;
@@ -353,8 +354,8 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
}
}
if (pkt->data[len - 1] == 0x05) {
- struct pkt *newpkt = malloc(sizeof(*pkt) + vpninfo->ip_info.mtu + vpninfo->pkt_trailer);
- int newlen = vpninfo->ip_info.mtu;
+ struct pkt *newpkt = malloc(sizeof(*pkt) + receive_mtu + vpninfo->pkt_trailer);
+ int newlen = receive_mtu;
if (!newpkt) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to allocate memory to decrypt ESP packet\n"));
@@ -367,7 +368,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
free(newpkt);
continue;
}
- newpkt->len = vpninfo->ip_info.mtu - newlen;
+ newpkt->len = receive_mtu - newlen;
vpn_progress(vpninfo, PRG_TRACE,
_("LZO decompressed %d bytes into %d\n"),
len - 2 - pkt->data[len-2], newpkt->len);
From 29445c3915ddc481aee609fe804dc2733c9b5741 Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Tue, 27 Mar 2018 15:49:58 +0200
Subject: [PATCH 090/131] Add basic Dockerfile
---
Dockerfile | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 Dockerfile
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..c9982a4d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,21 @@
+FROM debian:8-slim
+WORKDIR /openconnect
+RUN apt update \
+ && apt install -y \
+ build-essential \
+ gettext \
+ autoconf \
+ automake \
+ libproxy-dev \
+ libxml2-dev \
+ libtool \
+ vpnc-scripts \
+ pkg-config \
+ libgnutls28-dev \
+ git
+ADD . .
+RUN ./autogen.sh
+RUN ./configure
+RUN make
+RUN make install
+RUN ldconfig
From 5b1db80974772d9576330a73122590a5752e96a6 Mon Sep 17 00:00:00 2001
From: Martin Olsen
Date: Mon, 9 Apr 2018 09:34:58 -0700
Subject: [PATCH 091/131] Fixes linking ubuntu
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index c870d08e..a89acaf2 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,8 @@ $ git checkout globalprotect
$ ./autogen.sh
$ ./configure
$ make
-$ make install
+$ sudo make install
+$ sudo ldconfig
```
### Building on the Mac
From e74062121b49d9f6b4e913c44731dd29714b4812 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 12 Apr 2018 00:15:14 -0700
Subject: [PATCH 092/131] Fix leaks in getconfig XML parsing, caught with
Valgrind
1. Memory leakage caused by add_option() not behaving as it claimed to.
2. Memory leakage caused by not storing split-include routes in the
options list, as they should have been.
---
gpst.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gpst.c b/gpst.c
index 66d4c021..a149e4ba 100644
--- a/gpst.c
+++ b/gpst.c
@@ -92,7 +92,7 @@ static const char *add_option(struct openconnect_info *vpninfo, const char *opt,
free(new);
return NULL;
}
- new->value = strdup(val);
+ new->value = val;
new->next = vpninfo->cstp_options;
vpninfo->cstp_options = new;
@@ -500,7 +500,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
struct oc_split_include *inc = malloc(sizeof(*inc));
if (!inc)
continue;
- inc->route = s;
+ inc->route = add_option(vpninfo, "split-include", s);
inc->next = vpninfo->ip_info.split_includes;
vpninfo->ip_info.split_includes = inc;
}
From a3d0f29b3463cb52b558140e92897a18590f039e Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 12 Apr 2018 13:32:06 -0700
Subject: [PATCH 093/131] more memory leaks in the passing of the challenge
prompt and auth_id (from parse_javascript) to the auth form builder
---
auth-globalprotect.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index bb019d7c..61ba751e 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -27,7 +27,15 @@ void gpst_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
http_common_headers(vpninfo, buf);
}
-/* our "auth form" always has a username and password or challenge */
+/* The GlobalProtect auth form always has two visible fields:
+ * 1) username
+ * 2) one secret value:
+ * - normal account password
+ * - "challenge" (2FA) password, along with form name in auth_id
+ *
+ * This function steals the value of auth_id and prompt for
+ * use in the auth form.
+ */
static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *prompt, char *auth_id)
{
static struct oc_auth_form *form;
@@ -37,8 +45,8 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
if (!form)
return NULL;
- if (prompt) form->message = strdup(prompt);
- form->auth_id = strdup(auth_id ? : "_gateway");
+ form->message = prompt ? : strdup(_("Please enter your username and password"));
+ form->auth_id = auth_id ? : strdup("_gateway");
opt = form->opts = calloc(1, sizeof(*opt));
if (!opt)
@@ -288,7 +296,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
const char *request_body_type = "application/x-www-form-urlencoded";
const char *method = "POST";
char *xml_buf=NULL, *orig_path;
- char *prompt=_("Please enter your username and password"), *auth_id=NULL;
+ char *prompt=NULL, *auth_id=NULL;
#ifdef HAVE_LIBSTOKEN
/* Step 1: Unlock software token (if applicable) */
From de0feaab998084d3d2effa559c218ce0eb85331a Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 12 Apr 2018 12:31:54 -0700
Subject: [PATCH 094/131] First take on a general-purpose solution for #97 and
#98
This change allows the user to specify an alternative-secret field for the
login form submission, instead of 'passwd'.
The alternative field is specified by appending :FIELDNAME to the URL path:
https://vpn.bigcorp.com/gateway:prelogin-cookie (for #97)
https://vpn.bigcorp.com/portal:portal-userauthcookie (for #98)
---
auth-globalprotect.c | 32 ++++++++++++++++++++++----------
1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 61ba751e..d1fd2620 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -32,11 +32,12 @@ void gpst_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
* 2) one secret value:
* - normal account password
* - "challenge" (2FA) password, along with form name in auth_id
+ * - cookie from external authentication flow (INSTEAD OF password)
*
* This function steals the value of auth_id and prompt for
* use in the auth form.
*/
-static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *prompt, char *auth_id)
+static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *prompt, char *auth_id, char *pw_or_cookie_field)
{
static struct oc_auth_form *form;
static struct oc_form_opt *opt, *opt2;
@@ -59,8 +60,8 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
opt2 = opt->next = calloc(1, sizeof(*opt));
if (!opt2)
return NULL;
- opt2->name = strdup("passwd");
- opt2->label = auth_id ? strdup(_("Challenge: ")) : strdup(_("Password: "));
+ opt2->name = strdup(pw_or_cookie_field ? : "passwd");
+ asprintf(&opt2->label, "%s: ", auth_id ? _("Challenge") : (pw_or_cookie_field ? : _("Password")));
opt2->type = vpninfo->token_mode!=OC_TOKEN_MODE_NONE ? OC_FORM_OPT_TOKEN : OC_FORM_OPT_PASSWORD;
opt2->flags = OC_FORM_OPT_FILL_PASSWORD;
@@ -287,7 +288,7 @@ static int parse_portal_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
return result;
}
-static int gpst_login(struct openconnect_info *vpninfo, int portal)
+static int gpst_login(struct openconnect_info *vpninfo, int portal, const char *pw_or_cookie_field)
{
int result;
@@ -307,7 +308,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
}
#endif
- form = auth_form(vpninfo, prompt, auth_id);
+ form = auth_form(vpninfo, prompt, auth_id, pw_or_cookie_field);
if (!form)
return -ENOMEM;
@@ -358,7 +359,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
portal ? parse_portal_xml : parse_login_xml, &prompt, &auth_id);
if (result == -EAGAIN) {
free_auth_form(form);
- form = auth_form(vpninfo, prompt, auth_id);
+ form = auth_form(vpninfo, prompt, auth_id, pw_or_cookie_field);
if (!form)
return -ENOMEM;
continue;
@@ -380,19 +381,30 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
int gpst_obtain_cookie(struct openconnect_info *vpninfo)
{
+ char *pw_or_cookie_field = NULL;
int result;
+ /* An alternate password/secret field may be specified in the "URL path". Known possibilities:
+ * /portal:portal-userauthcookie
+ * /gateway:prelogin-cookie
+ */
+ if (vpninfo->urlpath
+ && (pw_or_cookie_field = strrchr(vpninfo->urlpath, ':'))!=NULL) {
+ *pw_or_cookie_field = '\0';
+ pw_or_cookie_field++;
+ }
+
if (vpninfo->urlpath && (!strcmp(vpninfo->urlpath, "portal") || !strncmp(vpninfo->urlpath, "global-protect", 14))) {
/* assume the server is a portal */
- return gpst_login(vpninfo, 1);
+ return gpst_login(vpninfo, 1, pw_or_cookie_field);
} else if (vpninfo->urlpath && (!strcmp(vpninfo->urlpath, "gateway") || !strncmp(vpninfo->urlpath, "ssl-vpn", 7))) {
/* assume the server is a gateway */
- return gpst_login(vpninfo, 0);
+ return gpst_login(vpninfo, 0, pw_or_cookie_field);
} else {
/* first try handling it as a gateway, then a portal */
- result = gpst_login(vpninfo, 0);
+ result = gpst_login(vpninfo, 0, pw_or_cookie_field);
if (result == -EEXIST) {
- result = gpst_login(vpninfo, 1);
+ result = gpst_login(vpninfo, 1, pw_or_cookie_field);
if (result == -EEXIST)
vpn_progress(vpninfo, PRG_ERR, _("Server is neither a GlobalProtect portal nor a gateway.\n"));
}
From 1b38c425ee3d0101d5c8e3f5edf5cff7258a14b2 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 12 Apr 2018 18:44:51 -0700
Subject: [PATCH 095/131] fix memory leak of pw_or_cookie_field too
---
auth-globalprotect.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index d1fd2620..50bb2a74 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -34,7 +34,7 @@ void gpst_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
* - "challenge" (2FA) password, along with form name in auth_id
* - cookie from external authentication flow (INSTEAD OF password)
*
- * This function steals the value of auth_id and prompt for
+ * This function steals the value of auth_id, prompt, and pw_or_cookie_field for
* use in the auth form.
*/
static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *prompt, char *auth_id, char *pw_or_cookie_field)
@@ -60,7 +60,7 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
opt2 = opt->next = calloc(1, sizeof(*opt));
if (!opt2)
return NULL;
- opt2->name = strdup(pw_or_cookie_field ? : "passwd");
+ opt2->name = pw_or_cookie_field ? : strdup("passwd");
asprintf(&opt2->label, "%s: ", auth_id ? _("Challenge") : (pw_or_cookie_field ? : _("Password")));
opt2->type = vpninfo->token_mode!=OC_TOKEN_MODE_NONE ? OC_FORM_OPT_TOKEN : OC_FORM_OPT_PASSWORD;
opt2->flags = OC_FORM_OPT_FILL_PASSWORD;
From c96a8809c260195aba9d7aa77fcabfba9d308d59 Mon Sep 17 00:00:00 2001
From: Max Rees
Date: Mon, 2 Apr 2018 01:28:16 -0400
Subject: [PATCH 096/131] Allow specifying server in configuration file
This allows the configuration file to have an entry of the form:
server https://server[:port][/group]
similar to the CLI invocation.
Signed-off-by: Max Rees
---
main.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/main.c b/main.c
index b2fb10ab..97dd8d8e 100644
--- a/main.c
+++ b/main.c
@@ -187,6 +187,7 @@ enum {
OPT_HTTP_AUTH,
OPT_LOCAL_HOSTNAME,
OPT_PROTOCOL,
+ OPT_SERVER,
OPT_PASSTOS,
OPT_REQUEST_IP,
};
@@ -271,6 +272,7 @@ static const struct option long_options[] = {
OPTION("no-system-trust", 0, OPT_NO_SYSTEM_TRUST),
OPTION("protocol", 1, OPT_PROTOCOL),
OPTION("request-ip", 1, OPT_REQUEST_IP),
+ OPTION("server", 1, OPT_SERVER),
#ifdef OPENCONNECT_GNUTLS
OPTION("gnutls-debug", 1, OPT_GNUTLS_DEBUG),
#endif
@@ -1166,6 +1168,10 @@ int main(int argc, char **argv)
if (openconnect_set_protocol(vpninfo, config_arg))
exit(1);
break;
+ case OPT_SERVER:
+ if (openconnect_parse_url(vpninfo, config_arg))
+ exit(1);
+ break;
case OPT_JUNIPER:
fprintf(stderr, "WARNING: Juniper Network Connect support is experimental.\n");
fprintf(stderr, "It will probably be superseded by Junos Pulse support.\n");
@@ -1461,7 +1467,7 @@ int main(int argc, char **argv)
if (optind < argc - 1) {
fprintf(stderr, _("Too many arguments on command line\n"));
usage();
- } else if (optind > argc - 1) {
+ } else if (optind > argc - 1 && !vpninfo->hostname) {
fprintf(stderr, _("No server specified\n"));
usage();
}
@@ -1517,7 +1523,10 @@ int main(int argc, char **argv)
if (config_lookup_host(vpninfo, argv[optind]))
exit(1);
- if (!vpninfo->hostname) {
+ /* The last argument without a corresponding --option is taken
+ * to be the server URL and overrides any --server option on the
+ * command line or from a --config */
+ if (!vpninfo->hostname || optind < argc) {
char *url = strdup(argv[optind]);
if (openconnect_parse_url(vpninfo, url))
From d882fe19c7bc98021bb8195e7f138007fbe7d086 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 13 Apr 2018 15:03:57 -0700
Subject: [PATCH 097/131] ensure that ESP tunnel is disabled before we re-fetch
the configuration (should fix #89)
---
gpst.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/gpst.c b/gpst.c
index a149e4ba..eaaba6d8 100644
--- a/gpst.c
+++ b/gpst.c
@@ -905,6 +905,10 @@ int gpst_setup(struct openconnect_info *vpninfo)
{
int ret;
+ /* ESP tunnel is unusable as soon as we (re-)fetch the configuration */
+ if (vpninfo->proto->udp_close)
+ vpninfo->proto->udp_close(vpninfo);
+
/* Get configuration */
ret = gpst_get_config(vpninfo);
if (ret)
From 3aa52027bdcfd6c5c3fad122097f29c7d42d03fc Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 13 Apr 2018 14:50:31 -0700
Subject: [PATCH 098/131] move determination of ESP-vs.-TLS outside of
calculate_mtu() function, and add explanation
This will help clarify our MTU calculations, should an issue like #89 arise again.
---
gpst.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/gpst.c b/gpst.c
index eaaba6d8..ace9e024 100644
--- a/gpst.c
+++ b/gpst.c
@@ -305,7 +305,7 @@ int gpst_xml_or_error(struct openconnect_info *vpninfo, int result, char *respon
* With HTTPS tunnel, there are 21 bytes of overhead beyond the
* TCP MSS: 5 bytes for TLS and 16 for GPST.
*/
-static int calculate_mtu(struct openconnect_info *vpninfo)
+static int calculate_mtu(struct openconnect_info *vpninfo, int can_use_esp)
{
int mtu = vpninfo->reqmtu, base_mtu = vpninfo->basemtu;
int mss = 0;
@@ -350,10 +350,8 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
base_mtu = 1280;
#ifdef HAVE_ESP
- /* If we can use the ESP tunnel (got secrets in config),
- * then we should pick the optimal MTU for ESP.
- */
- if (!mtu && vpninfo->dtls_state == DTLS_SECRET) {
+ /* If we can use the ESP tunnel then we should pick the optimal MTU for ESP. */
+ if (!mtu && can_use_esp) {
/* remove ESP, UDP, IP headers from base (wire) MTU */
mtu = ( base_mtu - UDP_HEADER_SIZE - ESP_HEADER_SIZE
- 12 /* both supported algos (SHA1 and MD5) have 96-bit MAC lengths (RFC2403 and RFC2404) */
@@ -370,9 +368,7 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
} else
#endif
- /* We are definitely using the TLS tunnel (no ESP secrets)
- * so we should base our MTU on the TCP MSS.
- */
+ /* We are definitely using the TLS tunnel, so we should base our MTU on the TCP MSS. */
if (!mtu) {
if (mss)
mtu = mss - 21;
@@ -595,9 +591,19 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
if (!vpninfo->ip_info.mtu) {
/* FIXME: GP gateway config always seems to be 0 */
- vpninfo->ip_info.mtu = calculate_mtu(vpninfo);
+ char *no_esp_reason = NULL;
+#ifdef HAVE_ESP
+ if (vpninfo->dtls_state == DTLS_DISABLED)
+ no_esp_reason = _("ESP disabled");
+ else if (vpninfo->dtls_state == DTLS_NOSECRET)
+ no_esp_reason = _("No ESP keys received");
+#else
+ no_esp_reason = _("ESP support not available in this build");
+#endif
+ vpninfo->ip_info.mtu = calculate_mtu(vpninfo, !!no_esp_reason);
vpn_progress(vpninfo, PRG_ERR,
- _("No MTU received. Calculated %d\n"), vpninfo->ip_info.mtu);
+ _("No MTU received. Calculated %d for %s%s\n"), vpninfo->ip_info.mtu,
+ no_esp_reason ? "TLS tunnel. " : "ESP tunnel", no_esp_reason ? : "");
/* return -EINVAL; */
}
if (!vpninfo->ip_info.addr) {
From 5596bbab6cf3fe8620e84b74a2720eaaed0b90f1 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 13 Apr 2018 17:22:12 -0700
Subject: [PATCH 099/131] extreme README makeover
---
README.md | 96 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 57 insertions(+), 39 deletions(-)
diff --git a/README.md b/README.md
index a89acaf2..619e1411 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,8 @@
* [Building from source on Linux](#building-from-source-on-linux)
* [Building on the Mac](#building-on-the-mac)
* [Connecting](#connecting)
- * [Portal vs. gateway servers](#portal-vs-gateway-servers)
+ * [Portal vs. gateway servers](#portal-vs-gateway-servers)
+ * [TODO](#todo)
# What is this?
@@ -20,18 +21,17 @@ PAN GlobalProtect VPN in its native modes (SSL and
[ESP](http://wikipedia.org/wiki/Encapsulating_Security_Payload))—with
no assistance or cooperation needed from your VPN administrators.
-## Feedback and troubleshooting
-
-This is a [work in progress](http://lists.infradead.org/pipermail/openconnect-devel/2016-October/004035.html).
+I began developing it [in October 2016](http://lists.infradead.org/pipermail/openconnect-devel/2016-October/004035.html),
+and started using it for "real work" almost immediately. It has become
+increasingly polished since then.
-That said, I've been using it for real work for many weeks, and it works very well for me.
+## Feedback and troubleshooting
-Having other people test it would be awesome and I welcome your
-feedback! Please report any problems here on Github rather than
-bothering the OpenConnect mailing list, since this is *not part of any
-official OpenConnect release*.
+GlobalProtect support is *not yet part of any official OpenConnect release*
+(but see discussions on [official mailing list](https://lists.infradead.org/mailman/listinfo/openconnect-devel)).
+Keep this in mind when discussing GlobalProtect issues on the mailing list.
-If you are having trouble
+Please report any problems as Github issues. If you are having trouble
authenticating to your GlobalProtect server, please run OpenConnect
with the `--dump -vvv` flags to dump the authentication flow; please
compare the back-and-forth configuration requests to [this anonymized
@@ -62,8 +62,7 @@ $ git checkout globalprotect
$ ./autogen.sh
$ ./configure
$ make
-$ sudo make install
-$ sudo ldconfig
+$ sudo make install && sudo ldconfig
```
### Building on the Mac
@@ -84,8 +83,7 @@ Please see [this Gist](https://gist.github.com/moklett/3170636) on how to set up
## Connecting
Run openconnect like this to test it with your GlobalProtect VPN
-provider. (Include `--certificate cert_with_privkey.pem` if your VPN
-requires a client certificate and/or private key.)
+provider.
```sh
$ ./openconnect --protocol=gp server.company.com --dump -vvv
@@ -94,36 +92,56 @@ Username:
Password:
```
-Currently it only supports username, password, and optionally client
-certificate authentication… since that's the only example I have. But
-I'd welcome feedback if there are other authentication methods in use
-out there.
+It currently supports the following authentication mechanisms:
+
+* username and password
+* "challenge"-based multi-factor authentication, wherein the server requests a secondary username and password after the first one
+* TLS/SSL client certificate (include `--certificate cert_with_privkey.pem` if your VPN requires a _client_ certificate and private key)
-## Portal vs. gateway servers
+I'd welcome feedback on how to support other authentication methods in use with GlobalProtect.
-For my VPN, the VPN tunnel server is the *same* as the VPN "portal"
-server, but your VPN may differ. Try using both the "Portal address"
-and the "GlobalProtect Gateway IP" shown in the Windows client with
-OpenConnect:
+### Portal vs. gateway servers
+
+For some GlobalProtect VPNs, there is a distinction between "portal"
+and "gateway" servers, although in many GlobalProtect VPNs they run on
+the _same_ server. "Portal" application URLs are found under `/global-protect`,
+while "gateway" application URLs are under `/ssl-vpn`.
+
+Try using both the "Portal address" and the "GlobalProtect Gateway IP" shown in the Windows client with OpenConnect:
[]
-You can also use [`get-globalprotect-config.py`](get-globalprotect-config.py) to list the available gateway servers:
+The official GlobalProtect VPN clients _always_ connect first via the
+portal. The portal then sends a choice of one or more
+gateways. However, this behavior is unnecessary, and adds an
+additional delay in establishing a connection.
+
+Recent versions of `openconnect` can connect via _either_ the portal
+endpoint _or_ the gateway endpoint:
+
+* If unspecified, the gateway endpoint is tried first, then the portal endpoint.
+* For the gateway, include a URL-path starting with `/ssl-vpn` or specify `--usergroup=gateway`
+* For the portal, include a URL-path starting with `/global-protect` or specify `--usergroup=portal`
+ * To choose a specific gateway from the portal without further prompting, add `--authgroup $GATEWAYNAME`
+
+Example of connecting via the portal interface and getting a choice of gateway servers:
```sh
-$ ./get-globalprotect-config.py [--cert client_cert_with_privkey.pem] portal.company.com
- ...
-
- 5
-
-
-
- 1
- yes
- WowSuchGateway
-
-
-
-
- ...
+$ openconnect --protocol=gp --usergroup=portal server.company.com
+Please enter your username and password.
+Username:
+Password:
+..
+Connected to HTTPS on server.company.com
+3 gateway servers available:
+ NorthAmerica (vpn-na.company.com)
+ Europe (vpn-eu.company.com)
+ Asia (vpn-asia.company.com)
+Please select GlobalProtect gateway.
+GATEWAY: [NorthAmerica|Europe|Asia]:
+...
```
+
+# TODO
+
+* Support web-based/SAML-based authentication flows (see [pull #98](//github.com/dlenski/openconnect/issues/98) for preliminary work)
From 166b5d2432a5099b042e018f21f20bd60c46ba88 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 13 Apr 2018 17:26:17 -0700
Subject: [PATCH 100/131] add README section about HIP reports
---
README.md | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/README.md b/README.md
index 619e1411..67860409 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@
* [Building on the Mac](#building-on-the-mac)
* [Connecting](#connecting)
* [Portal vs. gateway servers](#portal-vs-gateway-servers)
+ * [HIP report submission](#hip-report-submission)
* [TODO](#todo)
# What is this?
@@ -100,6 +101,41 @@ It currently supports the following authentication mechanisms:
I'd welcome feedback on how to support other authentication methods in use with GlobalProtect.
+### HIP report submission
+
+The HIP ("Host Integrity Protection") mechanism is a security scanner
+for PAN GlobalProtect VPNs, in the same vein as Cisco's CSD and
+Juniper's Host Checker.
+
+The server requests a "HIP report" upon client connection, then the
+client generates a "HIP report" XML file, and then the client uploads
+it to the server.
+
+If all goes well, the client should have the expected level of access
+to resources on the network after these steps are complete. At least
+two things can go wrong:
+
+* Many GlobalProtect servers report that they require HIP reports, but
+ don't actually enforce this requirement. (For this reason,
+ OpenConnect _does not currently fail_ if a HIP report is required
+ but no HIP report script is provided.)
+* Many GlobalProtect servers will claim that the HIP report was
+ accepted successfully but silently fail to enable the expected
+ network access, presumably because some aspect of the HIP report
+ contents were not approved.
+
+OpenConnect supports HIP report generation and submission by passing
+the `--csd-wrapper=SCRIPT` argument with a shell script to generate a
+HIP report in the format expected by the server. This shell script
+must output the HIP report to standard output and exit successfully
+(status code 0).
+
+An example [`hipreport.sh`](hipreport.sh) script is included in the
+repository. Depending on how picky your GlobalProtect VPN is, it may
+be necessary to spoof or alter some of the parameters of the HIP
+report to match your GlobalProtect VPN's expectations as to its
+contents.
+
### Portal vs. gateway servers
For some GlobalProtect VPNs, there is a distinction between "portal"
From fc0220dc8bb7739e85722f5557fcf097353873bd Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 15 Apr 2018 17:44:27 -0700
Subject: [PATCH 101/131] underp ESP-vs.-TLS MTU calculation (borked in
3aa5202, ping #89)
---
gpst.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gpst.c b/gpst.c
index 7b34aad2..fb16eb06 100644
--- a/gpst.c
+++ b/gpst.c
@@ -600,7 +600,7 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
#else
no_esp_reason = _("ESP support not available in this build");
#endif
- vpninfo->ip_info.mtu = calculate_mtu(vpninfo, !!no_esp_reason);
+ vpninfo->ip_info.mtu = calculate_mtu(vpninfo, !no_esp_reason);
vpn_progress(vpninfo, PRG_ERR,
_("No MTU received. Calculated %d for %s%s\n"), vpninfo->ip_info.mtu,
no_esp_reason ? "TLS tunnel. " : "ESP tunnel", no_esp_reason ? : "");
From f227781d6c786ab3aa94a07dd699dba530abf284 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 17 Apr 2018 15:08:09 -0700
Subject: [PATCH 102/131] fix too-early free(), appears to fix #101
---
gpst.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/gpst.c b/gpst.c
index fb16eb06..44a67412 100644
--- a/gpst.c
+++ b/gpst.c
@@ -582,7 +582,7 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
vpninfo->urlpath = orig_path;
if (result < 0)
- goto out;
+ goto pre_opt_out;
/* parse getconfig result */
result = gpst_xml_or_error(vpninfo, result, xml_buf, gpst_parse_config_xml, NULL, NULL);
@@ -641,8 +641,9 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
}
out:
- buf_free(request_body);
free_optlist(old_cstp_opts);
+pre_opt_out:
+ buf_free(request_body);
free(xml_buf);
return result;
}
From f573478fb45e05a0ceefb6f4a6a68e06fbdcec73 Mon Sep 17 00:00:00 2001
From: Yage Hu
Date: Wed, 18 Apr 2018 17:44:11 -0700
Subject: [PATCH 103/131] Fix Google 2FA typo
Google 2FA fail would fail with `Unkown form ID 'frmTotpToken'`
---
auth-juniper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/auth-juniper.c b/auth-juniper.c
index eee85d2f..acd9c77e 100644
--- a/auth-juniper.c
+++ b/auth-juniper.c
@@ -77,7 +77,7 @@ static int oncp_can_gen_tokencode(struct openconnect_info *vpninfo,
if (strcmp(form->auth_id, "frmDefender") &&
strcmp(form->auth_id, "frmNextToken") &&
- strcmp(form->auth_id, "ftmTotpToken"))
+ strcmp(form->auth_id, "frmTotpToken"))
return -EINVAL;
return can_gen_tokencode(vpninfo, form, opt);
From ffe46ab2e5cef8aacb2d3e69fda0f20a854b445f Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 21 Apr 2018 16:28:17 -0700
Subject: [PATCH 104/131] briefly mention new --server option
---
main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/main.c b/main.c
index 97dd8d8e..ba1cd45c 100644
--- a/main.c
+++ b/main.c
@@ -781,7 +781,7 @@ static int gai_override_cb(void *cbdata, const char *node,
static void usage(void)
{
- printf(_("Usage: openconnect [options] \n"));
+ printf(_("Usage: openconnect [options] [--server=]\n"));
printf(_("Open client for multiple VPN protocols, version %s\n\n"), openconnect_version_str);
print_build_opts();
printf(" --config=CONFIGFILE %s\n", _("Read options from config file"));
From 774b20af2f70199c40f5d963a246d2f9461e52db Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 21 Apr 2018 16:11:43 -0700
Subject: [PATCH 105/131] reorder options
---
main.c | 116 ++++++++++++++++++++++++++++-----------------------------
1 file changed, 58 insertions(+), 58 deletions(-)
diff --git a/main.c b/main.c
index ba1cd45c..d7858e3d 100644
--- a/main.c
+++ b/main.c
@@ -785,35 +785,32 @@ static void usage(void)
printf(_("Open client for multiple VPN protocols, version %s\n\n"), openconnect_version_str);
print_build_opts();
printf(" --config=CONFIGFILE %s\n", _("Read options from config file"));
-#ifndef _WIN32
- printf(" -b, --background %s\n", _("Continue in background after startup"));
- printf(" --pid-file=PIDFILE %s\n", _("Write the daemon's PID to this file"));
-#endif
+ printf(" -V, --version %s\n", _("Report version number"));
+ printf(" -h, --help %s\n", _("Display help text"));
+ print_supported_protocols_usage();
+ printf(" -u, --user=NAME %s\n", _("Set login username"));
+ printf(" --no-passwd %s\n", _("Disable password/SecurID authentication"));
+ printf(" --non-inter %s\n", _("Do not expect user input; exit if it is required"));
+ printf(" --passwd-on-stdin %s\n", _("Read password from standard input"));
+ printf(" --authgroup=GROUP %s\n", _("Choose authentication login selection"));
printf(" -c, --certificate=CERT %s\n", _("Use SSL client certificate CERT"));
- printf(" -e, --cert-expire-warning=DAYS %s\n", _("Warn when certificate lifetime < DAYS"));
printf(" -k, --sslkey=KEY %s\n", _("Use SSL private key file KEY"));
- printf(" -C, --cookie=COOKIE %s\n", _("Use WebVPN cookie COOKIE"));
- printf(" --cookie-on-stdin %s\n", _("Read cookie from standard input"));
- printf(" -d, --deflate %s\n", _("Enable compression (default)"));
- printf(" -D, --no-deflate %s\n", _("Disable compression"));
- printf(" --force-dpd=INTERVAL %s\n", _("Set minimum Dead Peer Detection interval"));
+ printf(" -e, --cert-expire-warning=DAYS %s\n", _("Warn when certificate lifetime < DAYS"));
printf(" -g, --usergroup=GROUP %s\n", _("Set login usergroup"));
- printf(" -h, --help %s\n", _("Display help text"));
- printf(" -i, --interface=IFNAME %s\n", _("Use IFNAME for tunnel interface"));
-#ifndef _WIN32
- printf(" -l, --syslog %s\n", _("Use syslog for progress messages"));
-#endif
- printf(" --timestamp %s\n", _("Prepend timestamp to progress messages"));
- printf(" --passtos %s\n", _("copy TOS / TCLASS when using DTLS"));
-#ifndef _WIN32
- printf(" -U, --setuid=USER %s\n", _("Drop privileges after connecting"));
- printf(" --csd-user=USER %s\n", _("Drop privileges during CSD execution"));
- printf(" --csd-wrapper=SCRIPT %s\n", _("Run SCRIPT instead of CSD binary"));
-#endif
- printf(" -m, --mtu=MTU %s\n", _("Request MTU from server (legacy servers only)"));
- printf(" --base-mtu=MTU %s\n", _("Indicate path MTU to/from server"));
printf(" -p, --key-password=PASS %s\n", _("Set key passphrase or TPM SRK PIN"));
printf(" --key-password-from-fsid %s\n", _("Key passphrase is fsid of file system"));
+ printf(" --token-mode=MODE %s\n", _("Software token type: rsa, totp or hotp"));
+ printf(" --token-secret=STRING %s\n", _("Software token secret"));
+#ifndef HAVE_LIBSTOKEN
+ printf(" %s\n", _("(NOTE: libstoken (RSA SecurID) disabled in this build)"));
+#endif
+#ifndef HAVE_LIBPCSCLITE
+ printf(" %s\n", _("(NOTE: Yubikey OATH disabled in this build)"));
+#endif
+ printf(" --servercert=FINGERPRINT %s\n", _("Server's certificate SHA1 fingerprint"));
+ printf(" --no-cert-check %s\n", _("Do not require server SSL cert to be valid"));
+ printf(" --no-system-trust %s\n", _("Disable default system certificate authorities"));
+ printf(" --cafile=FILE %s\n", _("Cert file for server verification"));
printf(" -P, --proxy=URL %s\n", _("Set proxy server"));
printf(" --proxy-auth=METHODS %s\n", _("Set proxy authentication methods"));
printf(" --no-proxy %s\n", _("Disable proxy"));
@@ -821,51 +818,54 @@ static void usage(void)
#ifndef LIBPROXY_HDR
printf(" %s\n", _("(NOTE: libproxy disabled in this build)"));
#endif
- printf(" --pfs %s\n", _("Require perfect forward secrecy"));
+ printf(" --reconnect-timeout %s\n", _("Connection retry timeout in seconds"));
+ printf(" --resolve=HOST:IP %s\n", _("Use IP when connecting to HOST"));
+ printf(" --passtos %s\n", _("copy TOS / TCLASS when using DTLS"));
+ printf(" --dtls-local-port=PORT %s\n", _("Set local port for DTLS datagrams"));
+ printf(" -C, --cookie=COOKIE %s\n", _("Use WebVPN cookie COOKIE"));
+ printf(" --cookie-on-stdin %s\n", _("Read cookie from standard input"));
+ printf(" --authenticate %s\n", _("Authenticate only and print login info"));
+ printf(" --cookieonly %s\n", _("Fetch webvpn cookie only; don't connect"));
+ printf(" --printcookie %s\n", _("Print webvpn cookie before connecting"));
+#ifndef _WIN32
+ printf(" -b, --background %s\n", _("Continue in background after startup"));
+ printf(" --pid-file=PIDFILE %s\n", _("Write the daemon's PID to this file"));
+ printf(" -U, --setuid=USER %s\n", _("Drop privileges after connecting"));
+#endif
+#ifndef _WIN32
+ printf(" -l, --syslog %s\n", _("Use syslog for progress messages"));
+#endif
+ printf(" -v, --verbose %s\n", _("More output"));
printf(" -q, --quiet %s\n", _("Less output"));
- printf(" -Q, --queue-len=LEN %s\n", _("Set packet queue limit to LEN pkts"));
+ printf(" --dump-http-traffic %s\n", _("Dump HTTP authentication traffic (implies --verbose"));
+ printf(" --timestamp %s\n", _("Prepend timestamp to progress messages"));
+ printf(" -i, --interface=IFNAME %s\n", _("Use IFNAME for tunnel interface"));
printf(" -s, --script=SCRIPT %s\n", _("Shell command line for using a vpnc-compatible config script"));
printf(" %s: \"%s\"\n", _("default"), default_vpncscript);
#ifndef _WIN32
printf(" -S, --script-tun %s\n", _("Pass traffic to 'script' program, not tun"));
#endif
- printf(" -u, --user=NAME %s\n", _("Set login username"));
- printf(" -V, --version %s\n", _("Report version number"));
- printf(" -v, --verbose %s\n", _("More output"));
- printf(" --dump-http-traffic %s\n", _("Dump HTTP authentication traffic (implies --verbose"));
- printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
- printf(" --authgroup=GROUP %s\n", _("Choose authentication login selection"));
- printf(" --authenticate %s\n", _("Authenticate only and print login info"));
- printf(" --cookieonly %s\n", _("Fetch webvpn cookie only; don't connect"));
- printf(" --printcookie %s\n", _("Print webvpn cookie before connecting"));
- printf(" --cafile=FILE %s\n", _("Cert file for server verification"));
printf(" --disable-ipv6 %s\n", _("Do not ask for IPv6 connectivity"));
- printf(" --dtls-ciphers=LIST %s\n", _("OpenSSL ciphers to support for DTLS"));
+ printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
+ printf(" -m, --mtu=MTU %s\n", _("Request MTU from server (legacy servers only)"));
+ printf(" --base-mtu=MTU %s\n", _("Indicate path MTU to/from server"));
+ printf(" -d, --deflate %s\n", _("Enable compression (default)"));
+ printf(" -D, --no-deflate %s\n", _("Disable compression"));
+ printf(" --force-dpd=INTERVAL %s\n", _("Set minimum Dead Peer Detection interval"));
+ printf(" --pfs %s\n", _("Require perfect forward secrecy"));
printf(" --no-dtls %s\n", _("Disable DTLS"));
- printf(" --no-http-keepalive %s\n", _("Disable HTTP connection re-use"));
- printf(" --no-passwd %s\n", _("Disable password/SecurID authentication"));
- printf(" --no-cert-check %s\n", _("Do not require server SSL cert to be valid"));
- printf(" --no-system-trust %s\n", _("Disable default system certificate authorities"));
- printf(" --no-xmlpost %s\n", _("Do not attempt XML POST authentication"));
- printf(" --non-inter %s\n", _("Do not expect user input; exit if it is required"));
- printf(" --passwd-on-stdin %s\n", _("Read password from standard input"));
- printf(" --token-mode=MODE %s\n", _("Software token type: rsa, totp or hotp"));
- printf(" --token-secret=STRING %s\n", _("Software token secret"));
-#ifndef HAVE_LIBSTOKEN
- printf(" %s\n", _("(NOTE: libstoken (RSA SecurID) disabled in this build)"));
-#endif
-#ifndef HAVE_LIBPCSCLITE
- printf(" %s\n", _("(NOTE: Yubikey OATH disabled in this build)"));
-#endif
- printf(" --reconnect-timeout %s\n", _("Connection retry timeout in seconds"));
- printf(" --servercert=FINGERPRINT %s\n", _("Server's certificate SHA1 fingerprint"));
+ printf(" --dtls-ciphers=LIST %s\n", _("OpenSSL ciphers to support for DTLS"));
+ printf(" -Q, --queue-len=LEN %s\n", _("Set packet queue limit to LEN pkts"));
+ printf(" --request-ip=IP %s\n", _("Request a specific IPv4 address"));
printf(" --useragent=STRING %s\n", _("HTTP header User-Agent: field"));
printf(" --local-hostname=STRING %s\n", _("Local hostname to advertise to server"));
- printf(" --resolve=HOST:IP %s\n", _("Use IP when connecting to HOST"));
printf(" --os=STRING %s\n", _("OS type (linux,linux-64,win,...) to report"));
- printf(" --dtls-local-port=PORT %s\n", _("Set local port for DTLS datagrams"));
- printf(" --request-ip=IP %s\n", _("Request a specific IPv4 address"));
- print_supported_protocols_usage();
+#ifndef _WIN32
+ printf(" --csd-user=USER %s\n", _("Drop privileges during CSD execution"));
+ printf(" --csd-wrapper=SCRIPT %s\n", _("Run SCRIPT instead of CSD binary"));
+#endif
+ printf(" --no-http-keepalive %s\n", _("Disable HTTP connection re-use"));
+ printf(" --no-xmlpost %s\n", _("Do not attempt XML POST authentication"));
printf("\n");
From 096f91605a43da29592a0a88c2b6d67956fc018e Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sat, 21 Apr 2018 16:22:52 -0700
Subject: [PATCH 106/131] add section headings
---
main.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/main.c b/main.c
index d7858e3d..e2969703 100644
--- a/main.c
+++ b/main.c
@@ -661,7 +661,7 @@ static void print_supported_protocols_usage(void)
struct oc_vpn_proto *protos, *p;
if (openconnect_get_supported_protocols(&protos)>=0) {
- printf(_("\n Set VPN protocol:\n"));
+ printf("\n%s:\n", _("Set VPN protocol"));
for (p=protos; p->name; p++)
printf(" --protocol=%-16s %s%s\n",
p->name, p->description, p==protos ? _(" (default)") : "");
@@ -787,7 +787,10 @@ static void usage(void)
printf(" --config=CONFIGFILE %s\n", _("Read options from config file"));
printf(" -V, --version %s\n", _("Report version number"));
printf(" -h, --help %s\n", _("Display help text"));
+
print_supported_protocols_usage();
+
+ printf("\n%s:\n", _("Authentication"));
printf(" -u, --user=NAME %s\n", _("Set login username"));
printf(" --no-passwd %s\n", _("Disable password/SecurID authentication"));
printf(" --non-inter %s\n", _("Do not expect user input; exit if it is required"));
@@ -807,10 +810,14 @@ static void usage(void)
#ifndef HAVE_LIBPCSCLITE
printf(" %s\n", _("(NOTE: Yubikey OATH disabled in this build)"));
#endif
+
+ printf("\n%s:\n", _("Server validation"));
printf(" --servercert=FINGERPRINT %s\n", _("Server's certificate SHA1 fingerprint"));
printf(" --no-cert-check %s\n", _("Do not require server SSL cert to be valid"));
printf(" --no-system-trust %s\n", _("Disable default system certificate authorities"));
printf(" --cafile=FILE %s\n", _("Cert file for server verification"));
+
+ printf("\n%s:\n", _("Internet connectivity"));
printf(" -P, --proxy=URL %s\n", _("Set proxy server"));
printf(" --proxy-auth=METHODS %s\n", _("Set proxy authentication methods"));
printf(" --no-proxy %s\n", _("Disable proxy"));
@@ -822,16 +829,22 @@ static void usage(void)
printf(" --resolve=HOST:IP %s\n", _("Use IP when connecting to HOST"));
printf(" --passtos %s\n", _("copy TOS / TCLASS when using DTLS"));
printf(" --dtls-local-port=PORT %s\n", _("Set local port for DTLS datagrams"));
+
+ printf("\n%s:\n", _("Authentication (two-phase)"));
printf(" -C, --cookie=COOKIE %s\n", _("Use WebVPN cookie COOKIE"));
printf(" --cookie-on-stdin %s\n", _("Read cookie from standard input"));
printf(" --authenticate %s\n", _("Authenticate only and print login info"));
printf(" --cookieonly %s\n", _("Fetch webvpn cookie only; don't connect"));
printf(" --printcookie %s\n", _("Print webvpn cookie before connecting"));
+
#ifndef _WIN32
+ printf("\n%s:\n", _("Process control"));
printf(" -b, --background %s\n", _("Continue in background after startup"));
printf(" --pid-file=PIDFILE %s\n", _("Write the daemon's PID to this file"));
printf(" -U, --setuid=USER %s\n", _("Drop privileges after connecting"));
#endif
+
+ printf("\n%s:\n", _("Logging (two-phase)"));
#ifndef _WIN32
printf(" -l, --syslog %s\n", _("Use syslog for progress messages"));
#endif
@@ -839,12 +852,16 @@ static void usage(void)
printf(" -q, --quiet %s\n", _("Less output"));
printf(" --dump-http-traffic %s\n", _("Dump HTTP authentication traffic (implies --verbose"));
printf(" --timestamp %s\n", _("Prepend timestamp to progress messages"));
+
+ printf("\n%s:\n", _("VPN configuration script"));
printf(" -i, --interface=IFNAME %s\n", _("Use IFNAME for tunnel interface"));
printf(" -s, --script=SCRIPT %s\n", _("Shell command line for using a vpnc-compatible config script"));
printf(" %s: \"%s\"\n", _("default"), default_vpncscript);
#ifndef _WIN32
printf(" -S, --script-tun %s\n", _("Pass traffic to 'script' program, not tun"));
#endif
+
+ printf("\n%s:\n", _("Tunnel control"));
printf(" --disable-ipv6 %s\n", _("Do not ask for IPv6 connectivity"));
printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
printf(" -m, --mtu=MTU %s\n", _("Request MTU from server (legacy servers only)"));
@@ -857,13 +874,19 @@ static void usage(void)
printf(" --dtls-ciphers=LIST %s\n", _("OpenSSL ciphers to support for DTLS"));
printf(" -Q, --queue-len=LEN %s\n", _("Set packet queue limit to LEN pkts"));
printf(" --request-ip=IP %s\n", _("Request a specific IPv4 address"));
+
+ printf("\n%s:\n", _("Local system information"));
printf(" --useragent=STRING %s\n", _("HTTP header User-Agent: field"));
printf(" --local-hostname=STRING %s\n", _("Local hostname to advertise to server"));
printf(" --os=STRING %s\n", _("OS type (linux,linux-64,win,...) to report"));
+
#ifndef _WIN32
+ printf("\n%s:\n", _("CSD execution"));
printf(" --csd-user=USER %s\n", _("Drop privileges during CSD execution"));
printf(" --csd-wrapper=SCRIPT %s\n", _("Run SCRIPT instead of CSD binary"));
#endif
+
+ printf("\n%s:\n", _("Server bugs"));
printf(" --no-http-keepalive %s\n", _("Disable HTTP connection re-use"));
printf(" --no-xmlpost %s\n", _("Do not attempt XML POST authentication"));
From 5691d958813ee8c57cdb628b7eb1aca1a9de501d Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Sun, 22 Apr 2018 13:53:10 -0700
Subject: [PATCH 107/131] reuse username in challenge-auth form (fixes #102)
When going from the "normal" username/password login form to the username/challenge form,
the username should be reused, but placed in a hidden field so that the user isn't
prompted to re-enter it.
---
auth-globalprotect.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 61ba751e..79805811 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -33,10 +33,10 @@ void gpst_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
* - normal account password
* - "challenge" (2FA) password, along with form name in auth_id
*
- * This function steals the value of auth_id and prompt for
+ * This function steals the value of auth_id and prompt and username for
* use in the auth form.
*/
-static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *prompt, char *auth_id)
+static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *prompt, char *auth_id, char *username)
{
static struct oc_auth_form *form;
static struct oc_form_opt *opt, *opt2;
@@ -53,8 +53,13 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
return NULL;
opt->name=strdup("user");
opt->label=strdup(_("Username: "));
- opt->type = OC_FORM_OPT_TEXT;
- opt->flags = OC_FORM_OPT_FILL_USERNAME;
+ if (username) {
+ opt->type = OC_FORM_OPT_HIDDEN;
+ opt->_value = username;
+ } else {
+ opt->type = OC_FORM_OPT_TEXT;
+ opt->flags = OC_FORM_OPT_FILL_USERNAME;
+ }
opt2 = opt->next = calloc(1, sizeof(*opt));
if (!opt2)
@@ -307,7 +312,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
}
#endif
- form = auth_form(vpninfo, prompt, auth_id);
+ form = auth_form(vpninfo, prompt, auth_id, NULL);
if (!form)
return -ENOMEM;
@@ -357,17 +362,21 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
result = gpst_xml_or_error(vpninfo, result, xml_buf,
portal ? parse_portal_xml : parse_login_xml, &prompt, &auth_id);
if (result == -EAGAIN) {
+ /* Steal and reuse username from first form */
+ char *username = form->opts ? form->opts->_value : NULL;
+ form->opts->_value = NULL;
free_auth_form(form);
- form = auth_form(vpninfo, prompt, auth_id);
+ form = auth_form(vpninfo, prompt, auth_id, username);
if (!form)
return -ENOMEM;
- continue;
} else if (portal && result == 0) {
+ /* Portal login succeeded; reuse same credentials to login to gateway */
portal = 0;
goto redo_gateway;
- } else if (result == -EACCES) /* Invalid username/password */
- continue;
- else
+ } else if (result == -EACCES) {
+ /* Invalid username/password; reuse same form, but blank */
+ nuke_opt_values(form->opts);
+ } else
break;
}
From 7a6d32c214acb7e1f923c78c2be92ab0cf48043b Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 26 Apr 2018 08:27:33 -0700
Subject: [PATCH 108/131] I always get memory handling wrong when I do things
in a hurry (ping #98)
---
auth-globalprotect.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 50bb2a74..6da20376 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -34,8 +34,8 @@ void gpst_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
* - "challenge" (2FA) password, along with form name in auth_id
* - cookie from external authentication flow (INSTEAD OF password)
*
- * This function steals the value of auth_id, prompt, and pw_or_cookie_field for
- * use in the auth form.
+ * This function steals the value of auth_id and prompt for
+ * use in the auth form; pw_or_cookie_field is NOT stolen.
*/
static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *prompt, char *auth_id, char *pw_or_cookie_field)
{
@@ -60,7 +60,7 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
opt2 = opt->next = calloc(1, sizeof(*opt));
if (!opt2)
return NULL;
- opt2->name = pw_or_cookie_field ? : strdup("passwd");
+ opt2->name = strdup(pw_or_cookie_field ? : "passwd");
asprintf(&opt2->label, "%s: ", auth_id ? _("Challenge") : (pw_or_cookie_field ? : _("Password")));
opt2->type = vpninfo->token_mode!=OC_TOKEN_MODE_NONE ? OC_FORM_OPT_TOKEN : OC_FORM_OPT_PASSWORD;
opt2->flags = OC_FORM_OPT_FILL_PASSWORD;
From be2d62d0082860a8582e3e8081b0bf11825f9c0a Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Fri, 4 May 2018 11:47:31 +0200
Subject: [PATCH 109/131] Add Dockerfile and instructions
Signed-off-by: andor-pierdelacabeza
---
Dockerfile | 14 ++++++++++----
README.md | 26 ++++++++++++++++++++++++++
2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index c9982a4d..cbebbe90 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM debian:8-slim
+FROM debian:9-slim as builder
WORKDIR /openconnect
RUN apt update \
&& apt install -y \
@@ -12,10 +12,16 @@ RUN apt update \
vpnc-scripts \
pkg-config \
libgnutls28-dev \
- git
+ git \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
ADD . .
RUN ./autogen.sh
RUN ./configure
RUN make
-RUN make install
-RUN ldconfig
+
+#FROM debian:9-slim
+#WORKDIR /openconnect
+#COPY --from=builder /openconnect .
+#RUN make install
+#RUN ldconfig
diff --git a/README.md b/README.md
index c870d08e..5e0b2910 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,32 @@ certificate authentication… since that's the only example I have. But
I'd welcome feedback if there are other authentication methods in use
out there.
+## Docker
+
+Building an openconnect Docker image is as easy as:
+
+```sh
+$ docker build -t openconnect .
+```
+
+Then, you can run that docker image as a container:
+
+```sh
+$ docker run -ti openconnect
+/openconnect# ./openconnect --protocol=gp server.company.com
+```
+
+But that'll restrict the use of the tunnel to *inside* the container,
+and maybe you want to use it system-wide. For that, you'll need a
+privileged container making use of the host (you computer) network:
+
+```sh
+$ docker run -ti --rm --privileged --net=host openconnect
+/openconnect# ./openconnect --protocol=gp server.company.com
+```
+Leave that container running, open another terminal, and you'll see a
+newly created tun connection for your whole system to use.
+
## Portal vs. gateway servers
For my VPN, the VPN tunnel server is the *same* as the VPN "portal"
From 95fc2c6eba780c5265bb6bfd40594ecccaead953 Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Fri, 4 May 2018 11:50:46 +0200
Subject: [PATCH 110/131] Add Docker to ToC
Signed-off-by: andor-pierdelacabeza
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 5e0b2910..6a9b4b73 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@
* [Building from source on Linux](#building-from-source-on-linux)
* [Building on the Mac](#building-on-the-mac)
* [Connecting](#connecting)
+ * [Docker] (#docker)
* [Portal vs. gateway servers](#portal-vs-gateway-servers)
# What is this?
From c156c1b0df84a2cf9902e23cf07d9cd3dc06a0f8 Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Fri, 4 May 2018 11:51:34 +0200
Subject: [PATCH 111/131] =?UTF-8?q?Fix=20Docker=20in=20ToC=20=C2=AC=5F?=
=?UTF-8?q?=C2=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: andor-pierdelacabeza
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 6a9b4b73..f0415490 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
* [Building from source on Linux](#building-from-source-on-linux)
* [Building on the Mac](#building-on-the-mac)
* [Connecting](#connecting)
- * [Docker] (#docker)
+ * [Docker](#docker)
* [Portal vs. gateway servers](#portal-vs-gateway-servers)
# What is this?
From 64ad7ca10d4dfde2b4a49b1a977ab90d1c9eb83d Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Fri, 4 May 2018 12:53:59 +0200
Subject: [PATCH 112/131] Add Docker ToDo
Signed-off-by: andor-pierdelacabeza
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 424179f0..4af90fde 100644
--- a/README.md
+++ b/README.md
@@ -208,3 +208,4 @@ GATEWAY: [NorthAmerica|Europe|Asia]:
# TODO
* Support web-based/SAML-based authentication flows (see [pull #98](//github.com/dlenski/openconnect/issues/98) for preliminary work)
+* Configure multi-stage build into the Dockerfile, to get a smaller Docker image
From eb4de65bf2535ffac8ada769ec8c7f348bed9681 Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Tue, 8 May 2018 15:51:13 +0200
Subject: [PATCH 113/131] Add first TravisCI testing
Signed-off-by: andor-pierdelacabeza
---
.travis.yml | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index dbae5bd1..8ae65945 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,3 +26,14 @@ script: ./autogen.sh &&
make VERBOSE=1 version.c &&
make &&
make VERBOSE=1 -j4 check
+
+jobs:
+ include:
+ - stage: docker build
+ sudo: required
+ services:
+ - docker
+ before_install:
+ - docker built -t openconnect .
+ script:
+ - docker run openconnect "/openconnect/openconnect" "-V"
From 7e4960ae7e98590b1251310108878b64d4d109c4 Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Tue, 8 May 2018 15:53:40 +0200
Subject: [PATCH 114/131] Fix docker build :(
Signed-off-by: andor-pierdelacabeza
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 8ae65945..e0526c86 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,6 +34,6 @@ jobs:
services:
- docker
before_install:
- - docker built -t openconnect .
+ - docker build -t openconnect .
script:
- docker run openconnect "/openconnect/openconnect" "-V"
From 382967a3f74e369bcb18405f325d2715d427defb Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Tue, 8 May 2018 16:03:43 +0200
Subject: [PATCH 115/131] Test multistage Travis build
Signed-off-by: andor-pierdelacabeza
---
.travis.yml | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index e0526c86..75732b5c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,34 +3,35 @@ notifications:
false
dist: trusty
-sudo: false
+sudo: required
language: c
compiler:
- gcc
+services:
+ - docker
+
env:
global:
- MAKEFLAGS="-j 2"
-before_script:
- - sudo apt-get update -qq
- - sudo apt-get install -qq build-essential autoconf automake libtool pkg-config
- vpnc-scripts
- gettext libproxy-dev libxml2-dev liblz4-1 liblz4-dev libstoken-dev liboath-dev
- libgnutls28-dev # actually GnuTLS 3.2.11 ¯\_(ツ)_/¯
-
-
-script: ./autogen.sh &&
- ./configure &&
- make VERBOSE=1 version.c &&
- make &&
- make VERBOSE=1 -j4 check
-
jobs:
include:
+ - stage: app build
+ before_script:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq build-essential autoconf automake libtool pkg-config
+ vpnc-scripts
+ gettext libproxy-dev libxml2-dev liblz4-1 liblz4-dev libstoken-dev liboath-dev
+ libgnutls28-dev # actually GnuTLS 3.2.11 ¯\_(ツ)_/¯
+ script:
+ - ./autogen.sh
+ - ./configure
+ - make VERBOSE=1 version.c
+ - make
+ - make VERBOSE=1 -j4 check
- stage: docker build
- sudo: required
services:
- docker
before_install:
From 983a5157b178d916659347689f3a9275e0d83526 Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Tue, 8 May 2018 16:18:35 +0200
Subject: [PATCH 116/131] Test _gp_ string grepping
Signed-off-by: andor-pierdelacabeza
---
.travis.yml | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 75732b5c..60142e8e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,13 +12,10 @@ compiler:
services:
- docker
-env:
- global:
- - MAKEFLAGS="-j 2"
-
jobs:
include:
- stage: app build
+ env: MAKEFLAGS="-j 2"
before_script:
- sudo apt-get update -qq
- sudo apt-get install -qq build-essential autoconf automake libtool pkg-config
@@ -34,7 +31,7 @@ jobs:
- stage: docker build
services:
- docker
- before_install:
+ before_script:
- docker build -t openconnect .
script:
- - docker run openconnect "/openconnect/openconnect" "-V"
+ - docker run openconnect "/openconnect/openconnect" "-V"| grep notfound
From 9e79948d46e615b29e6221182c3524eabbd76188 Mon Sep 17 00:00:00 2001
From: andor-pierdelacabeza
Date: Tue, 8 May 2018 16:27:04 +0200
Subject: [PATCH 117/131] Add GlobalProtect support availability
Signed-off-by: andor-pierdelacabeza
---
.travis.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 60142e8e..937aad59 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,4 +34,6 @@ jobs:
before_script:
- docker build -t openconnect .
script:
- - docker run openconnect "/openconnect/openconnect" "-V"| grep notfound
+ - docker run openconnect "/openconnect/openconnect" "-V"| grep gp
+ # This last grep should be changed if this goes upstream, as it
+ # only checks for GlobalProtect support availability.
From 077c420a0db8ae96b00888726db1a05901dffa82 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 22 May 2018 18:57:10 +0300
Subject: [PATCH 118/131] attempted quick fix for #109
---
gpst.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/gpst.c b/gpst.c
index 44a67412..64f29591 100644
--- a/gpst.c
+++ b/gpst.c
@@ -261,6 +261,20 @@ int gpst_xml_or_error(struct openconnect_info *vpninfo, int result, char *respon
goto bad_xml;
}
+ /* is it user.name...... */
+ if (xmlnode_is_named(xml_node, "challenge")) {
+ for (xml_node=xml_node->children; xml_node; xml_node=xml_node->next) {
+ if (inputStr && xmlnode_is_named(xml_node, "inputstr"))
+ xmlnode_get_text(xml_node, "inputstr", (const char **)inputStr);
+ else if (prompt && xmlnode_is_named(xml_node, "respmsg"))
+ xmlnode_get_text(xml_node, "respmsg", (const char **)prompt);
+ else if (xmlnode_is_named(xml_node, "user"))
+ ; /* XXX: override the username passed to the next form? */
+ }
+ result = -EAGAIN;
+ goto out;
+ }
+
if (xml_cb)
result = xml_cb(vpninfo, xml_node);
From 27c556829a2c0d21d2ee5035b56365056feef96a Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 23 May 2018 11:56:49 +0300
Subject: [PATCH 119/131] don't reuse challenge auth form from portal (another
kludge for #109)
---
auth-globalprotect.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index c8349cdf..97bfb6b9 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -324,7 +324,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal, const char *
if (result)
goto out;
- redo_gateway:
+ reuse_whole_form:
buf_truncate(request_body);
/* generate token code if specified */
@@ -363,17 +363,25 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal, const char *
result = gpst_xml_or_error(vpninfo, result, xml_buf,
portal ? parse_portal_xml : parse_login_xml, &prompt, &auth_id);
if (result == -EAGAIN) {
+ char *username;
+ reuse_username:
/* Steal and reuse username from first form */
- char *username = form->opts ? form->opts->_value : NULL;
+ username = form->opts ? form->opts->_value : NULL;
form->opts->_value = NULL;
free_auth_form(form);
form = auth_form(vpninfo, prompt, auth_id, username, pw_or_cookie_field);
if (!form)
return -ENOMEM;
} else if (portal && result == 0) {
- /* Portal login succeeded; reuse same credentials to login to gateway */
+ /* Portal login succeeded; reuse same credentials to login to gateway,
+ * unless it was a challenge auth form, in which case we only
+ * reuse the username.
+ */
portal = 0;
- goto redo_gateway;
+ if (form->auth_id && form->auth_id[0] != '_')
+ goto reuse_username;
+ else
+ goto reuse_whole_form;
} else if (result == -EACCES) {
/* Invalid username/password; reuse same form, but blank */
nuke_opt_values(form->opts);
From 49a70742ee6cc3026b28acabe7e86af38a0f6262 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 24 May 2018 09:36:02 +0300
Subject: [PATCH 120/131] haste makes waste: don't reuse unreusable values
(ping #109)
---
auth-globalprotect.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 97bfb6b9..d1e7a21d 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -302,7 +302,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal, const char *
const char *request_body_type = "application/x-www-form-urlencoded";
const char *method = "POST";
char *xml_buf=NULL, *orig_path;
- char *prompt=NULL, *auth_id=NULL;
+ char *prompt=NULL, *auth_id=NULL, *username=NULL;
#ifdef HAVE_LIBSTOKEN
/* Step 1: Unlock software token (if applicable) */
@@ -313,7 +313,7 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal, const char *
}
#endif
- form = auth_form(vpninfo, prompt, auth_id, NULL, pw_or_cookie_field);
+ form = auth_form(vpninfo, prompt, auth_id, username, pw_or_cookie_field);
if (!form)
return -ENOMEM;
@@ -363,13 +363,13 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal, const char *
result = gpst_xml_or_error(vpninfo, result, xml_buf,
portal ? parse_portal_xml : parse_login_xml, &prompt, &auth_id);
if (result == -EAGAIN) {
- char *username;
reuse_username:
/* Steal and reuse username from first form */
username = form->opts ? form->opts->_value : NULL;
form->opts->_value = NULL;
free_auth_form(form);
form = auth_form(vpninfo, prompt, auth_id, username, pw_or_cookie_field);
+ prompt = auth_id = username = NULL;
if (!form)
return -ENOMEM;
} else if (portal && result == 0) {
From bfaba1b2ba2777f2495251e3870e5e88b5275fcc Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 24 May 2018 09:39:45 +0300
Subject: [PATCH 121/131] call the initial form "_default", not "_gateway",
since it can also be used by the portal
---
auth-globalprotect.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index d1e7a21d..ac32fe53 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -47,7 +47,7 @@ static struct oc_auth_form *auth_form(struct openconnect_info *vpninfo, char *pr
if (!form)
return NULL;
form->message = prompt ? : strdup(_("Please enter your username and password"));
- form->auth_id = auth_id ? : strdup("_gateway");
+ form->auth_id = auth_id ? : strdup("_default");
opt = form->opts = calloc(1, sizeof(*opt));
if (!opt)
From 1b3fbc7918cdd96bf5fd932867e1989be277ebcf Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 29 May 2018 21:24:15 +0300
Subject: [PATCH 122/131] GlobalProtect server simulator: almost as fun as
Microsoft Flight Simulator 1.0
---
README.md | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 4af90fde..77a90744 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,13 @@ transcript](PAN_GlobalProtect_protocol_doc.md)
and include information about relevant differences in your issue
report.
+**Bonus points:** If your VPN uses a weird authentication flow, please
+check out the Gist where I wrote a [quick-and-dirty "GlobalProtect server
+simulator"](https://gist.github.com/dlenski/08359391270337f7894b1e2a97d0d9a9) in
+Python. It's fairly straightforward to understand, and if you can
+modify it to reproduce the authentication flow used by your VPN, it'll
+make it a whole lot easier to add support.
+
## Installation
Please refer to the [build requirements for the official releases of OpenConnect](https://www.infradead.org/openconnect/building.html). **This version has the exact same build dependencies as OpenConnect v7.06**; modern versions of `autoconf`, `automake`, `gcc`, `libxml`, etc.
@@ -114,7 +121,7 @@ Then, you can run that docker image as a container:
```sh
$ docker run -ti openconnect
-/openconnect# ./openconnect --protocol=gp server.company.com
+/openconnect# ./openconnect --protocol=gp server.company.com
```
But that'll restrict the use of the tunnel to *inside* the container,
From 0e71e62440ff82156677e1941fbb2994bf403eec Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 30 May 2018 13:56:10 +0300
Subject: [PATCH 123/131] just defined esp_magic as uint32_t
(as @dwmw2 convinces me, https://github.com/dlenski/openconnect/commit/3c8e11e86edadfb2424ceba05b24f66d041a26b9#r29083673)
---
openconnect-internal.h | 4 ----
1 file changed, 4 deletions(-)
diff --git a/openconnect-internal.h b/openconnect-internal.h
index e22e67e9..738e7669 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -379,11 +379,7 @@ struct openconnect_info {
struct esp esp_out;
int enc_key_len;
int hmac_key_len;
-#ifdef _WIN32
uint32_t esp_magic; /* GlobalProtect magic ping address (network-endian) */
-#else
- in_addr_t esp_magic; /* GlobalProtect magic ping address (network-endian) */
-#endif
int tncc_fd; /* For Juniper TNCC */
const char *csd_xmltag;
From 695de11ff18848f966bb8a735836ec999ea7f0f2 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 31 Jul 2018 19:32:26 -0700
Subject: [PATCH 124/131] Tolerate packets that are larger than negotiated MTU
after decompression
In July 2016, the "Fixed regression with CSTP MTU handling" patch
(http://git.infradead.org/users/dwmw2/openconnect.git/commitdiff/90e1555494dbc1cf462552679f9aa3d30451d123)
allowed openconnect to gracefully handle uncompressed CSTP packets larger
than the negotiated MTU.
This patch extends that approach to tolerate compressed packets which are
larger than the negotiated MTU after decompression.
---
cstp.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/cstp.c b/cstp.c
index 3c35d05a..cb9fea81 100644
--- a/cstp.c
+++ b/cstp.c
@@ -743,7 +743,11 @@ static int cstp_reconnect(struct openconnect_info *vpninfo)
int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type,
unsigned char *buf, int len)
{
- struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->ip_info.mtu);
+ /* Some servers send us packets that are larger than
+ negotiated MTU after decompression. We reserve some extra
+ space to handle that */
+ int receive_mtu = MAX(16384, vpninfo->ip_info.mtu);
+ struct pkt *new = malloc(sizeof(struct pkt) + receive_mtu);
const char *comprname = "";
if (!new)
@@ -760,7 +764,7 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type
vpninfo->inflate_strm.avail_in = len - 4;
vpninfo->inflate_strm.next_out = new->data;
- vpninfo->inflate_strm.avail_out = vpninfo->ip_info.mtu;
+ vpninfo->inflate_strm.avail_out = receive_mtu;
vpninfo->inflate_strm.total_out = 0;
if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
@@ -782,7 +786,7 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type
} else if (compr_type == COMPR_LZS) {
comprname = "LZS";
- new->len = lzs_decompress(new->data, vpninfo->ip_info.mtu, buf, len);
+ new->len = lzs_decompress(new->data, receive_mtu, buf, len);
if (new->len < 0) {
len = new->len;
if (len == 0)
@@ -795,7 +799,7 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type
#ifdef HAVE_LZ4
} else if (compr_type == COMPR_LZ4) {
comprname = "LZ4";
- new->len = LZ4_decompress_safe((void *)buf, (void *)new->data, len, vpninfo->ip_info.mtu);
+ new->len = LZ4_decompress_safe((void *)buf, (void *)new->data, len, receive_mtu);
if (new->len <= 0) {
len = new->len;
if (len == 0)
From 1054ac1ccccdab4b52e2920887d9ff490dbd4eb7 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Tue, 31 Jul 2018 19:35:59 -0700
Subject: [PATCH 125/131] Align naming and commenting of mechanism for
receiving oversize packets across protocols
We've now implemented mechanisms to tolerate larger-than-expected packets for:
- Uncompressed CSTP packets ("Fixed regression with CSTP MTU handling"
patch in July 2016)
- Uncompressed oNCP packets ("Do not drop vpn connection if packet arrived
is larger than MTU" patch in May 2017)
- Uncompressed GPST packets (in original merge from March 2018; this is a
virtual necessity for GlobalProtect because it has no functional
mechanism for negotiating the MTU)
- Uncompressed ESP packets ("check for oversize ESP packets, with 256
bytes of headroom above calculated" in March 2018; GlobalProtect requires
this for the aforementioned reason)
- Compressed CSTP packets (preceding patch in this series)
Since this is a requiring issue across protocols, it's useful to align the
naming, commenting, and packet sizing-tolerance across the source files.
1) Use receive_mtu everywhere as the name for the maximum tolerated size of an
incoming packet.
2) Insert similar comments explaining its purpose everywhere it's used.
3) Use receive_mtu = MAX(16384, vpninfo->ip_info.mtu) for all TLS-based
tunnels, because 16384 is the maximum TLS record size.
4) Use receive_mtu = MAX(2048, vpninfo->vpninfo->ip_info.mtu + 256) for
all UDP-based tunnels, because the MTU of IP datagrams on the public
internet is effectively ~1500.
---
cstp.c | 11 +++++++----
esp.c | 6 +++++-
gpst.c | 5 ++++-
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/cstp.c b/cstp.c
index cb9fea81..47e8e961 100644
--- a/cstp.c
+++ b/cstp.c
@@ -900,18 +900,21 @@ int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
and add POLLOUT. As it is, though, it'll just chew CPU time in that
fairly unlikely situation, until the write backlog clears. */
while (1) {
- int len = MAX(16384, vpninfo->deflate_pkt_size ? : vpninfo->ip_info.mtu);
- int payload_len;
+ /* Some servers send us packets that are larger than
+ negotiated MTU. We reserve some extra space to
+ handle that */
+ int receive_mtu = MAX(16384, vpninfo->deflate_pkt_size ? : vpninfo->ip_info.mtu);
+ int len, payload_len;
if (!vpninfo->cstp_pkt) {
- vpninfo->cstp_pkt = malloc(sizeof(struct pkt) + len);
+ vpninfo->cstp_pkt = malloc(sizeof(struct pkt) + receive_mtu);
if (!vpninfo->cstp_pkt) {
vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
break;
}
}
- len = ssl_nonblock_read(vpninfo, vpninfo->cstp_pkt->cstp.hdr, len + 8);
+ len = ssl_nonblock_read(vpninfo, vpninfo->cstp_pkt->cstp.hdr, receive_mtu + 8);
if (!len)
break;
if (len < 0)
diff --git a/esp.c b/esp.c
index 9845701a..e35d0c53 100644
--- a/esp.c
+++ b/esp.c
@@ -256,10 +256,14 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
struct esp *esp = &vpninfo->esp_in[vpninfo->current_esp_in];
struct esp *old_esp = &vpninfo->esp_in[vpninfo->current_esp_in ^ 1];
struct pkt *this;
- int receive_mtu = MAX(2048, vpninfo->ip_info.mtu + 256);
int work_done = 0;
int ret;
+ /* Some servers send us packets that are larger than negotiated
+ MTU, or lack the ability to negotiate MTU (see gpst.c). We
+ reserve some extra space to handle that */
+ int receive_mtu = MAX(2048, vpninfo->ip_info.mtu + 256);
+
if (vpninfo->dtls_state == DTLS_SLEEPING) {
if (ka_check_deadline(timeout, time(NULL), vpninfo->new_dtls_started + vpninfo->dtls_attempt_period)
|| vpninfo->dtls_need_reconnect) {
diff --git a/gpst.c b/gpst.c
index 64f29591..8ca62941 100644
--- a/gpst.c
+++ b/gpst.c
@@ -1007,7 +1007,10 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
goto do_reconnect;
while (1) {
- int receive_mtu = MAX(2048, vpninfo->ip_info.mtu + 256);
+ /* Some servers send us packets that are larger than
+ negotiated MTU. We reserve some extra space to
+ handle that */
+ int receive_mtu = MAX(16384, vpninfo->ip_info.mtu);
int len, payload_len;
if (!vpninfo->cstp_pkt) {
From f37cc2115709064c0ac2c6273ab6f6bbf2e3f8c9 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 1 Aug 2018 18:28:01 -0700
Subject: [PATCH 126/131] Clarify a few uncommented corners of the ESP support
Signed-off-by: Daniel Lenski
---
esp.c | 6 ++++++
library.c | 3 ++-
oncp.c | 1 +
openconnect-internal.h | 5 +++--
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/esp.c b/esp.c
index e35d0c53..d51e44aa 100644
--- a/esp.c
+++ b/esp.c
@@ -296,6 +296,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
len);
work_done = 1;
+ /* both supported algos (SHA1 and MD5) have 12-byte MAC lengths (RFC2403 and RFC2404) */
if (len <= sizeof(pkt->esp) + 12)
continue;
@@ -319,6 +320,11 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
continue;
}
+ /* Possible values of the Next Header field are:
+ 0x04: IP[v4]-in-IP
+ 0x05: supposed to mean Internet Stream Protocol
+ (XXX: but used for LZO compressed packets by Juniper)
+ 0x29: IPv6 encapsulation */
if (pkt->data[len - 1] != 0x04 && pkt->data[len - 1] != 0x29 &&
pkt->data[len - 1] != 0x05) {
vpn_progress(vpninfo, PRG_ERR,
diff --git a/library.c b/library.c
index 39973631..b199a897 100644
--- a/library.c
+++ b/library.c
@@ -905,7 +905,8 @@ int openconnect_setup_tun_device(struct openconnect_info *vpninfo,
static const char *compr_name_map[] = {
[COMPR_DEFLATE] = "Deflate",
[COMPR_LZS] = "LZS",
- [COMPR_LZ4] = "LZ4"
+ [COMPR_LZ4] = "LZ4",
+ [COMPR_LZO] = "LZO",
};
const char *openconnect_get_cstp_compression(struct openconnect_info * vpninfo)
diff --git a/oncp.c b/oncp.c
index 17853af9..945681cd 100644
--- a/oncp.c
+++ b/oncp.c
@@ -323,6 +323,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
if (attrlen != 1)
goto badlen;
vpninfo->esp_compr = data[0];
+ vpninfo->dtls_compr = data[0] ? COMPR_LZO : 0;
vpn_progress(vpninfo, PRG_DEBUG, _("ESP compression: %d\n"), data[0]);
break;
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 738e7669..5e301103 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -174,10 +174,11 @@ struct pkt {
#define COMPR_DEFLATE (1<<0)
#define COMPR_LZS (1<<1)
#define COMPR_LZ4 (1<<2)
-#define COMPR_MAX COMPR_LZ4
+#define COMPR_LZO (1<<3)
+#define COMPR_MAX COMPR_LZO
#ifdef HAVE_LZ4
-#define COMPR_STATELESS (COMPR_LZS | COMPR_LZ4)
+#define COMPR_STATELESS (COMPR_LZS | COMPR_LZ4 | COMPR_LZO)
#else
#define COMPR_STATELESS (COMPR_LZS)
#endif
From bc80fb959f4147ef40f2fd1b90e72f299244053b Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 1 Aug 2018 18:13:59 -0700
Subject: [PATCH 127/131] Clarify protocol description in connection message
- Include both the TCP- and UDP-based protocols' compression details
- The UDP-based protocol really can't be connected by the time this
prints, since the mainloop hasn't had enough time to receive the
connection confirmation packets; show it as "in progress"
Before (with default verbosity):
Connected as 10.0.0.3 + dead::be:ef, using SSL + deflate
Established DTLS connection (using GnuTLS). Ciphersuite (DTLS1.2)-(RSA)-(AES-128-GCM).
After:
Connected as 10.0.0.3 + dead::be:ef, using SSL + Deflate, with DTLS + LZS in progress
Established DTLS connection (using GnuTLS). Ciphersuite (DTLS1.2)-(RSA)-(AES-128-GCM).
Signed-off-by: Daniel Lenski
---
gpst.c | 2 +-
library.c | 3 +++
main.c | 28 ++++++++--------------------
openconnect-internal.h | 1 +
4 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/gpst.c b/gpst.c
index 8ca62941..bdbc93ce 100644
--- a/gpst.c
+++ b/gpst.c
@@ -617,7 +617,7 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
vpninfo->ip_info.mtu = calculate_mtu(vpninfo, !no_esp_reason);
vpn_progress(vpninfo, PRG_ERR,
_("No MTU received. Calculated %d for %s%s\n"), vpninfo->ip_info.mtu,
- no_esp_reason ? "TLS tunnel. " : "ESP tunnel", no_esp_reason ? : "");
+ no_esp_reason ? "SSL tunnel. " : "ESP tunnel", no_esp_reason ? : "");
/* return -EINVAL; */
}
if (!vpninfo->ip_info.addr) {
diff --git a/library.c b/library.c
index b199a897..b05d197a 100644
--- a/library.c
+++ b/library.c
@@ -117,6 +117,7 @@ const struct vpn_proto openconnect_protos[] = {
.tcp_mainloop = cstp_mainloop,
.add_http_headers = cstp_common_headers,
.obtain_cookie = cstp_obtain_cookie,
+ .udp_protocol = "DTLS",
#ifdef HAVE_DTLS
.udp_setup = dtls_setup,
.udp_mainloop = dtls_mainloop,
@@ -133,6 +134,7 @@ const struct vpn_proto openconnect_protos[] = {
.tcp_mainloop = oncp_mainloop,
.add_http_headers = oncp_common_headers,
.obtain_cookie = oncp_obtain_cookie,
+ .udp_protocol = "ESP",
#ifdef HAVE_ESP
.udp_setup = esp_setup,
.udp_mainloop = esp_mainloop,
@@ -152,6 +154,7 @@ const struct vpn_proto openconnect_protos[] = {
.tcp_mainloop = gpst_mainloop,
.add_http_headers = gpst_common_headers,
.obtain_cookie = gpst_obtain_cookie,
+ .udp_protocol = "ESP",
#ifdef HAVE_ESP
.udp_setup = esp_setup,
.udp_mainloop = esp_mainloop,
diff --git a/main.c b/main.c
index e2969703..f782c0f0 100644
--- a/main.c
+++ b/main.c
@@ -1087,7 +1087,7 @@ int main(int argc, char **argv)
char *urlpath = NULL;
struct oc_vpn_option *gai;
char *ip;
- const char *compr = "";
+ const char *ssl_compr, *udp_compr;
char *proxy = getenv("https_proxy");
char *vpnc_script = NULL;
const struct oc_ip_info *ip_info;
@@ -1609,33 +1609,21 @@ int main(int argc, char **argv)
* reconnects end up in infinite loop trying to connect
* to non existing DTLS */
vpninfo->dtls_state = DTLS_DISABLED;
- fprintf(stderr, _("Set up DTLS failed; using SSL instead\n"));
+ fprintf(stderr, _("Set up UDP failed; using SSL instead\n"));
}
openconnect_get_ip_info(vpninfo, &ip_info, NULL, NULL);
- if (vpninfo->dtls_state != DTLS_CONNECTED) {
- if (vpninfo->cstp_compr == COMPR_DEFLATE)
- compr = " + deflate";
- else if (vpninfo->cstp_compr == COMPR_LZS)
- compr = " + lzs";
- else if (vpninfo->cstp_compr == COMPR_LZ4)
- compr = " + lz4";
- } else {
- if (vpninfo->dtls_compr == COMPR_DEFLATE)
- compr = " + deflate";
- else if (vpninfo->dtls_compr == COMPR_LZS)
- compr = " + lzs";
- else if (vpninfo->dtls_compr == COMPR_LZ4)
- compr = " + lz4";
- }
+ ssl_compr = openconnect_get_cstp_compression(vpninfo);
+ udp_compr = openconnect_get_dtls_compression(vpninfo);
vpn_progress(vpninfo, PRG_INFO,
- _("Connected as %s%s%s, using %s%s\n"),
+ _("Connected as %s%s%s, using SSL%s%s, with %s%s%s %s\n"),
ip_info->addr?:"",
(ip_info->netmask6 && ip_info->addr) ? " + " : "",
ip_info->netmask6 ? : "",
- (vpninfo->dtls_state != DTLS_CONNECTED) ? "SSL"
- : "DTLS", compr);
+ ssl_compr ? " + " : "", ssl_compr ? : "",
+ vpninfo->proto->udp_protocol ? : "UDP", udp_compr ? " + " : "", udp_compr ? : "",
+ (vpninfo->dtls_state == DTLS_DISABLED || vpninfo->dtls_state == DTLS_NOSECRET ? _("disabled") : _("in progress")));
if (!vpninfo->vpnc_script) {
vpn_progress(vpninfo, PRG_INFO,
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 5e301103..63c2f348 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -264,6 +264,7 @@ struct vpn_proto {
const char *name;
const char *pretty_name;
const char *description;
+ const char *udp_protocol;
const char *override_useragent;
unsigned int flags;
int (*vpn_close_session)(struct openconnect_info *vpninfo, const char *reason);
From 163515a9f7a5c0c4b5bebecdc89996f1a0fd0e33 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Wed, 1 Aug 2018 18:25:13 -0700
Subject: [PATCH 128/131] Fill in a few missing references to GlobalProtect,
TNCC, and DTLS support in the docs
Also clarifies the command-line options regarding compression
Signed-off-by: Daniel Lenski
---
main.c | 4 ++--
www/anyconnect.xml | 2 +-
www/features.xml | 2 +-
www/globalprotect.xml | 6 ++++++
www/index.xml | 9 ++++++---
www/juniper.xml | 8 ++++----
6 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/main.c b/main.c
index f782c0f0..1ce4d080 100644
--- a/main.c
+++ b/main.c
@@ -866,8 +866,8 @@ static void usage(void)
printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
printf(" -m, --mtu=MTU %s\n", _("Request MTU from server (legacy servers only)"));
printf(" --base-mtu=MTU %s\n", _("Indicate path MTU to/from server"));
- printf(" -d, --deflate %s\n", _("Enable compression (default)"));
- printf(" -D, --no-deflate %s\n", _("Disable compression"));
+ printf(" -d, --deflate %s\n", _("Enable stateful compression (default is stateless only)"));
+ printf(" -D, --no-deflate %s\n", _("Disable all compression"));
printf(" --force-dpd=INTERVAL %s\n", _("Set minimum Dead Peer Detection interval"));
printf(" --pfs %s\n", _("Require perfect forward secrecy"));
printf(" --no-dtls %s\n", _("Disable DTLS"));
diff --git a/www/anyconnect.xml b/www/anyconnect.xml
index 5ee1ce17..fd7e90ac 100644
--- a/www/anyconnect.xml
+++ b/www/anyconnect.xml
@@ -59,7 +59,7 @@ The username/password for OpenSSL RT is 'guest/guest'
GnuTLS
-Support for Cisco's version of DTLS was included in GnuTLS from 3.0.21 onwards.
+Support for Cisco's version of DTLS was included in GnuTLS from 3.0.21 onwards (commited in fd5ca1af).
diff --git a/www/features.xml b/www/features.xml
index cbe91447..f878e96d 100644
--- a/www/features.xml
+++ b/www/features.xml
@@ -24,7 +24,7 @@
- Automatic update of VPN server list / configuration.
- Roaming support, allowing reconnection when the local IP address changes.
- Run without root privileges (see here).
- - Support for "Cisco Secure Desktop" (see here) and "GlobalProtect HIP report" (see here).
+ - Support for "Cisco Secure Desktop" (see here), Juniper TNCC (see here), and "GlobalProtect HIP report" (see here).
- Graphical connection tools for various environments (see here).
diff --git a/www/globalprotect.xml b/www/globalprotect.xml
index 655db9a2..a9de423a 100644
--- a/www/globalprotect.xml
+++ b/www/globalprotect.xml
@@ -16,6 +16,12 @@
href="https://tools.ietf.org/html/rfc3948">ESP, with routing and
configuration information distributed in XML format.
+GlobalProtect mode is requested by adding --protocol=gp
+to the command line:
+
+ openconnect --protocol=gp vpn.example.com
+
+
Authentication
To authenticate, you connect to the secure web server (POST
diff --git a/www/index.xml b/www/index.xml
index 28d0b95a..ec2147e9 100644
--- a/www/index.xml
+++ b/www/index.xml
@@ -9,15 +9,18 @@
OpenConnect
-
OpenConnect is an SSL VPN client initially created to support Cisco's AnyConnect SSL VPN. It has since been ported to support the Juniper SSL VPN which is now known as Pulse Connect Secure.
+OpenConnect is an SSL VPN client initially created to support Cisco's AnyConnect SSL VPN.
+It has since been ported to support the Juniper SSL VPN (which is now known as Pulse Connect Secure),
+and to the Palo Alto Networks GlobalProtect SSL VPN.
OpenConnect is released under the GNU Lesser Public License, version 2.1.
Like vpnc,
OpenConnect is not officially supported by, or associated in any way
-with, Cisco Systems, Juniper Networks or Pulse Secure. It just happens to interoperate with their equipment.
+with, Cisco Systems, Juniper Networks, Pulse Secure, or Palo Alto Networks.
+It just happens to interoperate with their equipment.
-Development of OpenConnect was started after a trial of the Cisco
+
Development of OpenConnect was started after a trial of the Cisco
client under Linux found it to have many deficiencies:
- Inability to use SSL certificates from a TPM or
diff --git a/www/juniper.xml b/www/juniper.xml
index d4f3fbfe..82f31061 100644
--- a/www/juniper.xml
+++ b/www/juniper.xml
@@ -16,10 +16,10 @@ experimental, and is quite likely to be deprecated in favour of the newer
Junos
Pulse protocol.
-
For the time being, Juniper mode is requested by adding --juniper
+
Juniper mode is requested by adding --protocol=nc
to the command line:
- openconnect --juniper vpn.example.com
+ openconnect --protocol=nc vpn.example.com
Network Connect works very similarly to
@@ -65,7 +65,7 @@ pass the cookie to OpenConnect with its -C option, for example:
-Host Checker (tncc.jar)
+Host Checker (tncc.jar)
Many sites require a Java applet to run certain tests as a precondition
of authentication. This works by sending a DSPREAUTH cookie
@@ -80,7 +80,7 @@ along with the tncc-preload.so from
this repository.
It may also be necessary to pass a Mozilla-compatible user agent string:
- ./openconnect --juniper --useragent 'Mozilla/5.0 (Linux) Firefox' --csd-wrapper=./tncc-wrapper.py vpn.example.com
+ ./openconnect --protocol=nc --useragent 'Mozilla/5.0 (Linux) Firefox' --csd-wrapper=./tncc-wrapper.py vpn.example.com
From 6d1febd94d2d334c0d8d64bc6b8cbfae74b5ec51 Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 2 Aug 2018 12:10:45 -0700
Subject: [PATCH 129/131] Reduce unnecessary connection-rebuilding for Juniper
The current oNCP (Juniper) protocol support sets "Connection: close" in all
HTTP requests. This is not ideal because it requires many TLS handshakes
and round-trips, making the connection very slow to start when the latency
of the connection to the gateway is high, especially if the number of
authentication forms and redirects is large.
Simply removing the "Connection: close" header causes the oNCP connection
to fail; the server doesn't interpret the first packet sent over the oNCP
tunnel correctly (the vestigial authentication packet).
However, it appears that the "Connection: close" header *only* needs to be
specified for this final HTTP request, and not for any of the prior ones.
The presence of this header seems to signal to the gateway that it should
stop treating this as an HTTP connection, and start treating it as an
oNCP tunnel.
Tested on two different Juniper gateways, one which returns
"NCP-Version: 2" and one which returns "NCP-Version: 3" in response to
the oNCP negotiation requests.
---
auth-juniper.c | 1 -
oncp.c | 14 ++++++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/auth-juniper.c b/auth-juniper.c
index acd9c77e..30ceb3ae 100644
--- a/auth-juniper.c
+++ b/auth-juniper.c
@@ -47,7 +47,6 @@ void oncp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
{
http_common_headers(vpninfo, buf);
- buf_append(buf, "Connection: close\r\n");
// buf_append(buf, "Content-Length: 256\r\n");
buf_append(buf, "NCP-Version: 3\r\n");
// buf_append(buf, "Accept-Encoding: gzip\r\n");
diff --git a/oncp.c b/oncp.c
index 945681cd..48ea5ff5 100644
--- a/oncp.c
+++ b/oncp.c
@@ -561,6 +561,11 @@ int oncp_connect(struct openconnect_info *vpninfo)
reqbuf = buf_alloc();
buf_append(reqbuf, "POST /dana/js?prot=1&svc=1 HTTP/1.1\r\n");
+ /* Seems unnecessary because we always ignore the response body,
+ and close the connection anyway, but retained in case any
+ server depends on it. (See comments on second negotiation
+ request below. */
+ buf_append(reqbuf, "Connection: close\r\n");
oncp_common_headers(vpninfo, reqbuf);
buf_append(reqbuf, "Content-Length: 256\r\n");
buf_append(reqbuf, "\r\n");
@@ -572,6 +577,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
goto out;
}
+ vpn_progress(vpninfo, PRG_TRACE, _("Sending oNCP negotiation request #1\n"));
ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
if (ret < 0)
goto out;
@@ -606,6 +612,13 @@ int oncp_connect(struct openconnect_info *vpninfo)
buf_truncate(reqbuf);
buf_append(reqbuf, "POST /dana/js?prot=1&svc=4 HTTP/1.1\r\n");
+ /* The TLS socket actually remains open for use by the oNCP
+ tunnel, but the "Connection: close" header is nevertheless
+ required here. It appears to signal to the server to stop
+ treating this as an HTTP connection and to start treating
+ it as an oNCP connection.
+ */
+ buf_append(reqbuf, "Connection: close\r\n");
oncp_common_headers(vpninfo, reqbuf);
buf_append(reqbuf, "Content-Length: 256\r\n");
buf_append(reqbuf, "\r\n");
@@ -616,6 +629,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
ret = buf_error(reqbuf);
goto out;
}
+ vpn_progress(vpninfo, PRG_TRACE, _("Sending oNCP negotiation request #2\n"));
ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
if (ret < 0)
goto out;
From 81cbc1f0f82d1c9d290f7b21be82e570e3812c2e Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Thu, 2 Aug 2018 12:10:45 -0700
Subject: [PATCH 130/131] Remove first oNCP negotiation request (only second is
necessary)
The current oNCP (Juniper) protocol support issues two separate
oNCP negotiation requests.
1) POST /dana/js?prot=1&svc=1 HTTP/1.1
2) POST /dana/js?prot=1&svc=4 HTTP/1.1
The first of these two requests appears to be totally unnecessary, based on
testing with two different Juniper gateways, one of which returns
"NCP-Version: 2" and one which returns "NCP-Version: 3" in response to the
oNCP negotiation requests.
Removing the first request saves an additional TLS negotiation (2-3
roundtrips with TLS 1.0) and allows the connection to start faster.
---
oncp.c | 52 ----------------------------------------------------
1 file changed, 52 deletions(-)
diff --git a/oncp.c b/oncp.c
index 48ea5ff5..675b9ae1 100644
--- a/oncp.c
+++ b/oncp.c
@@ -560,57 +560,6 @@ int oncp_connect(struct openconnect_info *vpninfo)
reqbuf = buf_alloc();
- buf_append(reqbuf, "POST /dana/js?prot=1&svc=1 HTTP/1.1\r\n");
- /* Seems unnecessary because we always ignore the response body,
- and close the connection anyway, but retained in case any
- server depends on it. (See comments on second negotiation
- request below. */
- buf_append(reqbuf, "Connection: close\r\n");
- oncp_common_headers(vpninfo, reqbuf);
- buf_append(reqbuf, "Content-Length: 256\r\n");
- buf_append(reqbuf, "\r\n");
-
- if (buf_error(reqbuf)) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Error creating oNCP negotiation request\n"));
- ret = buf_error(reqbuf);
- goto out;
- }
-
- vpn_progress(vpninfo, PRG_TRACE, _("Sending oNCP negotiation request #1\n"));
- ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
- if (ret < 0)
- goto out;
-
- /* The server is fairly weird. It sends Connection: close which would
- * indicate an HTTP 1.0-style body, but doesn't seem to actually close
- * the connection. So tell process_http_response() it was a CONNECT
- * request, since we don't care about the body anyway, and then close
- * the connection for ourselves. */
- ret = process_http_response(vpninfo, 1, NULL, reqbuf);
- openconnect_close_https(vpninfo, 0);
- if (ret < 0) {
- /* We'll already have complained about whatever offended us */
- goto out;
- }
- if (ret != 200) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Unexpected %d result from server\n"),
- ret);
- ret = -EINVAL;
- goto out;
- }
-
- /* Now the second request. We should reduce the duplication
- here but let's not overthink it for now; we should see what
- the authentication requests are going to look like, and make
- do_https_request() or a new helper function work for those
- too. */
- ret = openconnect_open_https(vpninfo);
- if (ret)
- goto out;
-
- buf_truncate(reqbuf);
buf_append(reqbuf, "POST /dana/js?prot=1&svc=4 HTTP/1.1\r\n");
/* The TLS socket actually remains open for use by the oNCP
tunnel, but the "Connection: close" header is nevertheless
@@ -629,7 +578,6 @@ int oncp_connect(struct openconnect_info *vpninfo)
ret = buf_error(reqbuf);
goto out;
}
- vpn_progress(vpninfo, PRG_TRACE, _("Sending oNCP negotiation request #2\n"));
ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
if (ret < 0)
goto out;
From 88b075bc3cb47797e1954de1c48108254881296c Mon Sep 17 00:00:00 2001
From: Daniel Lenski
Date: Fri, 3 Aug 2018 20:01:26 -0700
Subject: [PATCH 131/131] include computer name in the GP cookie
The GlobalProtect "cookie" is an overstuffed monstrosity, due to the
requirement to retain a few random, non-secret values in order to logout
successfully (see gpst_bye):
authcookie=d41d8cd98f00b204e9800998ecf8427e&portal=Gateway-X&user=user.name&domain=big-corp
Until now, I've avoided including the computer field in this cookie, on the assumption that it
can reproduced at any time using vpninfo->localname. However, it appears that this value can't always
be reproduced correctly when running under NetworkManager:
https://github.com/dlenski/network-manager-openconnect/issues/7
In order to be more robust, this patch therefore also includes the local hostname in the cookie:
authcookie=d41d8cd98f00b204e9800998ecf8427e&portal=Gateway-X&user=user.name&domain=big-corp&computer=hostname
---
auth-globalprotect.c | 4 ++--
gpst.c | 8 ++------
hipreport.sh | 12 ++++--------
3 files changed, 8 insertions(+), 16 deletions(-)
diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index ac32fe53..5cf64877 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -153,6 +153,7 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
append_opt(cookie, arg->opt, value);
free((void *)value);
}
+ append_opt(cookie, "computer", vpninfo->localname);
vpninfo->cookie = strdup(cookie->data);
return buf_free(cookie);
@@ -449,8 +450,7 @@ int gpst_bye(struct openconnect_info *vpninfo, const char *reason)
*
* Don't blame me. I didn't design this.
*/
- append_opt(request_body, "computer", vpninfo->localname);
- buf_append(request_body, "&%s", vpninfo->cookie);
+ buf_append(request_body, "%s", vpninfo->cookie);
if ((result = buf_error(request_body)))
goto out;
diff --git a/gpst.c b/gpst.c
index bdbc93ce..0170316a 100644
--- a/gpst.c
+++ b/gpst.c
@@ -783,9 +783,8 @@ static int build_csd_token(struct openconnect_info *vpninfo)
if (!vpninfo->csd_token)
return -ENOMEM;
- /* use localname and cookie (excluding volatile authcookie and preferred-ip) to build md5sum */
+ /* use cookie (excluding volatile authcookie and preferred-ip) to build md5sum */
buf = buf_alloc();
- append_opt(buf, "computer", vpninfo->localname);
filter_opts(buf, vpninfo->cookie, "authcookie,preferred-ip", 0);
if (buf_error(buf))
goto out;
@@ -809,9 +808,8 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
const char *method = "POST";
char *xml_buf=NULL, *orig_path;
- /* cookie gives us these fields: authcookie, portal, user, domain, and (maybe the unnecessary) preferred-ip */
+ /* cookie gives us these fields: authcookie, portal, user, domain, computer, and (maybe the unnecessary) preferred-ip */
buf_append(request_body, "client-role=global-protect-full&%s", vpninfo->cookie);
- append_opt(request_body, "computer", vpninfo->localname);
append_opt(request_body, "client-ip", vpninfo->ip_info.addr);
if (report) {
/* XML report contains many characters requiring URL-encoding (%xx) */
@@ -906,8 +904,6 @@ static int run_hip_script(struct openconnect_info *vpninfo)
hip_argv[i++] = openconnect_utf8_to_legacy(vpninfo, vpninfo->csd_wrapper);
hip_argv[i++] = (char *)"--cookie";
hip_argv[i++] = vpninfo->cookie;
- hip_argv[i++] = (char *)"--computer";
- hip_argv[i++] = vpninfo->localname;
hip_argv[i++] = (char *)"--client-ip";
hip_argv[i++] = (char *)vpninfo->ip_info.addr;
hip_argv[i++] = (char *)"--md5";
diff --git a/hipreport.sh b/hipreport.sh
index a25cf139..832aabc8 100755
--- a/hipreport.sh
+++ b/hipreport.sh
@@ -6,10 +6,7 @@
#
# --cookie: a URL-encoded string, as output by openconnect
# --authenticate --protocol=gp, which includes parameters
-# --from the /ssl-vpn/login.esp response
-#
-# --computer: local hostname, which can be overriden with
-# --openconnect local-hostname=HOSTNAME
+# from the /ssl-vpn/login.esp response
#
# --client-ip: IPv4 address allocated by the GlobalProtect VPN for
# this client (included in /ssl-vpn/getconfig.esp
@@ -22,26 +19,25 @@
# Read command line arguments into variables
COOKIE=
-COMPUTER=
IP=
MD5=
while [ "$1" ]; do
if [ "$1" = "--cookie" ]; then shift; COOKIE="$1"; fi
- if [ "$1" = "--computer" ]; then shift; COMPUTER="$1"; fi
if [ "$1" = "--client-ip" ]; then shift; IP="$1"; fi
if [ "$1" = "--md5" ]; then shift; MD5="$1"; fi
shift
done
-if [ -z "$COOKIE" -o -z "$COMPUTER" -o -z "$IP" -o -z "$MD5" ]; then
+if [ -z "$COOKIE" -o -z "$IP" -o -z "$MD5" ]; then
echo "Parameters --cookie, --computer, --client-ip, and --md5 are required" >&2
exit 1;
fi
-# Extract username and domain from cookie
+# Extract username and domain and computer from cookie
USER=$(echo "$COOKIE" | sed -rn 's/(.+&|^)user=([^&]+)(&.+|$)/\2/p')
DOMAIN=$(echo "$COOKIE" | sed -rn 's/(.+&|^)domain=([^&]+)(&.+|$)/\2/p')
+COMPUTER=$(echo "$COOKIE" | sed -rn 's/(.+&|^)computer=([^&]+)(&.+|$)/\2/p')
# Timestamp in the format expected by GlobalProtect server
NOW=$(date +'%m/%d/%Y %H:%M:%S')