diff --git a/NEWS b/NEWS
index da02da76..07c968dd 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@
anyconnect clients seem to supporting TLS1.3 but unable to handle
a client with an RSA key (#318)
- Enable a race free user disconnection via occtl (#59)
+- Added the config option of a pre-login-banner (#313)
* Version 1.1.0 (released 2020-06-16)
diff --git a/doc/sample.config b/doc/sample.config
index 0bcf1ae0..a291b8d4 100644
--- a/doc/sample.config
+++ b/doc/sample.config
@@ -190,9 +190,12 @@ ca-cert = ../tests/certs/ca.pem
# information at: https://gitlab.com/ocserv/ocserv/issues
isolate-workers = true
-# A banner to be displayed on clients
+# A banner to be displayed on clients after connection
#banner = "Welcome"
+# A banner to be displayed on clients before connection
+#pre-login-banner = "Welcome"
+
# Limit the number of clients. Unset or set to zero for unlimited.
#max-clients = 1024
max-clients = 16
diff --git a/src/config.c b/src/config.c
index 1f1ab123..0278db0c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -874,6 +874,8 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name, co
fprintf(stderr, WARNSTR"the option 'session-control' is deprecated\n");
} else if (strcmp(name, "banner") == 0) {
READ_STRING(config->banner);
+ } else if (strcmp(name, "pre-login-banner") == 0) {
+ READ_STRING(config->pre_login_banner);
} else if (strcmp(name, "dtls-legacy") == 0) {
READ_TF(config->dtls_legacy);
} else if (strcmp(name, "cisco-client-compat") == 0) {
diff --git a/src/vpn.h b/src/vpn.h
index 5876bb21..77933dcc 100644
--- a/src/vpn.h
+++ b/src/vpn.h
@@ -242,6 +242,7 @@ struct cfg_st {
unsigned no_compress_limit; /* under this size (in bytes) of data there will be no compression */
#endif
char *banner;
+ char *pre_login_banner;
char *ocsp_response; /* file with the OCSP response */
char *default_domain; /* domain to be advertised */
diff --git a/src/worker-auth.c b/src/worker-auth.c
index 40ea3a7e..b708164f 100644
--- a/src/worker-auth.c
+++ b/src/worker-auth.c
@@ -73,41 +73,41 @@ static const char ocv3_success_msg_head[] = "\n";
-#define OC_LOGIN_MSG_START \
+#define OC_LOGIN_START \
"\n" \
"\n" \
VERSION_MSG \
- "\n" \
+ "\n"
+
+#define OC_LOGIN_FORM_START \
"%s\n" \
"\n" "";
+#define OC_LOGIN_END \
+ "\n" ""
-static const char login_msg_user[] =
- "\n";
+#define OC_LOGIN_FORM_INPUT_USER \
+ "\n"
#define DEFAULT_PASSWD_LABEL "Password:"
-#define LOGIN_MSG_PASSWORD \
+#define OC_LOGIN_FORM_INPUT_PASSWORD \
"\n"
-#define LOGIN_MSG_PASSWORD_CTR \
+#define OC_LOGIN_FORM_INPUT_PASSWORD_CTR \
"\n"
#define _OCV3_LOGIN_MSG_START(x) \
"\n" \
- "\n" \
- "%s\n" \
- "\n"
#ifdef SUPPORT_OIDC_AUTH
#define HTTP_AUTH_OIDC_PREFIX "Bearer"
#endif
-static const char ocv3_login_msg_end[] =
- "\n";
static int get_cert_info(worker_st * ws);
static int basic_auth_handler(worker_st * ws, unsigned http_ver, const char *msg);
@@ -208,20 +208,20 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, unsig
char context[BASE64_ENCODE_RAW_LENGTH(SID_SIZE) + 1];
unsigned int i, j;
str_st str;
- const char *login_msg_start;
- const char *login_msg_end;
+ const char *login_start;
+ const char *login_end;
if (ws->req.user_agent_type == AGENT_OPENCONNECT_V3) {
/* certain v2.x modified clients require a different auth_id
* when password is being requested, rather than username */
if (ws->auth_state == S_AUTH_REQ)
- login_msg_start = OCV3_PASSWD_MSG_START;
+ login_start = OCV3_PASSWD_START;
else
- login_msg_start = OCV3_LOGIN_MSG_START;
- login_msg_end = ocv3_login_msg_end;
+ login_start = OCV3_LOGIN_START;
+ login_end = OCV3_LOGIN_END;
} else {
- login_msg_start = OC_LOGIN_MSG_START;
- login_msg_end = oc_login_msg_end;
+ login_start = OC_LOGIN_START;
+ login_end = OC_LOGIN_END;
}
if ((ws->selected_auth->type & AUTH_TYPE_GSSAPI) && ws->auth_state < S_AUTH_COOKIE) {
@@ -269,44 +269,64 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, unsig
}
if (ws->auth_state == S_AUTH_REQ) {
- /* only ask password */
+ /* Password Form */
if (pmsg == NULL || strncasecmp(pmsg, DEFAULT_PASSWD_LABEL, sizeof(DEFAULT_PASSWD_LABEL)-1) == 0)
pmsg = "Please enter your password.";
- ret = str_append_printf(&str, login_msg_start, pmsg);
+ ret = str_append_str(&str, login_start);
+ if (ret < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ ret = str_append_printf(&str, OC_LOGIN_FORM_START, pmsg);
if (ret < 0) {
ret = -1;
goto cleanup;
}
if (pcounter > 0)
- ret = str_append_printf(&str, LOGIN_MSG_PASSWORD_CTR, pcounter);
+ ret = str_append_printf(&str, OC_LOGIN_FORM_INPUT_PASSWORD_CTR, pcounter);
else
- ret = str_append_str(&str, LOGIN_MSG_PASSWORD);
+ ret = str_append_str(&str, OC_LOGIN_FORM_INPUT_PASSWORD);
if (ret < 0) {
ret = -1;
goto cleanup;
}
- ret = str_append_str(&str, login_msg_end);
+ ret = str_append_str(&str, login_end);
if (ret < 0) {
ret = -1;
goto cleanup;
}
} else {
+ /* Username / Groups Form */
if (pmsg == NULL)
pmsg = "Please enter your username.";
- /* ask for username and groups */
- ret = str_append_printf(&str, login_msg_start, pmsg);
+ ret = str_append_str(&str, login_start);
+ if (ret < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (WSCONFIG(ws)->pre_login_banner) {
+ ret = str_append_printf(&str, "%s", WSCONFIG(ws)->pre_login_banner);
+ if (ret < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ ret = str_append_printf(&str, OC_LOGIN_FORM_START, pmsg);
if (ret < 0) {
ret = -1;
goto cleanup;
}
if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
- ret = str_append_str(&str, login_msg_user);
+ ret = str_append_str(&str, OC_LOGIN_FORM_INPUT_USER);
if (ret < 0) {
ret = -1;
goto cleanup;
@@ -396,7 +416,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, unsig
}
}
- ret = str_append_str(&str, login_msg_end);
+ ret = str_append_str(&str, login_end);
if (ret < 0) {
ret = -1;
goto cleanup;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a99746cc..7e14e037 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -96,7 +96,7 @@ dist_check_SCRIPTS += test-pass test-pass-cert test-cert test-group-pass \
test-enc-key test-sighup-key-change test-get-cert test-san-cert \
test-gssapi test-pass-opt-cert test-cert-opt-pass test-gssapi-opt-pass \
test-gssapi-opt-cert haproxy-auth test-maintenance \
- test-group-name flowcontrol
+ test-group-name flowcontrol banner
if HAVE_CWRAP_PAM
dist_check_SCRIPTS += test-pam test-pam-noauth
diff --git a/tests/banner b/tests/banner
new file mode 100755
index 00000000..e43fc7a8
--- /dev/null
+++ b/tests/banner
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# Copyright (C) 2013 Nikos Mavrogiannopoulos
+#
+# This file is part of ocserv.
+#
+# ocserv is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at
+# your option) any later version.
+#
+# ocserv 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# tests whether the pre-login-banner is printed
+
+SERV="${SERV:-../src/ocserv}"
+srcdir=${srcdir:-.}
+NO_NEED_ROOT=1
+PORT=4173
+TMPFILE=ocserv-plbanner.$$.tmp
+PIDFILE=ocserv-pid.$$.tmp
+
+. `dirname $0`/common.sh
+
+function finish {
+ set +e
+ echo " * Cleaning up..."
+ test -n "${PIDFILE}" && test -f "${PIDFILE}" && kill $(cat ${PIDFILE}) >/dev/null 2>&1
+ test -n "${PIDFILE}" && rm -f ${PIDFILE} >/dev/null 2>&1
+ test -n "${CONFIG}" && rm -f ${CONFIG} >/dev/null 2>&1
+ test -n "${TMPFILE}" && rm -f ${TMPFILE} >/dev/null 2>&1
+}
+trap finish EXIT
+
+echo "Testing banner printing... "
+
+update_config test1.config
+launch_sr_server -d 1 -p ${PIDFILE} -f -c ${CONFIG} & PID=$!
+wait_server $PID
+
+sleep 3
+
+echo "Connecting to obtain cookie... "
+( echo "test" | LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT $ADDRESS:$PORT -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly >${TMPFILE} 2>&1 ) ||
+ fail $PID "Could not receive cookie from server"
+
+grep "AN UNPREDICTABLE BANNER" ${TMPFILE} >/dev/null
+if test $? != 0;then
+ echo "The banner was not printed"
+ cat $TMPFILE
+ exit 1
+fi
+
+echo "Connecting to obtain cookie with wrong password... "
+( echo "tost" | LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT $ADDRESS:$PORT -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly >${TMPFILE} 2>&1 ) &&
+ fail $PID "Received cookie when we shouldn't"
+
+grep "AN UNPREDICTABLE BANNER" ${TMPFILE} >/dev/null
+if test $? != 0;then
+ echo "The banner was not printed"
+ cat $TMPFILE
+ exit 1
+fi
+
+exit 0
diff --git a/tests/data/test1.config b/tests/data/test1.config
index 251a822b..cce0a376 100644
--- a/tests/data/test1.config
+++ b/tests/data/test1.config
@@ -12,6 +12,8 @@ max-ban-score = 0
# A banner to be displayed on clients
#banner = "Welcome"
+pre-login-banner = "AN UNPREDICTABLE BANNER"
+
# Use listen-host to limit to specific IPs or to the IPs of a provided hostname.
#listen-host = [IP|HOSTNAME]
@@ -107,12 +109,6 @@ auth-timeout = 40
# a failed authentication attempt.
#min-reauth-time = 2
-# Cookie validity time (in seconds)
-# Once a client is authenticated he's provided a cookie with
-# which he can reconnect. This option sets the maximum lifetime
-# of that cookie.
-cookie-validity = 172800
-
# Script to call when a client connects and obtains an IP
# Parameters are passed on the environment.
# REASON, USERNAME, GROUPNAME, HOSTNAME (the hostname selected by client),
@@ -122,12 +118,6 @@ cookie-validity = 172800
#connect-script = /usr/bin/myscript
#disconnect-script = /usr/bin/myscript
-# UTMP
-use-utmp = true
-
-# PID file
-pid-file = ./ocserv.pid
-
# The default server directory. Does not require any devices present.
#chroot-dir = /path/to/chroot