AM_CONDITIONAL(BUILD_NSIS, [ test "$build_nsis" = "yes" ])
AM_CONDITIONAL(OPENCONNECT_WINTUN, [ test "${wintun_arch}" != "" ])
+AC_ARG_WITH([external-browser],
+ [AS_HELP_STRING([--with-external-browser],
+ [command to use for spawning external web browser])])
+
+if test "$with_external_browser" = "yes" || test "$with_external_browser" = ""; then
+ AC_MSG_CHECKING([for xdg-open])
+ AC_PATH_PROG(with_external_browser, xdg-open, no)
+fi
+if test "$with_external_browser" != "no"; then
+ if test -x "${with_external_browser}"; then
+ AC_DEFINE_UNQUOTED(DEFAULT_EXTERNAL_BROWSER, "${with_external_browser}", [External browser executable])
+ else
+ AC_MSG_ERROR([${with_external_browser} does not seem to be executable.])
+ fi
+fi
+
AC_ARG_WITH([vpnc-script],
[AS_HELP_STRING([--with-vpnc-script],
[default location of vpnc-script helper])])
AC_CHECK_FUNC(nl_langinfo, [AC_DEFINE(HAVE_NL_LANGINFO, 1, [Have nl_langinfo() function])], [])
+AC_CHECK_FUNC(posix_spawn, [AC_DEFINE(HAVE_POSIX_SPAWN, 1, [Have posix_spawn() function])], [])
+
if test "$ac_cv_func_nl_langinfo" = "yes"; then
AM_ICONV
if test "$am_cv_func_iconv" = "yes"; then
}
#else
+#ifdef HAVE_POSIX_SPAWN
+#include <spawn.h>
+#endif
+
#include <ctype.h>
#define HPKE_TAG_PUBKEY 1
if (set_sock_nonblock(listen_fd))
goto sockerr;
+ /* Now that we are listening on the socket, we can spawn the browser */
+ if (vpninfo->open_ext_browser) {
+ ret = vpninfo->open_ext_browser(vpninfo, vpninfo->sso_login, vpninfo->cbdata);
+#if defined(HAVE_POSIX_SPAWN) && defined(DEFAULT_EXTERNAL_BROWSER)
+ } else {
+ vpn_progress(vpninfo, PRG_TRACE, _("Spawning external browser '%s'\n"),
+ DEFAULT_EXTERNAL_BROWSER);
+
+ pid_t pid = 0;
+ char * browser_argv[3] = { (char *)DEFAULT_EXTERNAL_BROWSER, vpninfo->sso_login, NULL };
- /* Now that we are listening on the socket, we can spawn the browser...
- or just tell the user to, for now */
- vpn_progress(vpninfo, PRG_ERR,
- _("Point browser to this URL:\n%s\n"),
- vpninfo->sso_login);
+ if (posix_spawn(&pid, DEFAULT_EXTERNAL_BROWSER, NULL, NULL, browser_argv, environ)) {
+ ret = -errno;
+ vpn_perror(vpninfo, _("Spawn browser"));
+ }
+#else
+ } else {
+ ret = -EINVAL;
+#endif
+ }
+ if (ret)
+ vpn_progress(vpninfo, PRG_ERR,
+ _("Failed to spawn external browser for %s\n"),
+ vpninfo->sso_login);
char *returl = NULL;
struct oc_text_buf *b64_buf = NULL;
openconnect_webview_load_changed;
} OPENCONNECT_5_6;
+OPENCONNECT_5_8 {
+ global:
+ openconnect_set_external_browser_callback;
+} OPENCONNECT_5_7;
+
OPENCONNECT_PRIVATE {
global: @SYMVER_TIME@ @SYMVER_GETLINE@ @SYMVER_JAVA@ @SYMVER_ASPRINTF@ @SYMVER_VASPRINTF@ @SYMVER_WIN32_STRERROR@ @SYMVER_WIN32_SETENV@
openconnect_get_tls_library_version;
vpninfo->try_http_auth = 0;
}
+void openconnect_set_external_browser_callback(struct openconnect_info *vpninfo,
+ openconnect_open_webview_vfn browser_fn)
+{
+ vpninfo->open_ext_browser = browser_fn;
+ vpninfo->try_http_auth = 0;
+}
+
int openconnect_webview_load_changed(struct openconnect_info *vpninfo,
const struct oc_webview_result *result)
{
static char *token_filename;
static int allowed_fingerprints;
+static char *ext_browser;
+
struct accepted_cert {
struct accepted_cert *next;
char *fingerprint;
OPT_DTLS_CIPHERS,
OPT_DTLS12_CIPHERS,
OPT_DUMP_HTTP,
+ OPT_EXT_BROWSER,
OPT_FORCE_DPD,
OPT_FORCE_TROJAN,
OPT_GNUTLS_DEBUG,
OPTION("syslog", 0, 'l'),
OPTION("csd-user", 1, OPT_CSD_USER),
OPTION("csd-wrapper", 1, OPT_CSD_WRAPPER),
+#endif
+#ifdef HAVE_POSIX_SPAWN
+ OPTION("external-browser", 1, OPT_EXT_BROWSER),
#endif
OPTION("pfs", 0, OPT_PFS),
OPTION("allow-insecure-crypto", 0, OPT_ALLOW_INSECURE_CRYPTO),
return TRUE;
}
#endif
+#ifdef HAVE_POSIX_SPAWN
+#include <spawn.h>
+static int spawn_browser(struct openconnect_info *vpninfo, const char *url, void *cbdata)
+{
+ vpn_progress(vpninfo, PRG_TRACE,
+ _("Main Spawning external browser '%s'\n"),
+ ext_browser);
+ pid_t pid = 0;
+ char *browser_argv[3] = { ext_browser, (char *)url, NULL };
+ if (posix_spawn(&pid, ext_browser, NULL, NULL, browser_argv, environ)) {
+ vpn_perror(vpninfo, _("Spawn browser"));
+ return -errno;
+ }
+
+ return 0;
+}
+#endif
static void print_default_vpncscript(void)
{
printf("%s %s\n", _("Default vpnc-script (override with --script):"),
printf(" -e, --cert-expire-warning=DAYS %s\n", _("Warn when certificate lifetime < DAYS"));
printf(" -g, --usergroup=GROUP %s\n", _("Set login usergroup"));
printf(" -p, --key-password=PASS %s\n", _("Set key passphrase or TPM SRK PIN"));
+ printf(" --external-browser=BROWSER %s\n", _("Set external browser executable"));
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, hotp or oidc"));
printf(" --token-secret=STRING %s\n", _("Software token secret or oidc token"));
case 's': /* --script */
case OPT_CSD_WRAPPER: /* --csd-wrapper */
+ case OPT_EXT_BROWSER: /* --external-browser */
autocomplete_special("EXECUTABLE", comp_opt, prefixlen, NULL);
break;
case 's':
vpnc_script = dup_config_arg();
break;
+ case OPT_EXT_BROWSER:
+ ext_browser = dup_config_arg();
+ break;
case 'u':
free(username);
username = dup_config_arg();
verbose = PRG_DEBUG;
openconnect_set_loglevel(vpninfo, verbose);
-
if (autoproxy) {
#ifdef LIBPROXY_HDR
vpninfo->proxy_factory = px_proxy_factory_new();
if (proxy && openconnect_set_http_proxy(vpninfo, strdup(proxy)))
exit(1);
+#ifdef HAVE_POSIX_SPAWN
+ if (ext_browser)
+ openconnect_set_external_browser_callback(vpninfo, spawn_browser);
+#endif
+
#ifndef _WIN32
memset(&sa, 0, sizeof(sa));
openconnect_validate_peer_cert_vfn validate_peer_cert;
openconnect_write_new_config_vfn write_new_config;
openconnect_open_webview_vfn open_webview;
+ openconnect_open_webview_vfn open_ext_browser;
openconnect_process_auth_form_vfn process_auth_form;
openconnect_progress_vfn progress;
openconnect_protect_socket_vfn protect_socket;
#define OPENCONNECT_API_VERSION_MINOR 7
/*
+ * API version 5.8:
+ * - Add openconnect_set_external_browser_callback()
+ *
* API version 5.7 (v8.20; 2022-02-20):
* - Add openconnect_get_connect_url()
* - Add openconnect_set_cookie()
int openconnect_webview_load_changed(struct openconnect_info *vpninfo,
const struct oc_webview_result *result);
+void openconnect_set_external_browser_callback(struct openconnect_info *vpninfo,
+ openconnect_open_webview_vfn);
+
/* Callback to allow binding a newly created socket's file descriptor to
a specific interface, e.g. with SO_BINDTODEVICE. This tells the kernel
not to route the traffic in question over the VPN tunnel. */