to.auth_user_pass_verify_script = options->auth_user_pass_verify_script;
to.auth_user_pass_verify_script_via_file = options->auth_user_pass_verify_script_via_file;
to.tmp_dir = options->tmp_dir;
- to.username_as_common_name = options->username_as_common_name;
+ to.ssl_flags = options->ssl_flags;
if (options->ccd_exclusive)
to.client_config_dir_exclusive = options->client_config_dir;
#endif
[\ \fB\-\-askpass\fR\ \fI[file]\fR\ ]
[\ \fB\-\-auth\-nocache\fR\ ]
[\ \fB\-\-auth\-retry\fR\ \fItype\fR\ ]
+[\ \fB\-\-auth\-user\-pass\-optional\fR\ ]
[\ \fB\-\-auth\-user\-pass\-verify\fR\ \fIscript\fR\ ]
[\ \fB\-\-auth\-user\-pass\fR\ \fIup\fR\ ]
[\ \fB\-\-auth\fR\ \fIalg\fR\ ]
in the OpenVPN source distribution.
.\"*********************************************************
.TP
+.B --auth-user-pass-optional
+Allow connections by clients that do not specify a username/password.
+Normally, when
+.B --auth-user-pass-verify
+or
+.B --management-client-auth
+is specified (or an authentication plugin module), the
+OpenVPN server daemon will require connecting clients to specify a
+username and password. This option makes the submission of a username/password
+by clients optional, passing the responsibility to the user-defined authentication
+module/script to accept or deny the client based on other factors
+(such as the setting of X509 certificate fields). When this option is used,
+and a connecting client does not submit a username/password, the user-defined
+authentication module/script will see the username and password as being set
+to empty strings (""). The authentication module/script MUST have logic
+to detect this condition and respond accordingly.
+.\"*********************************************************
+.TP
.B --client-cert-not-required
Don't require client certificate, client will authenticate
using username/password only. Be aware that using this directive
" run script cmd to verify. If method='via-env', pass\n"
" user/pass via environment, if method='via-file', pass\n"
" user/pass via temporary file.\n"
+ "--auth-user-pass-optional : Allow connections by clients that don't\n"
+ " specify a username/password.\n"
"--client-to-client : Internally route client-to-client traffic.\n"
"--duplicate-cn : Allow multiple clients with the same common name to\n"
" concurrently connect.\n"
SHOW_INT (cf_per);
SHOW_INT (max_clients);
SHOW_INT (max_routes_per_client);
- SHOW_BOOL (client_cert_not_required);
- SHOW_BOOL (username_as_common_name)
SHOW_STR (auth_user_pass_verify_script);
SHOW_BOOL (auth_user_pass_verify_script_via_file);
+ SHOW_INT (ssl_flags);
#if PORT_SHARE
SHOW_STR (port_share_host);
SHOW_INT (port_share_port);
|| PLUGIN_OPTION_LIST (options)
|| MAN_CLIENT_AUTH_ENABLED (options));
const char *postfix = "must be used with --management-client-auth, an --auth-user-pass-verify script, or plugin";
- if (options->client_cert_not_required && !ccnr)
+ if ((options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) && !ccnr)
msg (M_USAGE, "--client-cert-not-required %s", postfix);
- if (options->username_as_common_name && !ccnr)
+ if ((options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && !ccnr)
msg (M_USAGE, "--username-as-common-name %s", postfix);
+ if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr)
+ msg (M_USAGE, "--auth-user-pass-optional %s", postfix);
}
}
else
msg (M_USAGE, "--duplicate-cn requires --mode server");
if (options->cf_max || options->cf_per)
msg (M_USAGE, "--connect-freq requires --mode server");
- if (options->client_cert_not_required)
+ if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
msg (M_USAGE, "--client-cert-not-required requires --mode server");
- if (options->username_as_common_name)
+ if (options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)
msg (M_USAGE, "--username-as-common-name requires --mode server");
+ if (options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL)
+ msg (M_USAGE, "--auth-user-pass-optional requires --mode server");
if (options->auth_user_pass_verify_script)
msg (M_USAGE, "--auth-user-pass-verify requires --mode server");
#if PORT_SHARE
else if (streq (p[0], "client-cert-not-required"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- options->client_cert_not_required = true;
+ options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED;
}
else if (streq (p[0], "username-as-common-name"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- options->username_as_common_name = true;
+ options->ssl_flags |= SSLF_USERNAME_AS_COMMON_NAME;
+ }
+ else if (streq (p[0], "auth-user-pass-optional"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL;
}
else if (streq (p[0], "auth-user-pass-verify") && p[1])
{
int max_clients;
int max_routes_per_client;
- bool client_cert_not_required;
- bool username_as_common_name;
const char *auth_user_pass_verify_script;
bool auth_user_pass_verify_script_via_file;
+ unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */
#if PORT_SHARE
char *port_share_host;
int port_share_port;
/* Require peer certificate verification */
#if P2MP_SERVER
- if (options->client_cert_not_required)
+ if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
{
msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION --client-cert-not-required may accept clients which do not present a certificate");
}
bool ret = false;
/* Is username defined? */
- if (strlen (up->username))
+ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
{
/* Set environmental variables prior to calling script */
setenv_str (session->opt->es, "script_type", "user-pass-verify");
int retval = OPENVPN_PLUGIN_FUNC_ERROR;
/* Is username defined? */
- if (strlen (up->username))
+ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
{
/* set username/password in private env space */
setenv_str (session->opt->es, "username", raw_username);
int retval = KMDA_ERROR;
/* Is username defined? */
- if (strlen (up->username))
+ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
{
/* set username/password in private env space */
setenv_str (session->opt->es, "username", raw_username);
if (!read_string (buf, up->username, USER_PASS_LEN)
|| !read_string (buf, up->password, USER_PASS_LEN))
{
- msg (D_TLS_ERRORS, "TLS Error: Auth Username/Password was not provided by peer");
CLEAR (*up);
- goto error;
+ if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: Auth Username/Password was not provided by peer");
+ goto error;
+ }
}
/* preserve raw username before string_mod remapping, for plugins */
s2 = verify_user_pass_script (session, up);
/* check sizing of username if it will become our common name */
- if (session->opt->username_as_common_name && strlen (up->username) >= TLS_CN_LEN)
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_CN_LEN)
{
msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_CN_LEN);
s1 = OPENVPN_PLUGIN_FUNC_ERROR;
ks->auth_deferred = true;
#endif
- if (session->opt->username_as_common_name)
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
set_common_name (session, up->username);
msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
#ifdef ENABLE_DEF_AUTH
"succeeded",
#endif
up->username,
- session->opt->username_as_common_name ? "[CN SET]" : "");
+ (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
}
else
{
const char *auth_user_pass_verify_script;
bool auth_user_pass_verify_script_via_file;
const char *tmp_dir;
- bool username_as_common_name;
/* use the client-config-dir as a positive authenticator */
const char *client_config_dir_exclusive;
struct env_set *es;
const struct plugin_list *plugins;
+ /* configuration file boolean options */
+# define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0)
+# define SSLF_USERNAME_AS_COMMON_NAME (1<<1)
+# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2)
+ unsigned int ssl_flags;
+
#ifdef MANAGEMENT_DEF_AUTH
struct man_def_auth_context *mda_context;
#endif