Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ openfortivpn_SOURCES = src/config.c src/config.h src/hdlc.c src/hdlc.h \
src/http.c src/http.h src/io.c src/io.h src/ipv4.c \
src/ipv4.h src/log.c src/log.h src/tunnel.c \
src/tunnel.h src/main.c src/ssl.h src/xml.c \
src/xml.h src/userinput.c src/userinput.h \
src/saml.c src/saml.h
src/xml.h src/userinput.c src/userinput.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 =
Expand Down
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -131,11 +136,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`
* Debian/Ubuntu: `gcc` `automake` `autoconf` `libssl-dev` `make` `pkg-config`
* Arch Linux: `gcc` `automake` `autoconf` `openssl` `pkg-config`
* Gentoo Linux: `net-dialup/ppp` `pkg-config`
* openSUSE: `gcc` `automake` `autoconf` `libopenssl-devel` `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` `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`

Expand Down
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ PKG_CHECK_MODULES(OPENSSL, [libssl >= 1.0.2 libcrypto >= 1.0.2], [], [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
Expand Down
3 changes: 3 additions & 0 deletions doc/openfortivpn.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ openfortivpn \- Client for PPP+SSL VPN tunnel services
[\fB\-p\fR \fI<pass>\fR]
[\fB\-\-cookie=\fI<cookie>\fR]
[\fB\-\-cookie\-on\-stdin\fR]
[\fB\-\-saml\fR]
[\fB\-\-pinentry=\fI<name>\fR]
[\fB\-\-otp=\fI<otp>\fR]
[\fB\-\-otp\-prompt=\fI<prompt>\fR]
Expand Down Expand Up @@ -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<name>\fR
The pinentry program to use. Allows supplying the password in a secure manner.
Expand Down
14 changes: 14 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 8 additions & 6 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down
25 changes: 15 additions & 10 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "tunnel.h"
#include "userinput.h"
#include "log.h"
#include "saml.h"

#include <openssl/ssl.h>

Expand Down Expand Up @@ -75,7 +76,7 @@

#define usage \
"Usage: openfortivpn [<host>[:<port>]] [-u <user>] [-p <pass>]\n" \
" [--cookie=<cookie>] [--cookie-on-stdin]\n" \
" [--cookie=<cookie>] [--cookie-on-stdin] [--saml]\n" \
" [--otp=<otp>] [--otp-delay=<delay>] [--otp-prompt=<prompt>]\n" \
" [--pinentry=<program>] [--realm=<realm>]\n" \
" [--ifname=<ifname>] [--set-routes=<0|1>]\n" \
Expand Down Expand Up @@ -113,6 +114,7 @@ PPPD_USAGE \
" " SYSCONFDIR "/openfortivpn/config).\n" \
" -u <user>, --username=<user> VPN account username.\n" \
" -p <pass>, --password=<pass> VPN account password.\n" \
" --saml Use saml login.\n" \
" --cookie=<cookie> A valid session cookie (SVPNCOOKIE).\n" \
" --cookie-on-stdin Read the cookie (SVPNCOOKIE) from standard input.\n" \
" -o <otp>, --otp=<otp> One-Time-Password.\n" \
Expand Down Expand Up @@ -243,6 +245,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[] = {
Expand All @@ -255,6 +258,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},
Expand Down Expand Up @@ -634,15 +638,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",
Expand All @@ -654,18 +664,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;
Expand Down
Loading