diff options
-rw-r--r-- | init.c | 2 | ||||
-rw-r--r-- | openvpn.8 | 19 | ||||
-rw-r--r-- | options.c | 26 | ||||
-rw-r--r-- | options.h | 3 | ||||
-rw-r--r-- | ssl.c | 21 | ||||
-rw-r--r-- | ssl.h | 7 |
6 files changed, 57 insertions, 21 deletions
@@ -1756,7 +1756,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) 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 @@ -102,6 +102,7 @@ openvpn \- secure IP tunnel daemon. [\ \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\ ] @@ -3250,6 +3251,24 @@ For a sample script that performs PAM authentication, see 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 @@ -381,6 +381,8 @@ static const char usage_message[] = " 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" @@ -965,10 +967,9 @@ show_p2mp_parms (const struct options *o) 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); @@ -1702,10 +1703,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne || 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 @@ -1735,10 +1738,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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 @@ -4559,12 +4564,17 @@ add_option (struct options *options, 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]) { @@ -385,10 +385,9 @@ struct options 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; @@ -1555,7 +1555,7 @@ init_ssl (const struct options *options) /* 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"); } @@ -2958,7 +2958,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up 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"); @@ -3025,7 +3025,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up 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); @@ -3077,7 +3077,7 @@ verify_user_pass_management (struct tls_session *session, const struct user_pass 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); @@ -3336,9 +3336,12 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi 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 */ @@ -3361,7 +3364,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi 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; @@ -3384,7 +3387,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi 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 @@ -3393,7 +3396,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi "succeeded", #endif up->username, - session->opt->username_as_common_name ? "[CN SET]" : ""); + (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); } else { @@ -456,7 +456,6 @@ struct tls_options 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; @@ -465,6 +464,12 @@ struct tls_options 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 |