From bbfbc1a638b6f63fc5d6ae487bcc1754842bf0e2 Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Tue, 29 Nov 2022 10:58:48 +0100 Subject: [PATCH 1/9] Add saml login with webkit --- Makefile.am | 8 +- configure.ac | 2 + src/config.c | 14 ++++ src/config.h | 14 ++-- src/main.c | 22 +++--- src/saml.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/saml.h | 6 ++ src/tunnel.c | 22 ++++++ 8 files changed, 284 insertions(+), 18 deletions(-) create mode 100644 src/saml.c create mode 100644 src/saml.h diff --git a/Makefile.am b/Makefile.am index 41fc6e6d..d3f194a0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,15 +7,17 @@ openfortivpn_SOURCES = src/config.c src/config.h src/hdlc.c src/hdlc.h \ src/tunnel.h src/main.c src/ssl.h src/xml.c \ src/xml.h src/userinput.c src/userinput.h \ src/openssl_hostname_validation.c \ - src/openssl_hostname_validation.h + src/openssl_hostname_validation.h \ + src/saml.c src/saml.h openfortivpn_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" \ -DPPP_PATH=\"@PPP_PATH@\" \ -DNETSTAT_PATH=\"@NETSTAT_PATH@\" \ -DRESOLVCONF_PATH=\"@RESOLVCONF_PATH@\" \ -DREVISION=\"@REVISION@\" \ - $(OPENSSL_CFLAGS) $(LIBSYSTEMD_CFLAGS) + $(OPENSSL_CFLAGS) $(LIBSYSTEMD_CFLAGS) \ + $(LIBGTK_CFLAGS) $(LIBWEBKIT_CFLAGS) openfortivpn_CFLAGS = -Wall -pedantic -openfortivpn_LDADD = $(OPENSSL_LIBS) $(LIBSYSTEMD_LIBS) +openfortivpn_LDADD = $(OPENSSL_LIBS) $(LIBSYSTEMD_LIBS) $(LIBGTK_LIBS) $(LIBWEBKIT_LIBS) PATHFILES = CLEAN_LOCALS = diff --git a/configure.ac b/configure.ac index 856e94be..4424132d 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,8 @@ PKG_CHECK_MODULES(OPENSSL, [libssl >= 0.9.8 libcrypto >= 0.9.8], [], [AC_MSG_ERR AC_CHECK_LIB([pthread], [pthread_create], [], [AC_MSG_ERROR([Cannot find libpthread.])]) AC_CHECK_LIB([util], [forkpty], [], [AC_MSG_ERROR([Cannot find libutil.])]) PKG_CHECK_MODULES(LIBSYSTEMD, [libsystemd], [AC_DEFINE(HAVE_SYSTEMD)], [AC_MSG_RESULT([libsystemd not present])]) +PKG_CHECK_MODULES(LIBGTK, [gtk+-3.0], [AC_DEFINE(HAVE_GTK)], [AC_MSG_RESULT([gtk not present])]) +PKG_CHECK_MODULES(LIBWEBKIT, [webkit2gtk-4.0], [AC_DEFINE(HAVE_WEBKIT)], [AC_MSG_RESULT([webkit2gtk not present])]) # we assume presence of the following C standard headers # and omit them in the following header checks diff --git a/src/config.c b/src/config.c index 94f0d6aa..7aa0c28e 100644 --- a/src/config.c +++ b/src/config.c @@ -77,6 +77,7 @@ const struct vpn_config invalid_cfg = { .pem_passphrase = {'\0'}, .pem_passphrase_set = 0, .insecure_ssl = -1, + .saml = -1, .cipher_list = NULL, .min_tls = -1, .seclevel_1 = -1, @@ -282,6 +283,15 @@ int load_config(struct vpn_config *cfg, const char *filename) continue; } cfg->no_ftm_push = no_ftm_push; + } else if (strcmp(key, "saml") == 0) { + int saml = strtob(val); + + if (saml < 0) { + log_warn("Bad saml in configuration file: \"%s\".\n", + val); + continue; + } + cfg->saml = saml; } else if (strcmp(key, "pinentry") == 0) { free(cfg->pinentry); cfg->pinentry = strdup(val); @@ -590,6 +600,10 @@ void merge_config(struct vpn_config *dst, struct vpn_config *src) } if (src->insecure_ssl != invalid_cfg.insecure_ssl) dst->insecure_ssl = src->insecure_ssl; + + if (src->saml != invalid_cfg.saml) + dst->saml = src->saml; + if (src->cipher_list) { free(dst->cipher_list); dst->cipher_list = src->cipher_list; diff --git a/src/config.h b/src/config.h index 6e47ce5e..c2caa3fe 100644 --- a/src/config.h +++ b/src/config.h @@ -58,12 +58,13 @@ struct x509_digest { char data[SHA256STRLEN]; }; -#define GATEWAY_HOST_SIZE 253 -#define USERNAME_SIZE 64 -#define PASSWORD_SIZE 256 -#define OTP_SIZE 64 -#define REALM_SIZE 63 -#define PEM_PASSPHRASE_SIZE 31 +#define GATEWAY_HOST_SIZE 253 +#define USERNAME_SIZE 64 +#define PASSWORD_SIZE 256 +#define OTP_SIZE 64 +#define REALM_SIZE 63 +#define PEM_PASSPHRASE_SIZE 31 +#define SAML_BROWSER_SIZE 8 /* * RFC 6265 does not limit the size of cookies: @@ -126,6 +127,7 @@ struct vpn_config { int pem_passphrase_set; int insecure_ssl; int min_tls; + int saml; int seclevel_1; char *cipher_list; struct x509_digest *cert_whitelist; diff --git a/src/main.c b/src/main.c index 7e7efa1d..fa343eaf 100644 --- a/src/main.c +++ b/src/main.c @@ -19,6 +19,7 @@ #include "tunnel.h" #include "userinput.h" #include "log.h" +#include "saml.h" #include @@ -243,6 +244,7 @@ int main(int argc, char **argv) .use_engine = 0, .user_agent = NULL, }; + struct vpn_config cli_cfg = invalid_cfg; const struct option long_options[] = { @@ -255,6 +257,7 @@ int main(int argc, char **argv) {"password", required_argument, NULL, 'p'}, {"cookie", required_argument, NULL, 0}, {"cookie-on-stdin", no_argument, NULL, 0}, + {"saml", no_argument, &cli_cfg.saml, 1}, {"otp", required_argument, NULL, 'o'}, {"otp-prompt", required_argument, NULL, 0}, {"otp-delay", required_argument, NULL, 0}, @@ -634,15 +637,21 @@ int main(int argc, char **argv) log_error("Specify a valid host:port couple.\n"); goto user_error; } - // Check username - if (cfg.username[0] == '\0' && !cfg.cookie) + + if (geteuid() != 0) { + log_error("This process was not spawned with root privileges, which are required.\n"); + ret = EXIT_FAILURE; + goto exit; + } + + if (cfg.username[0] == '\0' && !cfg.cookie && !cfg.saml) // Need either username or cert if (cfg.user_cert == NULL) { log_error("Specify a username.\n"); goto user_error; } // If username but no password given, interactively ask user - if (!cfg.password_set && cfg.username[0] != '\0' && !cfg.cookie) { + if (!cfg.password_set && cfg.username[0] != '\0' && !cfg.cookie && !cfg.saml) { char hint[USERNAME_SIZE + 1 + REALM_SIZE + 1 + GATEWAY_HOST_SIZE + 10]; sprintf(hint, "%s_%s_%s_password", @@ -654,18 +663,13 @@ int main(int argc, char **argv) log_debug("Configuration host = \"%s\"\n", cfg.gateway_host); log_debug("Configuration realm = \"%s\"\n", cfg.realm); log_debug("Configuration port = \"%d\"\n", cfg.gateway_port); + if (cfg.username[0] != '\0') log_debug("Configuration username = \"%s\"\n", cfg.username); log_debug_all("Configuration password = \"%s\"\n", cfg.password); if (cfg.otp[0] != '\0') log_debug("One-time password = \"%s\"\n", cfg.otp); - if (geteuid() != 0) { - log_error("This process was not spawned with root privileges, which are required.\n"); - ret = EXIT_FAILURE; - goto exit; - } - do { if (run_tunnel(&cfg) != 0) ret = EXIT_FAILURE; diff --git a/src/saml.c b/src/saml.c new file mode 100644 index 00000000..95d0c2dc --- /dev/null +++ b/src/saml.c @@ -0,0 +1,214 @@ +#include "log.h" +#include "config.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// Global variables that need to be shared with the child process. +char *svpncookie = NULL; +size_t svpncookie_size = 0; + +static void destroy_window_cb(GtkWidget *widget, GtkWidget *window) +{ + gtk_main_quit(); +} + +static gboolean close_web_view_cb(WebKitWebView *webView, GtkWidget *window) +{ + gtk_widget_destroy(window); + return TRUE; +} + +static void cookie_ready_callback(GObject *obj, GAsyncResult *res, + gpointer user_data) +{ + WebKitCookieManager *cookie_mgr = (WebKitCookieManager *)obj; + + GError *err = NULL; + GList *cookies = + webkit_cookie_manager_get_cookies_finish(cookie_mgr, res, &err); + + if (err != NULL) { + printf("There was an error while getting the cookies: %s\n", + err->message); + return; + } + + // There was no cookie for the specified domain. + if (!cookies) + return; + + GList *cur = cookies; + bool found_cookie = false; + + while (cur) { + if (strcmp(soup_cookie_get_name(cur->data), "SVPNCOOKIE") == + 0) { + strcpy(svpncookie, "SVPNCOOKIE="); + + strncpy(svpncookie + + sizeof(char) * strlen("SVPNCOOKIE="), + soup_cookie_get_value(cur->data), + svpncookie_size); + + // Just in case that strncpy doesn't set the null terminator. + svpncookie[svpncookie_size - 1] = '\0'; + found_cookie = true; + break; + } + + cur = cur->next; + } + + g_list_free(cookies); + + // Exit the browser and gtk when we got the cookie. + if (found_cookie) + gtk_main_quit(); +} + +static void cookie_changed_cb(WebKitCookieManager *self, gpointer *data) +{ + char url[strlen("https://") + strlen((const char *)data) + 1]; + sprintf(url, "https://%s", (char *)data); + + webkit_cookie_manager_get_cookies(self, url, NULL, + cookie_ready_callback, data); +} + +/* Returns the given directory/file under the home directory. + * Return value must be manyally freed */ +static char *get_under_home_dir(char *dir) +{ + char *username = getlogin(); + char *result = + malloc(strlen("/home//") + strlen(username) + strlen(dir) + 1); + + sprintf(result, "/home/%s/%s", username, dir); + + return result; +} + +static int webkit_get_cookie(char *host, char *realm, char *website_cert) +{ + char *cookie_file = get_under_home_dir(".openfortivpncookies"); + + gtk_init(0, NULL); + GtkWidget *main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(main_window), 800, 600); + + WebKitWebsiteDataManager *data_mgr = + webkit_website_data_manager_new(NULL); + + WebKitCookieManager *cookie_mgr = + webkit_website_data_manager_get_cookie_manager(data_mgr); + + webkit_cookie_manager_set_persistent_storage( + cookie_mgr, cookie_file, WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT); + + WebKitWebContext *web_context = + webkit_web_context_new_with_website_data_manager(data_mgr); + WebKitWebView *web_view = + WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(web_context)); + + gtk_container_add(GTK_CONTAINER(main_window), GTK_WIDGET(web_view)); + g_signal_connect(main_window, "destroy", G_CALLBACK(destroy_window_cb), + NULL); + g_signal_connect(web_view, "close", G_CALLBACK(close_web_view_cb), + main_window); + g_signal_connect(cookie_mgr, "changed", G_CALLBACK(cookie_changed_cb), + host); + + GTlsCertificate *cert = + g_tls_certificate_new_from_pem(website_cert, -1, NULL); + + webkit_web_context_allow_tls_certificate_for_host(web_context, cert, + host); + + char saml_url[strlen("https:///remote/saml/start") + strlen(host) + + strlen("?realm=") + strlen(realm) + 1]; + + if (realm) { + sprintf(saml_url, "https://%s/remote/saml/start?realm=%s", host, + realm); + } else { + sprintf(saml_url, "https://%s/remote/saml/start", host); + } + + webkit_web_view_load_uri(web_view, saml_url); + + gtk_widget_grab_focus(GTK_WIDGET(web_view)); + gtk_widget_show_all(main_window); + + gtk_main(); + + // Don't allow other users to read the cookies. + chmod("/home/lorenz/.openfortivpncookies", 0600); + + free(cookie_file); + return 0; +} + +/* Returns 0 if the cookie was set successfully. -1 if there was an error. */ +int saml_get_cookie(char *vpn_domain, char *realm, char **dst_cookie, + char *website_cert) +{ + svpncookie_size = sizeof(char) * (COOKIE_SIZE + 1); + + // This is needed because the browser (child process) needs to set the + // cookie (write to the memory) which is not possible with malloc, etc. + svpncookie = mmap(NULL, svpncookie_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + char *user_id = getenv("SUDO_UID"); + + if (!user_id) { + log_error( + "Could not find the SUDO_UID enviroment variable." + "Please set it to your UID if you're not running with sudo (required to run the browser)\n"); + + goto exit_error; + } + + uid_t browser_uid = atoi(user_id); + + if (browser_uid == 0) { + log_error( + "Cannot run the browser as root. Please set SUDO_UID to an appropiate user.\n"); + goto exit_error; + } + + if (fork() == 0) { + char *home_dir = get_under_home_dir(""); + + clearenv(); + setenv("HOME", home_dir, 1); + setenv("DISPLAY", ":0", 1); + + setuid(browser_uid); + webkit_get_cookie(vpn_domain, realm, website_cert); + + free(home_dir); + exit(EXIT_SUCCESS); + } + + wait(NULL); + + *dst_cookie = strndup(svpncookie, COOKIE_SIZE); + + int ret = 0; + goto exit; +exit_error: + ret = -1; + goto exit; +exit: + munmap(svpncookie, svpncookie_size); + return ret; +} diff --git a/src/saml.h b/src/saml.h new file mode 100644 index 00000000..a3eef2d6 --- /dev/null +++ b/src/saml.h @@ -0,0 +1,6 @@ +#ifndef OPENFORTIVPN_SAML_H +#define OPENFORTIVPN_SAML_H + +int saml_get_cookie(char *vpn_domain, char *realm, char **dst_cookie, char *cert); + +#endif diff --git a/src/tunnel.c b/src/tunnel.c index c228c6be..aaac284b 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -30,6 +30,7 @@ #include "http.h" #include "log.h" #include "userinput.h" +#include "saml.h" #ifndef HAVE_X509_CHECK_HOST #include "openssl_hostname_validation.h" #endif @@ -40,6 +41,7 @@ #endif #include #include +#include #if HAVE_SYSTEMD #include #endif @@ -1287,10 +1289,30 @@ int run_tunnel(struct vpn_config *config) // Step 2: connect to the HTTP interface and authenticate to get a // cookie + if (config->saml) { + X509 *cert = SSL_get_peer_certificate(tunnel.ssl_handle); + + BIO *b = BIO_new(BIO_s_mem()); + PEM_write_bio_X509(b, cert); + + char *cert_buffer; + BIO_get_mem_data(b, &cert_buffer); + + BIO_set_close(b, BIO_NOCLOSE); + BIO_free(b); + X509_free(cert); + + saml_get_cookie(config->gateway_host, config->realm, + &config->cookie, cert_buffer); + + free(cert_buffer); + } + if (config->cookie) ret = auth_set_cookie(&tunnel, config->cookie); else ret = auth_log_in(&tunnel); + if (ret != 1) { log_error("Could not authenticate to gateway. Please check the password, client certificate, etc.\n"); log_debug("%s (%d)\n", err_http_str(ret), ret); From f9a0c7f5f7f82c16b012caa671c46755f22db785 Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Tue, 29 Nov 2022 11:27:37 +0100 Subject: [PATCH 2/9] Update the documentation to include --saml --- doc/openfortivpn.1.in | 3 +++ src/main.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/openfortivpn.1.in b/doc/openfortivpn.1.in index abed22f0..94f26081 100644 --- a/doc/openfortivpn.1.in +++ b/doc/openfortivpn.1.in @@ -10,6 +10,7 @@ openfortivpn \- Client for PPP+SSL VPN tunnel services [\fB\-p\fR \fI\fR] [\fB\-\-cookie=\fI\fR] [\fB\-\-cookie\-on\-stdin\fR] +[\fB\-\-saml\fR] [\fB\-\-pinentry=\fI\fR] [\fB\-\-otp=\fI\fR] [\fB\-\-otp\-prompt=\fI\fR] @@ -79,6 +80,8 @@ A valid cookie (SVPNCOOKIE) to use in place of username and password. .TP \fB\-\-cookie\-on\-stdin\fR Read the cookie (SVPNCOOKIE) from standard input. +\fB\-\-saml\fR +Use saml for authentication. .TP \fB\-\-pinentry=\fI\fR The pinentry program to use. Allows supplying the password in a secure manner. diff --git a/src/main.c b/src/main.c index fa343eaf..a6e0e398 100644 --- a/src/main.c +++ b/src/main.c @@ -76,7 +76,7 @@ #define usage \ "Usage: openfortivpn [[:]] [-u ] [-p ]\n" \ -" [--cookie=] [--cookie-on-stdin]\n" \ +" [--cookie=] [--cookie-on-stdin] [--saml]\n" \ " [--otp=] [--otp-delay=] [--otp-prompt=]\n" \ " [--pinentry=] [--realm=]\n" \ " [--ifname=] [--set-routes=<0|1>]\n" \ @@ -114,6 +114,7 @@ PPPD_USAGE \ " " SYSCONFDIR "/openfortivpn/config).\n" \ " -u , --username= VPN account username.\n" \ " -p , --password= VPN account password.\n" \ +" --saml Use saml login.\n" \ " --cookie= A valid session cookie (SVPNCOOKIE).\n" \ " --cookie-on-stdin Read the cookie (SVPNCOOKIE) from standard input.\n" \ " -o , --otp= One-Time-Password.\n" \ From 7c86ff61e198d8c565ed80846665565ad5f83000 Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Mon, 5 Dec 2022 11:53:33 +0100 Subject: [PATCH 3/9] Make Webkit2gtk work on wayland --- src/saml.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/saml.c b/src/saml.c index 95d0c2dc..5c6e38f0 100644 --- a/src/saml.c +++ b/src/saml.c @@ -187,15 +187,21 @@ int saml_get_cookie(char *vpn_domain, char *realm, char **dst_cookie, if (fork() == 0) { char *home_dir = get_under_home_dir(""); + char *xdg_runtime_dir = malloc(strlen("/run/user/XXXXXXXXXX") + 1); + sprintf(xdg_runtime_dir, "/run/user/%d", browser_uid); clearenv(); setenv("HOME", home_dir, 1); setenv("DISPLAY", ":0", 1); + // Needed for wayland + setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1); + setuid(browser_uid); webkit_get_cookie(vpn_domain, realm, website_cert); free(home_dir); + free(xdg_runtime_dir); exit(EXIT_SUCCESS); } From 5f3f5d980a8ce793a81721cddf0c990cf87e54d4 Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Mon, 5 Dec 2022 12:08:19 +0100 Subject: [PATCH 4/9] Update the README to inclde build deps and saml example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fd542430..cd1918d3 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ For other distros, you'll need to build and install from source: 1. Install build dependencies. * RHEL/CentOS/Fedora: `gcc` `automake` `autoconf` `openssl-devel` `make` `pkg-config` - * Debian/Ubuntu: `gcc` `automake` `autoconf` `libssl-dev` `make` `pkg-config` + * Debian/Ubuntu: `gcc` `automake` `autoconf` `libssl-dev` `make` `pkg-config` `libgtk-3-dev` `libwebkitgtk-3.0-dev` * Arch Linux: `gcc` `automake` `autoconf` `openssl` `pkg-config` * Gentoo Linux: `net-dialup/ppp` `pkg-config` * openSUSE: `gcc` `automake` `autoconf` `libopenssl-devel` `pkg-config` From 3235f62ae583302c38366898aa07e4fae62d7245 Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Mon, 5 Dec 2022 12:13:59 +0100 Subject: [PATCH 5/9] Update the README to inclde build deps and saml example --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cd1918d3..902f7ee7 100644 --- a/README.md +++ b/README.md @@ -131,11 +131,11 @@ For other distros, you'll need to build and install from source: 1. Install build dependencies. - * RHEL/CentOS/Fedora: `gcc` `automake` `autoconf` `openssl-devel` `make` `pkg-config` + * RHEL/CentOS/Fedora: `gcc` `automake` `autoconf` `openssl-devel` `make` `pkg-config` `gtk3-devel` `webkit2gtk4.0-devel` * Debian/Ubuntu: `gcc` `automake` `autoconf` `libssl-dev` `make` `pkg-config` `libgtk-3-dev` `libwebkitgtk-3.0-dev` - * Arch Linux: `gcc` `automake` `autoconf` `openssl` `pkg-config` - * Gentoo Linux: `net-dialup/ppp` `pkg-config` - * openSUSE: `gcc` `automake` `autoconf` `libopenssl-devel` `pkg-config` + * Arch Linux: `gcc` `automake` `autoconf` `openssl` `pkg-config` `extra/webkit2gtk` + * Gentoo Linux: `net-dialup/ppp` `pkg-config` `net-libs/webkit-gtk` + * openSUSE: `gcc` `automake` `autoconf` `libopenssl-devel` `pkg-config` `webkit2gtk3` * macOS (Homebrew): `automake` `autoconf` `openssl@1.1` `pkg-config` * FreeBSD: `automake` `autoconf` `libressl` `pkgconf` From 96fef16b31729e697d56d896b599f7204e13656a Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Thu, 8 Dec 2022 08:15:57 +0100 Subject: [PATCH 6/9] SAML: Use the specified port for login --- src/saml.c | 22 ++++++++++++---------- src/saml.h | 4 +++- src/tunnel.c | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/saml.c b/src/saml.c index 5c6e38f0..29f2cca1 100644 --- a/src/saml.c +++ b/src/saml.c @@ -96,7 +96,8 @@ static char *get_under_home_dir(char *dir) return result; } -static int webkit_get_cookie(char *host, char *realm, char *website_cert) +static int webkit_get_cookie(char *gateway_host, uint16_t gateway_port, + char *realm, char *website_cert) { char *cookie_file = get_under_home_dir(".openfortivpncookies"); @@ -124,22 +125,23 @@ static int webkit_get_cookie(char *host, char *realm, char *website_cert) g_signal_connect(web_view, "close", G_CALLBACK(close_web_view_cb), main_window); g_signal_connect(cookie_mgr, "changed", G_CALLBACK(cookie_changed_cb), - host); + gateway_host); GTlsCertificate *cert = g_tls_certificate_new_from_pem(website_cert, -1, NULL); webkit_web_context_allow_tls_certificate_for_host(web_context, cert, - host); + gateway_host); - char saml_url[strlen("https:///remote/saml/start") + strlen(host) + + // Maximum possible port length is 5 (65536/XXXXX) + char saml_url[strlen("https://XXXXX/remote/saml/start") + strlen(gateway_host) + strlen("?realm=") + strlen(realm) + 1]; if (realm) { - sprintf(saml_url, "https://%s/remote/saml/start?realm=%s", host, - realm); + sprintf(saml_url, "https://%s:%d/remote/saml/start?realm=%s", gateway_host, + gateway_port, realm); } else { - sprintf(saml_url, "https://%s/remote/saml/start", host); + sprintf(saml_url, "https://%s:%d/remote/saml/start", gateway_host, gateway_port); } webkit_web_view_load_uri(web_view, saml_url); @@ -157,8 +159,8 @@ static int webkit_get_cookie(char *host, char *realm, char *website_cert) } /* Returns 0 if the cookie was set successfully. -1 if there was an error. */ -int saml_get_cookie(char *vpn_domain, char *realm, char **dst_cookie, - char *website_cert) +int saml_get_cookie(char *gateway_host, uint16_t gateway_port, char *realm, + char **dst_cookie, char *cert) { svpncookie_size = sizeof(char) * (COOKIE_SIZE + 1); @@ -198,7 +200,7 @@ int saml_get_cookie(char *vpn_domain, char *realm, char **dst_cookie, setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1); setuid(browser_uid); - webkit_get_cookie(vpn_domain, realm, website_cert); + webkit_get_cookie(gateway_host, gateway_port, realm, cert); free(home_dir); free(xdg_runtime_dir); diff --git a/src/saml.h b/src/saml.h index a3eef2d6..1b97a552 100644 --- a/src/saml.h +++ b/src/saml.h @@ -1,6 +1,8 @@ #ifndef OPENFORTIVPN_SAML_H #define OPENFORTIVPN_SAML_H -int saml_get_cookie(char *vpn_domain, char *realm, char **dst_cookie, char *cert); +#include + +int saml_get_cookie(char *vpn_domain, uint16_t gateway_port, char *realm, char **dst_cookie, char *cert); #endif diff --git a/src/tunnel.c b/src/tunnel.c index bcabf10c..743a15dd 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -1288,8 +1288,8 @@ int run_tunnel(struct vpn_config *config) BIO_free(b); X509_free(cert); - saml_get_cookie(config->gateway_host, config->realm, - &config->cookie, cert_buffer); + saml_get_cookie(config->gateway_host, config->gateway_port, + config->realm, &config->cookie, cert_buffer); free(cert_buffer); } From 1e30f7ad225850451d9e662c70b71c1d37e6e47d Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Thu, 8 Dec 2022 08:22:11 +0100 Subject: [PATCH 7/9] Change the README to include a saml example --- README.md | 5 +++++ src/saml.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 902f7ee7..9b039c99 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,11 @@ Examples openfortivpn vpn-gateway:8443 --username=foo --realm=bar ``` +* Connect using saml: + ``` + openfortivpn vpn-gateway:8443 --saml + ``` + * Store password securely with a pinentry program: ``` openfortivpn vpn-gateway:8443 --username=foo --pinentry=pinentry-mac diff --git a/src/saml.h b/src/saml.h index 1b97a552..1a765cb8 100644 --- a/src/saml.h +++ b/src/saml.h @@ -3,6 +3,6 @@ #include -int saml_get_cookie(char *vpn_domain, uint16_t gateway_port, char *realm, char **dst_cookie, char *cert); +int saml_get_cookie(char *gateway_port, uint16_t gateway_port, char *realm, char **dst_cookie, char *cert); #endif From 3c4bb21d92c70cf05d6bed172139c123ee72ade4 Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Thu, 8 Dec 2022 11:10:07 +0100 Subject: [PATCH 8/9] Remove error --- src/saml.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/saml.h b/src/saml.h index 1a765cb8..77f05e5a 100644 --- a/src/saml.h +++ b/src/saml.h @@ -3,6 +3,6 @@ #include -int saml_get_cookie(char *gateway_port, uint16_t gateway_port, char *realm, char **dst_cookie, char *cert); +int saml_get_cookie(char *gateway_host, uint16_t gateway_port, char *realm, char **dst_cookie, char *cert); #endif From 0acc0733ce5ad181fe0154b58e72b568e55d13c9 Mon Sep 17 00:00:00 2001 From: "lorenz.gassmann" Date: Thu, 8 Dec 2022 12:52:11 +0100 Subject: [PATCH 9/9] Remove my own path --- src/saml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/saml.c b/src/saml.c index 29f2cca1..648697c0 100644 --- a/src/saml.c +++ b/src/saml.c @@ -152,7 +152,7 @@ static int webkit_get_cookie(char *gateway_host, uint16_t gateway_port, gtk_main(); // Don't allow other users to read the cookies. - chmod("/home/lorenz/.openfortivpncookies", 0600); + chmod(cookie_file, 0600); free(cookie_file); return 0;