]> www.infradead.org Git - users/dwmw2/openconnect.git/log
users/dwmw2/openconnect.git
4 years agoAvoid free of argv[] when ciphersuite_config provided
David Woodhouse [Tue, 13 Apr 2021 04:09:06 +0000 (05:09 +0100)]
Avoid free of argv[] when ciphersuite_config provided

This should use dup_config_arg() since it gets freed.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoFix memory leak in F5 config parsing
David Woodhouse [Tue, 13 Apr 2021 04:08:24 +0000 (05:08 +0100)]
Fix memory leak in F5 config parsing

Wouldn't this be easier in C++? Or maybe Rust?

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoFix CI artifact list for out-of-tree builds
David Woodhouse [Tue, 13 Apr 2021 08:20:47 +0000 (09:20 +0100)]
Fix CI artifact list for out-of-tree builds

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoSet Fortinet DPD interval from server's config
Daniel Lenski [Mon, 12 Apr 2021 03:23:11 +0000 (20:23 -0700)]
Set Fortinet DPD interval from server's config

The name of the tag implies that its purpose is DTLS-specific (<dtls-config heartbeat-interval="X">)
and that it requires the use of the DTLS heartbeat extension (https://tools.ietf.org/html/rfc6520).

However, PPP already contains natural analogues for keepalive (Discard-Request) and DPD (Echo-Request
and Echo-Reply), which appear to work just fine with Fortinet servers. We may as well use the server's
heartbeat/keepalive interval for a more generic, transport-agnostic DPD mechanism, since OpenConnect
and PPP already support it.

The official Fortinet client software for Windows/Mac appears to be very deficient at dead peer
detection, so this may represent a substantial improvement in functionality for some users.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFix --disable-ipv6 option
David Woodhouse [Sun, 11 Apr 2021 17:02:39 +0000 (18:02 +0100)]
Fix --disable-ipv6 option

Commit 7e2129f8a9 ("ensure that openconnect_disable_{dtls,ipv6} do
nothing if vpninfo has ever been connected") added a check to disallow
setting this... if it wasn't already set, OR the connection had
previously been established. Which seems wrong; I think that was
supposed to have been *AND*.

Not that I object very much to this not working, a whole quarter of a
century after RFC1883 was published. But I wanted to use it for testing
PPP negotiation, and it wasn't working.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoAdd 'proto' integer value to struct vpn_proto
David Woodhouse [Fri, 9 Apr 2021 12:09:11 +0000 (13:09 +0100)]
Add 'proto' integer value to struct vpn_proto

Despite making no mention of this in the commit message, commit
423449253 ("rename (resp_buf, form_buf) → (req_buf, resp_buf) in f5.c
and fortinet.c") added a 'flavor' field to a bunch of functions in
auth-html.c and passed it through from the protocol code to indicate
some protocol-specific quirks for form parsing.

Until then, we had mostly structured the code so that there weren't many
cases where 'core' code needed to behave differently depending on the
protocol. There was only one case, in fact, to handle the stupid Pulse
ESP address family bug. That one *used* to check which protocol was in
use by comparing proto->udp_send_probes with &oncp_esp_send_probes.

So, add an integer 'proto' field to struct vpn_proto so it can be
checked without a strcmp. Remove the now-redundant 'flavor' field from
all those functions in auth-html.c since it's now in the vpninfo, and
make the ESP code check that for NC|PULSE too instead of the trick of
checking the proto->udp_send_probes function. Which was kind of icky.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoUpdate main web page
David Woodhouse [Thu, 8 Apr 2021 22:52:10 +0000 (23:52 +0100)]
Update main web page

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoRevert "www: updated links to vpnc-script"
David Woodhouse [Thu, 8 Apr 2021 22:51:16 +0000 (23:51 +0100)]
Revert "www: updated links to vpnc-script"

This reverts commit 1db8a2f592472357d405e3c5cca3f61aa05f3a1a.

4 years agoReference F5 and Fortinet support in manual page
Daniel Lenski [Thu, 8 Apr 2021 22:46:00 +0000 (15:46 -0700)]
Reference F5 and Fortinet support in manual page

Also, update the link to the modern vpnc-script, which was already updated in the other docs in 1db8a2f592472357d405e3c5cca3f61aa05f3a1a.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFix link to Jailbreak
David Woodhouse [Thu, 8 Apr 2021 22:54:14 +0000 (23:54 +0100)]
Fix link to Jailbreak

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoUpdate README.md (developer-facing docs on GitLab)
Daniel Lenski [Thu, 8 Apr 2021 22:44:20 +0000 (15:44 -0700)]
Update README.md (developer-facing docs on GitLab)

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoMulti-protocol support documentation
Daniel Lenski [Thu, 8 Apr 2021 21:32:32 +0000 (14:32 -0700)]
Multi-protocol support documentation

Mention F5 and Fortinet on the index page, explain the multi-protocol design
philosophy a bit more, and add a page with a concise list of the supported
protocols.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoExpand F5 and Fortinet documentation
Daniel Lenski [Thu, 8 Apr 2021 21:35:08 +0000 (14:35 -0700)]
Expand F5 and Fortinet documentation

Explain currently-supported authentication modes, and request feedback on additional modes.

Explain Fortinet's misfeature/design flaw, which prevents it from automatically reconnecting after a dropped or roamed connection, without a new authentication. Request feedback if anyone has acceess to a Fortinet VPN that *doesn't* have this flaw.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoAdd note-to-self comments about DTLS for F5/Fortinet
Daniel Lenski [Thu, 11 Feb 2021 17:08:55 +0000 (09:08 -0800)]
Add note-to-self comments about DTLS for F5/Fortinet

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoMerge branch 'juniper-auth-tests' of gitlab.com:openconnect/openconnect
David Woodhouse [Wed, 7 Apr 2021 16:11:40 +0000 (17:11 +0100)]
Merge branch 'juniper-auth-tests' of gitlab.com:openconnect/openconnect

4 years agoFix Juniper auth tests for out-of-tree builds
David Woodhouse [Wed, 7 Apr 2021 16:02:59 +0000 (17:02 +0100)]
Fix Juniper auth tests for out-of-tree builds

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoUse out-of-tree builds in CI
David Woodhouse [Wed, 7 Apr 2021 14:35:45 +0000 (15:35 +0100)]
Use out-of-tree builds in CI

Let's try to stop breaking them so often...

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoFix test paths for out-of-tree builds
David Woodhouse [Wed, 7 Apr 2021 14:35:20 +0000 (15:35 +0100)]
Fix test paths for out-of-tree builds

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoFix key filename mangling in auth-certificate test
David Woodhouse [Wed, 7 Apr 2021 15:57:18 +0000 (16:57 +0100)]
Fix key filename mangling in auth-certificate test

We want to strip the -key-xxx.yyy suffix from the key filename and
replace it with -cert.pem to find the corresponding certificate.

The original implementation was stripping all from the first - but
that fails when ${srcdir} contains a hyphen, so fix it up to be
more precise.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoUse oc_text_buf for internal_get_url()
Daniel Lenski [Mon, 5 Apr 2021 15:37:00 +0000 (08:37 -0700)]
Use oc_text_buf for internal_get_url()

Commit c8ca180f ("factor out internal_get_url function") consolidated
two pieces of code which reconstruct the URL from its constituent parts
into a single internal_get_url() function.

Both the original versions used oc_text_buf() and built up the URL
string in a simple and readable fashion. The new internal_get_url()
function used asprintf with "%s%s%s" and ternary operators ?"/":"" in an
apparent attempt to win an obfuscated C contest.

Unsurprisingly, the first attempt was buggy; this was subsequently fixed
in commit f78f0eccc ("bugfix internal_get_url") but the horridness
remained.

In addition, the original two versions had slightly different behaviour —
the one in auth-juniper.c would *always* append a trailing / at the end
of the URL string even if vpninfo->urlpath was NULL, while the one in
AnyConnect's auth.c would only do so if it was non-NULL (including when
it's set to "").

As well as switching back to using oc_text_buf to build up the string so
that we can read the code without our eyes bleeding, fix it to always
add the trailing / even when vpninfo->urlpath is NULL.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoMerge branch 'juniper-auth-tests' into 'juniper-auth-tests'
Daniel Lenski [Mon, 5 Apr 2021 16:40:22 +0000 (16:40 +0000)]
Merge branch 'juniper-auth-tests' into 'juniper-auth-tests'

fix: add missing licence to fake-tncc.py.

See merge request openconnect/openconnect!181

4 years agofix: add missing licence to fake-tncc.py.
Joachim Kuebart [Mon, 5 Apr 2021 16:25:33 +0000 (18:25 +0200)]
fix: add missing licence to fake-tncc.py.

Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>
4 years agofix: generalise check for user name field
Joachim Kuebart [Sun, 4 Apr 2021 20:11:10 +0000 (22:11 +0200)]
fix: generalise check for user name field

Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>
4 years agofix: fix Juniper Azure SSO login
Joachim Kuebart [Sat, 3 Apr 2021 20:44:44 +0000 (22:44 +0200)]
fix: fix Juniper Azure SSO login

Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>
4 years agoadd juniper-sso-auth test: add unit test for Azure MFA SSO
Joachim Kuebart [Fri, 2 Apr 2021 21:16:10 +0000 (23:16 +0200)]
add juniper-sso-auth test: add unit test for Azure MFA SSO

Adds a new fake-juniper-sso-server.py, alongside fake-juniper-server.py
(clearer this way, since they share very little in the way of auth handling).

Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>
4 years agomake --authgroup fill EITHER the role and/or the realm for Juniper
Daniel Lenski [Fri, 2 Apr 2021 09:26:21 +0000 (02:26 -0700)]
make --authgroup fill EITHER the role and/or the realm for Juniper

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd test path including frmSelectRoles
Daniel Lenski [Fri, 2 Apr 2021 07:57:14 +0000 (00:57 -0700)]
add test path including frmSelectRoles

frmSelectRoles is a "form" that sort of acts like a realm dropdown except that…

(1) It comes AFTER the credentials have been submitted (¯\_(ツ)_/¯)
(2) It doesn't actually contain any form fields. It only contains links to
    a small number of role choices. It then redirects to 'GET login.cgi'.
    Inane, but apparently used in the real world. See examples at:
    https://gitlab.gnome.org/GNOME/NetworkManager-openconnect/-/issues/30#note_988366

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd fake-juniper-server.py and tests/juniper-auth
Daniel Lenski [Wed, 31 Mar 2021 08:08:01 +0000 (01:08 -0700)]
add fake-juniper-server.py and tests/juniper-auth

Flask-based tests of Juniper authentication forms handling. Currently tested cases are:

- frmLogin with username/password
- frmLogin with username/password/authgroup
- frmLogin with username/password/token-as-2nd-password
- frmLogin with username/password ⇒ frmTotpToken
- frmLogin with username/password → frmDefender → frmConfirmation
- frmLogin with username/password → frmNextToken

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agobugfix internal_get_url
Daniel Lenski [Thu, 1 Apr 2021 20:09:58 +0000 (13:09 -0700)]
bugfix internal_get_url

Don't want (null) jammed into our URLs. I broke this in c8ca180f02a569e6692c699eb8aa70df976d49a5.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFix stray close paren in changelog
David Woodhouse [Wed, 31 Mar 2021 15:19:33 +0000 (16:19 +0100)]
Fix stray close paren in changelog

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoFix output redirection under Windows
David Woodhouse [Wed, 31 Mar 2021 13:35:33 +0000 (14:35 +0100)]
Fix output redirection under Windows

If WriteConsoleW() fails, convert to the *console* code page and write to
stdout/stderr (as appropriate) with fwrite().

Mostly researched by bers in !177.

Fixes: #229
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agofix openconnect_disable_dtls / --no-dtls
Daniel Lenski [Wed, 31 Mar 2021 02:43:08 +0000 (19:43 -0700)]
fix openconnect_disable_dtls / --no-dtls

The default/startup value of dtls_state is DTLS_NOSECRET, not DTLS_DISABLED.
I broke this in !49 / 7e2129f8a906f3858dc3792e1519332bf26ced99

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoAdd Wintun support
David Woodhouse [Sat, 27 Mar 2021 16:17:57 +0000 (16:17 +0000)]
Add Wintun support

Refactor the device discovery a little bit to accommodate it. We need
to scan the registry as we did for TAP-Windows anyway, in order to
find the TUNIDX that vpnc-script-win.js will use to configure routes.

So run through the scan as before, but *if* nothing is found and the
user specified an ifname, attempt to create a Wintun device with that
name. Then scan again and presumably we'll find it this time.

This should hopefully make it relatively harmless to existing setups
using TAP-Windows.

There's lots of memcpy here as Wintun *really* wants us to use its pool.
More thought required for that one, as it can't even handle stripping
packet headers so even if we decrypt directly into its buffer that
wouldn't be enough.

The configuration is also fairly horrid, as vpnc-script-win.js seems
to depend on the Legacy IP address being set on the interface before
it will set up the routes. Which of course assumes that there *is*
Legacy IP at all, and it isn't an IPv6-only tunnel.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoImport translations from GNOME
David Woodhouse [Tue, 30 Mar 2021 10:38:29 +0000 (11:38 +0100)]
Import translations from GNOME

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoResync translations with sources
David Woodhouse [Tue, 30 Mar 2021 10:37:00 +0000 (11:37 +0100)]
Resync translations with sources

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoAdd basic docs for (or at least admit the existence of) f5/fortinet
David Woodhouse [Tue, 30 Mar 2021 09:49:45 +0000 (10:49 +0100)]
Add basic docs for (or at least admit the existence of) f5/fortinet

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoMerge branch 'master' of gitlab.com:openconnect/openconnect
David Woodhouse [Tue, 30 Mar 2021 09:18:08 +0000 (10:18 +0100)]
Merge branch 'master' of gitlab.com:openconnect/openconnect

4 years agoMerge branch 'add_f5_and_fortinet' of gitlab.com:openconnect/openconnect
David Woodhouse [Tue, 30 Mar 2021 08:57:33 +0000 (09:57 +0100)]
Merge branch 'add_f5_and_fortinet' of gitlab.com:openconnect/openconnect

Add back some previously unused variables, remove another, fix more build
warnings.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agomain.c CLI: replace confusingly-used `FILE *pid_fp` with `int wrote_pid`
Daniel Lenski [Tue, 30 Mar 2021 00:28:31 +0000 (17:28 -0700)]
main.c CLI: replace confusingly-used `FILE *pid_fp` with `int wrote_pid`

This was last modified in 557ac6cfa, although the use of the closed `FILE *fp`
(to signal the need to delete the pidfile) long pre-dates that commit.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agobugfix !165 Juniper forms handling
Daniel Lenski [Mon, 29 Mar 2021 23:59:08 +0000 (16:59 -0700)]
bugfix !165 Juniper forms handling

I missed a small piece of my original "fix for forms with 'id' but no 'name'" (this one:
https://gitlab.com/openconnect/openconnect/-/commit/c8a6ee94180a09339eafefe0a2d889e7aa508e56#5503a3e92468be6db7c76e16b82bb5f3e9b14131_260_259)
in rebasing the ppp_core branch to merge cleanly with the changes from !171.

Caused this crash: https://gitlab.com/openconnect/openconnect/-/merge_requests/169#note_540411103

TODO: add Flask-based tests of Juniper auth to verify Juniper form handling.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFix build warnings
David Woodhouse [Mon, 29 Mar 2021 22:32:16 +0000 (23:32 +0100)]
Fix build warnings

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoMerge branch 'ppp_core' of gitlab.com:openconnect/openconnect
David Woodhouse [Mon, 29 Mar 2021 22:16:49 +0000 (23:16 +0100)]
Merge branch 'ppp_core' of gitlab.com:openconnect/openconnect

4 years agoMerge branch 'pre_PPP_cross_protocol_bits' of gitlab.com:openconnect/openconnect
David Woodhouse [Mon, 29 Mar 2021 21:53:07 +0000 (22:53 +0100)]
Merge branch 'pre_PPP_cross_protocol_bits' of gitlab.com:openconnect/openconnect

4 years agoFix installer deps
David Woodhouse [Mon, 29 Mar 2021 16:44:21 +0000 (17:44 +0100)]
Fix installer deps

Just including .openconnect.exe.d from the main Makefile means it always
has to be up to date. Which means we always have to *build* openconnect,
even if it was just invoked for 'make clean'. That's bogus.

So shift the DLL dependency tracking out into its own Makefile, to be
invoked recursively. Much as I hate recursive make in the general case,
this is one of the few cases where it makes sense.

The automatic dependencies weren't working very well anyway, as it was
happy to 'discover' openconnect.exe and libopenconnect-5.dll in the MinGW
sysroot instead of using the locally built ones, *and* libtool messes up
the filenames so you can't just depend on .libs/openconnect.exe anyway.

Fix up $(DISTCLEANFILES) to be a bit more complete while we're at it.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoInclude wintun dll in installer
David Woodhouse [Mon, 29 Mar 2021 10:19:33 +0000 (11:19 +0100)]
Include wintun dll in installer

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoFix handling of downloaded files
David Woodhouse [Mon, 29 Mar 2021 16:09:32 +0000 (17:09 +0100)]
Fix handling of downloaded files

We want the MinGW package builds to have the downloads provided in advance
as part of the source RPM, instead of requiring network access and fetching
them once for each of the win32 and win64 builds.

So let make find the file in its VPATH and then use the full pathname that
it puts into $< for the recipe. And use that recipe to validate the hash
of the file too.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoTurn off -Wdeclaration-after-statement and allow C99
David Woodhouse [Mon, 29 Mar 2021 10:17:21 +0000 (11:17 +0100)]
Turn off -Wdeclaration-after-statement and allow C99

I think this far into the 21st century we can allow declarations to be
in the middle of code blocks. Even MSVC supports that, even if it doesn't
do other parts of C99 like named struct initialisers.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
4 years agoflask-based tests: give up on CentOS7
Daniel Lenski [Mon, 29 Mar 2021 03:41:59 +0000 (20:41 -0700)]
flask-based tests: give up on CentOS7

For reasons that are not clear, OpenConnect fails to handshake a TLS connection
to Python 3.6 and Flask (from CentOS 7 EPEL), and I don't want to install
a 7-year-old distribution on a VM just to figure out why.

See https://gitlab.com/openconnect/openconnect/-/jobs/1135245618#L520 for
verification of the issue, and 9df05119a30dc3405ab56edbcab2576f46cac799
for a possibly-related issue with even older CentOS 6.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoI do believe a changelog addition is in order
Daniel Lenski [Mon, 29 Mar 2021 04:10:26 +0000 (21:10 -0700)]
I do believe a changelog addition is in order

This one is so big it gets TWO LINES :-)

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agodon't require F5 forms other than first one to have any particular name/ID
Daniel Lenski [Sun, 14 Mar 2021 18:38:38 +0000 (11:38 -0700)]
don't require F5 forms other than first one to have any particular name/ID

This allow-list of known forms is a relic of the HTML-form-parsing code
which was originally written for the Juniper protocol, and requires a bunch
of special-casing.  I don't think it's particularly relevant for F5 forms.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoF5: factor out plain_auth_form()
Daniel Lenski [Sun, 14 Mar 2021 18:37:17 +0000 (11:37 -0700)]
F5: factor out plain_auth_form()

Generates a plain auth form (username+password) in the absence of an HTML form.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agotest multi-domain logins in F5 tests
Daniel Lenski [Tue, 23 Feb 2021 04:56:39 +0000 (20:56 -0800)]
test multi-domain logins in F5 tests

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agorename (resp_buf, form_buf) → (req_buf, resp_buf) in f5.c and fortinet.c
Daniel Lenski [Tue, 23 Feb 2021 01:28:05 +0000 (17:28 -0800)]
rename (resp_buf, form_buf) → (req_buf, resp_buf) in f5.c and fortinet.c

The current names were borrowed from Juniper source, and are too confusing.

The newly-renamed 'req_buf' now contains data that we send to the servers,
and 'resp_buf' contains data that the server sends back to us.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoturns out F5 can have an authgroup dropdown
Daniel Lenski [Mon, 22 Feb 2021 09:22:46 +0000 (01:22 -0800)]
turns out F5 can have an authgroup dropdown

See https://remote.autoliv.com for an example. TODO: parse it and add it to the form.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: fix token code generation
Daniel Lenski [Mon, 22 Feb 2021 08:42:21 +0000 (00:42 -0800)]
Fortinet: fix token code generation

And make fake server require this field to be non-empty, in order to test it.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: fix crash caused by absence of redirect
Daniel Lenski [Mon, 22 Feb 2021 08:42:21 +0000 (00:42 -0800)]
Fortinet: fix crash caused by absence of redirect

And make fake server emulate this behavior to test it.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agomake F5 and Fortinet tests go through config-pulling (up to the point of tunnel conne...
Daniel Lenski [Mon, 22 Feb 2021 02:44:22 +0000 (18:44 -0800)]
make F5 and Fortinet tests go through config-pulling (up to the point of tunnel connection), rather than stopping after authentication

The fake servers don't actually implement the tunnel, but they do implement
the pre-tunnel configuration endpoints, and then simulate a "cookie rejected"
response upon tunnel connection.

OpenConnect distinguishes “cookie rejected” errors via an exit status of 2,
whereas any other failure results in an exit status of 1.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd auth-f5 tests
Daniel Lenski [Sun, 21 Feb 2021 23:02:44 +0000 (15:02 -0800)]
add auth-f5 tests

This tests OpenConnect's ability to authenticate with a (fake) F5
server, using username+password (the only option that OpenConnect
currently supports).

The fake F5 authentication server requires python3 and Flask.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd auth-fortinet tests
Daniel Lenski [Sun, 21 Feb 2021 23:02:44 +0000 (15:02 -0800)]
add auth-fortinet tests

This tests OpenConnect's ability to authenticate with a (fake) Fortinet
server, using all of the options that OpenConnect currently supports
(username+password, username+password+token, non-default realm).

The fake Fortinet authentication server requires Python 3.6 and Flask.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agocleanup and clarify comments about tests that are XFAIL in CI
Daniel Lenski [Mon, 29 Mar 2021 03:33:29 +0000 (20:33 -0700)]
cleanup and clarify comments about tests that are XFAIL in CI

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd openconnect__strchrnul function to compat.c
Daniel Lenski [Sat, 20 Feb 2021 17:39:07 +0000 (09:39 -0800)]
add openconnect__strchrnul function to compat.c

GNU strchrnul() is trivial to implement, and makes a bunch of string parsing
functions simpler and less error-prone.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet's realm parameter comes from the URL-path
Daniel Lenski [Fri, 19 Feb 2021 05:14:03 +0000 (21:14 -0800)]
Fortinet's realm parameter comes from the URL-path

See an example at https://github.com/adrienverge/openfortivpn/issues/827

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: parse <split-dns> domains and DNS servers from config
Daniel Lenski [Fri, 19 Feb 2021 04:14:00 +0000 (20:14 -0800)]
Fortinet: parse <split-dns> domains and DNS servers from config

Chimped config containing these settings from
https://github.com/adrienverge/openfortivpn/issues/824#issuecomment-764641406.

This doesn't actually *do* anything with the settings yet.

See https://github.com/dlenski/openconnect/issues/151 and
https://gitlab.com/openconnect/openconnect/-/merge_requests/132 for
discussion about split-DNS.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoattempt to implement Fortinet challenge-based 2FA (ping #225)
Daniel Lenski [Thu, 18 Feb 2021 03:27:10 +0000 (19:27 -0800)]
attempt to implement Fortinet challenge-based 2FA (ping #225)

2FA involves reading a bunch of values from the initial response and
parroting them back, along with changing the 'credential' field to 'code'.

This is based on Openfortivpn's implementation
(https://github.com/adrienverge/openfortivpn/blob/master/src/http.c#L711-L754),
and has been tested for basic correctness against a toy HTTPS server that
gives responses with the right format.

Still to do:

- Another one-time password mode: https://github.com/adrienverge/openfortivpn/blob/master/src/http.c#L672-L679, https://github.com/adrienverge/openfortivpn/commit/61dd4fcbbfe1dd89b95081e7d5f5c3e933d7897a
- There's a mobile-app-based "push" mode: https://github.com/adrienverge/openfortivpn/commit/2f16d964560d9b00acbf7bfc7131a0ac40c688f2

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agosimpler fortinet_obtain_cookie()
Daniel Lenski [Thu, 18 Feb 2021 03:23:36 +0000 (19:23 -0800)]
simpler fortinet_obtain_cookie()

Just build a static form, containing two fields ('username', 'credential')
like GP and F5.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoofficial Forticlient doesn't 'GET /remote/index', so let's not
Daniel Lenski [Wed, 10 Feb 2021 05:41:18 +0000 (21:41 -0800)]
official Forticlient doesn't 'GET /remote/index', so let's not

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoimplement fortinet_obtain_cookie
Daniel Lenski [Mon, 8 Feb 2021 01:49:10 +0000 (17:49 -0800)]
implement fortinet_obtain_cookie

Fortinet uses HTML-based login forms, similar to Juniper's, resulting in an SVPNCOOKIE.

Believe it or not, they're even more badly designed than Juniper's forms:

1. Inconsistent use of HTTP redirects ('Location' header) vs. Javascript-only redirects
2. Significant <input> fields that aren't actually nested within the <form> tag.
3. Misleading HTTP 405 status ("Method Not Allowed") after incorrect credentials are entered.
4. No apparent way to determine the allowed values for the realm field.
   (Though various articles floating around suggest it comes from the URL-path entry point,
   from which I assume it's triggered by JavaScript.)

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: assume default route if no split routes received
Daniel Lenski [Fri, 5 Feb 2021 02:56:05 +0000 (18:56 -0800)]
Fortinet: assume default route if no split routes received

That's what openfortivpn does, too: https://github.com/adrienverge/openfortivpn/blob/0fce4ba83260ce49b4d92b5eacae3acc3891ef91/src/ipv4.c#L1005-L1009

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: remove unused function
Daniel Lenski [Fri, 5 Feb 2021 02:55:04 +0000 (18:55 -0800)]
Fortinet: remove unused function

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: implement auth_expiration
Daniel Lenski [Fri, 5 Feb 2021 01:23:32 +0000 (17:23 -0800)]
Fortinet: implement auth_expiration

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: note divergences of header values from openfortivpn, and absence of DTLS...
Daniel Lenski [Fri, 5 Feb 2021 00:24:50 +0000 (16:24 -0800)]
Fortinet: note divergences of header values from openfortivpn, and absence of DTLS support

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: server rejects asyncmap and header compression options
Daniel Lenski [Thu, 4 Feb 2021 19:31:20 +0000 (11:31 -0800)]
Fortinet: server rejects asyncmap and header compression options

This appears to be a "feature" of all Fortinet servers, not just the one I have
access to. Openfortivpn calls pppd with the 'noaccomp nopfcomp default-asyncmap'
options: https://github.com/adrienverge/openfortivpn/blob/ba44ce1/src/tunnel.c#L233-L245

We should avoid offering these options to save an unnecessary round-trip in the
LCP stage of PPP configuration.

Don't blame me. I didn't design this.

For that matter, we don't need to include the asyncmap option with *any*
encapsulation that doesn't use HDLC.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet does not use HDLC framing
Daniel Lenski [Thu, 4 Feb 2021 20:38:49 +0000 (12:38 -0800)]
Fortinet does not use HDLC framing

It uses non-HDLC framing with a 6-byte header.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: socket switches abruptly from HTTP request to encapsulated PPP, with no...
Daniel Lenski [Thu, 4 Feb 2021 23:38:20 +0000 (15:38 -0800)]
Fortinet: socket switches abruptly from HTTP request to encapsulated PPP, with no HTTP-ish response

However, in the case of *failure* to start the PPP tunnel, an HTTP response
may be sent, and we'll need to detect that in the PPP mainloop.

Don't blame me. I didn't design this.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: explain to the user if connecting to an ancient server that doesn't support...
Daniel Lenski [Thu, 4 Feb 2021 01:58:00 +0000 (17:58 -0800)]
Fortinet: explain to the user if connecting to an ancient server that doesn't support XML config

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: ignore 401/403 response to remote/index request
Daniel Lenski [Wed, 3 Feb 2021 07:29:14 +0000 (23:29 -0800)]
Fortinet: ignore 401/403 response to remote/index request

Openfortivpn ignores the HTTP status code entirely in this request, and
others.  Testing shows that a 403 response here is routine and can be
ignored.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFortinet: set HTTP user-agent to 'Mozilla/5.0 SV1' as openfortivpn does
Daniel Lenski [Wed, 3 Feb 2021 06:57:52 +0000 (22:57 -0800)]
Fortinet: set HTTP user-agent to 'Mozilla/5.0 SV1' as openfortivpn does

This appears to suppress the need for 'host check' (presumably a
Trojan similar to those of other protocols) on some, if not all,
Fortinet servers.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoparse real Fortinet config
Daniel Lenski [Thu, 14 May 2020 03:41:00 +0000 (20:41 -0700)]
parse real Fortinet config

Based on these two real examples (https://forum.fortinet.com/tm.aspx?m=170415 and https://forum.fortinet.com/tm.aspx?m=105123).

Tested with sample XML in comments. Clean up a bunch of memory/state errors in PPP code (caught by static analyzer)

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agohard-code browser UA into test-fortinet-login.py
Daniel Lenski [Sun, 17 May 2020 23:37:33 +0000 (16:37 -0700)]
hard-code browser UA into test-fortinet-login.py

See https://gitlab.com/openconnect/openconnect/-/issues/142#note_343854311

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd test-fortinet-login.py
Daniel Lenski [Wed, 13 May 2020 21:29:41 +0000 (14:29 -0700)]
add test-fortinet-login.py

Often easier to prototype HTTPS-based authentication flows in Python, since
they're so fiddly and arbitary.  So I copied `test-f5-login.py` to
`test-fortinet-login.py`.  Currently only handles basic
username-and-password auth, no 2FA:

```
usage: test-fortinet-login.py [-h] [-v] [-u USERNAME] [-p PASSWORD] [-r REALM]
                              [-c CERT] [--key KEY] [--no-verify]
                              endpoint [extra [extra ...]]

positional arguments:
  endpoint              Fortinet server (or complete URL, e.g.
                        https://forti.vpn.com/remote/login)
  extra                 Extra field to pass to include in the login query
                        string (e.g. "foo=bar")

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose
  --no-verify           Ignore invalid server certificate

Login credentials:
  -u USERNAME, --username USERNAME
                        Username (will prompt if unspecified)
  -p PASSWORD, --password PASSWORD
                        Password (will prompt if unspecified)
  -r REALM, --realm REALM
                        Realm (empty if unspecified)
  -c CERT, --cert CERT  PEM file containing client certificate (and optionally
                        private key)
  --key KEY             PEM file containing client private key (if not
                        included in same file as certificate)
```

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoAdd basic attempt at Fortinet support
David Woodhouse [Wed, 13 May 2020 13:58:56 +0000 (14:58 +0100)]
Add basic attempt at Fortinet support

Squashed Fortinet-specific code from 64eb98f068ceac0985d4356890c69b6a0bac0bdf..61edd9e6284aad30a5eb43ec84ff72171d46ca5f

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoF5: pause-and-reconnect doesn't preserve IP addresses if we PPP-terminate
Daniel Lenski [Mon, 8 Feb 2021 22:41:05 +0000 (14:41 -0800)]
F5: pause-and-reconnect doesn't preserve IP addresses if we PPP-terminate

Add a no_terminate_on_pause flag to handle this.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoF5: fix old options leak on reconnect
Daniel Lenski [Mon, 8 Feb 2021 21:38:40 +0000 (13:38 -0800)]
F5: fix old options leak on reconnect

Need to save in cstp_options, but also strdup() because
process_http_response() will clobber them if we don't

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoF5: one of the GET requests in login flow appears unnecessary
Daniel Lenski [Mon, 8 Feb 2021 21:28:28 +0000 (13:28 -0800)]
F5: one of the GET requests in login flow appears unnecessary

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoF5: implement f5_obtain_cookie
Daniel Lenski [Mon, 8 Feb 2021 20:43:07 +0000 (12:43 -0800)]
F5: implement f5_obtain_cookie

Like Fortinet, F5's authentication interface is very Javascript-heavy.
Unlike with Fortinet, I didn't even both to try to parse and "follow" HTML forms.

For now, we just create a static form (with username and password fields),
ask the user to fill it out, submit it, and attempt to detect successful login
by a length-0 response including F5_ST and MRHSession cookies.

The F5_ST cookie appears to be a reliable(?) indicator of successful login.
It's a "session timeout" cookie (https://support.f5.com/csp/article/K15387),
which looks like '1z1z1z1612808487z604800'. The 4th field appears to be the
Unix epoch timestamp of session activation, and the 5th appears to be the
duration in seconds until it expires.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd test-f5-login.py script
Daniel Lenski [Wed, 6 May 2020 20:01:28 +0000 (13:01 -0700)]
add test-f5-login.py script

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agouse check_address_sanity for F5 too
Daniel Lenski [Wed, 20 May 2020 01:45:51 +0000 (18:45 -0700)]
use check_address_sanity for F5 too

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoFirst attempt at F5 support
David Woodhouse [Wed, 6 May 2020 11:26:45 +0000 (12:26 +0100)]
First attempt at F5 support

F5-specific code squashed from b072adc530ce74b1141e0a529d02fecb916c631c..08aa6af9e9bd93a71200631d38c84a6ac994a73e

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoppp-over-tls tests: fix PPP-over-IPv6 tests on Ubuntu
Daniel Lenski [Mon, 29 Mar 2021 02:55:18 +0000 (19:55 -0700)]
ppp-over-tls tests: fix PPP-over-IPv6 tests on Ubuntu

For reasons that are unclear, but probably also unimportant, IPv6 is disabled by default on this CI
image (verified in https://gitlab.com/openconnect/openconnect/-/jobs/1135199323#L335), and this will
cause PPP tests using IPv6 to fail.

Explicitly enabling IPv6 with sysctl resolves this.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoJuniper: bugfix handling of loginForm.VerificationCode
Daniel Lenski [Mon, 29 Mar 2021 02:00:52 +0000 (19:00 -0700)]
Juniper: bugfix handling of loginForm.VerificationCode

Need to whitelist this form by 'auth_id' in oncp_can_gen_tokencode. Missed in f582b233afc688cd7090aa01ee1a0af61597bef1.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoppp-over-tls tests: give up on CentOS 6
Daniel Lenski [Fri, 26 Feb 2021 02:39:45 +0000 (18:39 -0800)]
ppp-over-tls tests: give up on CentOS 6

We should be able to --enable-ppp-tests on CentOS 6, but they simply aren't working.

For reasons that are not clear, OpenConnect fails to handshake a TLS
connection to socat 1.7.2 (from CentOS 6 EPEL), and I don't want to install
an 11-year-old distribution on a VM just to figure out why.

So… no pppd-based tests for you, CentOS 6. 😡

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agofix <select>/<option> parsing bug
Daniel Lenski [Tue, 23 Feb 2021 04:46:15 +0000 (20:46 -0800)]
fix <select>/<option> parsing bug

The Juniper form-handling code was setting <select>/<option> labels
identically to their values.

Presumably, this was never caught before because they never actually differ
in real Juniper login forms? (but they do in F5 forms)

That is, a Juniper <option> field always looks like…

    <select name="realm">
      <option value="Something">Something</option>
      <option value="Another">Another</option>
    </select>

… and never like this:

    <select name="realm">
      <option value="group1">Something</option>
      <option value="group2">Another</option>
    </select>

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoppp-over-tls tests: more comments about how hard it is to use pppd as a test fixture
Daniel Lenski [Fri, 26 Feb 2021 01:53:38 +0000 (17:53 -0800)]
ppp-over-tls tests: more comments about how hard it is to use pppd as a test fixture

If anyone else ever has to touch this, they'll hopefully appreciate these.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoadd openconnect__strchrnul function to compat.c
Daniel Lenski [Sat, 20 Feb 2021 17:39:07 +0000 (09:39 -0800)]
add openconnect__strchrnul function to compat.c

GNU strchrnul() is trivial to implement, and makes a bunch of string parsing
functions simpler and less error-prone.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoppp-over-tls tests: /etc/ppp script permissions problems
Daniel Lenski [Fri, 26 Feb 2021 01:53:38 +0000 (17:53 -0800)]
ppp-over-tls tests: /etc/ppp script permissions problems

Some CI is still failing because pppd can't successfully execute the
/etc/ppp/* scripts after configuring the interfaces. Let's just move these
out of the way so that pppd won't try to execute them.

Side rant: pppd is the most appallingly bad program in terms of separation
of concerns.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoallegedly universal MTU calculator: use for GPST and PPP
Daniel Lenski [Sat, 16 May 2020 22:51:46 +0000 (15:51 -0700)]
allegedly universal MTU calculator: use for GPST and PPP

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoppp-over-tls test: figured out how to make socat invoke pppd
Daniel Lenski [Fri, 26 Feb 2021 00:54:47 +0000 (16:54 -0800)]
ppp-over-tls test: figured out how to make socat invoke pppd

This should hopefully allow these tests to run without timing race
conditions on all CI platforms.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agofactor out internal_split_cookies from auth-juniper.c
Daniel Lenski [Mon, 8 Feb 2021 19:38:19 +0000 (11:38 -0800)]
factor out internal_split_cookies from auth-juniper.c

This is useful for other protocols that use HTTP cookies for authentication, and may
need a way to handoff >1 cookie from the authentication phase to the connection phase.

Improve it slightly by allowing it to set a "default" HTTP cookie if the
authcookie string doesn't contain '=', since most protocols really only NEED
one cookie for the connection phase to work.

This allows shortcuts (like `openconnect --protocol=nc -C 'foobar'` → 'Cookie: DSID=foobar'
or `openconnect --protocol=fortinet -C 'ABCD123456=='` → 'Cookie: SVPNCOOKIE=ABCD123456==') without limiting
the ability to store multiple cookies if/when useful.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agoppp-over-tls tests: try to keep CentOS 6 CI working, and improve flaky startup of...
Daniel Lenski [Wed, 24 Feb 2021 05:03:47 +0000 (21:03 -0800)]
ppp-over-tls tests: try to keep CentOS 6 CI working, and improve flaky startup of pppd

Even with EPEL, CentOS has an old version of socat which doesn't support the
'rawer' option, so let's use the older 'raw,echo=0' combination to keep it
limping along.

More carefully try to verify that socat and pppd start up and connect to each other:

- Wait for socat to create PTY in 1-second increments, and keep going until PTY
  actually exists (up to 15 seconds).
- Wait for ppp to connect to PTY in 1-second increments, and keep going until pppd
  creates a "UUCP-style lockfile" for the PTY.
- Log how long it takes for the above process to complete (socat and pppd combined
  startup) in the test output.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
4 years agosplit htmlnode_next and htmlnode_dive
Daniel Lenski [Mon, 8 Feb 2021 01:47:08 +0000 (17:47 -0800)]
split htmlnode_next and htmlnode_dive

htmlnode_next(): try ->next, before ->parent
htmlnode_dive(): try children, before ->next, before ->parent

Signed-off-by: Daniel Lenski <dlenski@gmail.com>