# include <mysqld_error.h>
#endif
+#if (MYSQL_VERSION_ID >= 50555) && (MYSQL_VERSION_ID < 50600)
+#define HAVE_TLS_OPTIONS 1
+#define HAVE_CRL_OPTIONS 0
+#define HAVE_TLS_VERIFY_OPTIONS 0
+#elif (MYSQL_VERSION_ID >= 50636) && (MYSQL_VERSION_ID < 50700)
+#define HAVE_TLS_OPTIONS 1
+#define HAVE_CRL_OPTIONS 1
+#define HAVE_TLS_VERIFY_OPTIONS 0
+#elif MYSQL_VERSION_ID >= 50700
+#define HAVE_TLS_OPTIONS 1
+#define HAVE_CRL_OPTIONS 1
+#define HAVE_TLS_VERIFY_OPTIONS 1
+#endif
+
#include "rlm_sql.h"
static int mysql_instance_count = 0;
} rlm_sql_mysql_conn_t;
typedef struct rlm_sql_mysql_config {
- char const *tls_ca_file; //!< Path to the CA used to validate the server's certificate.
- char const *tls_ca_path; //!< Directory containing CAs that may be used to validate the
+ char const *tls_ca_file; //!< Path to the CA used to validate the server's certificate.
+ char const *tls_ca_path; //!< Directory containing CAs that may be used to validate the
//!< servers certificate.
- char const *tls_certificate_file; //!< Public certificate we present to the server.
- char const *tls_private_key_file; //!< Private key for the certificate we present to the server.
- char const *tls_cipher;
+ char const *tls_certificate_file; //!< Public certificate we present to the server.
+ char const *tls_private_key_file; //!< Private key for the certificate we present to the server.
+
+ char const *tls_crl_file; //!< Public certificate we present to the server.
+ char const *tls_crl_path; //!< Private key for the certificate we present to the server.
+
+ char const *tls_cipher; //!< Colon separated list of TLS ciphers for TLS <= 1.2.
- char const *warnings_str; //!< Whether we always query the server for additional warnings.
+ bool tls_required; //!< Require that the connection is encrypted.
+ bool tls_check_cert; //!< Verify there's a trust relationship between the server's
+ ///< cert and one of the CAs we have configured.
+ bool tls_check_cert_cn; //!< Verify that the CN in the server cert matches the host
+ ///< we passed to mysql_real_connect().
+
+ char const *warnings_str; //!< Whether we always query the server for additional warnings.
rlm_sql_mysql_warnings warnings; //!< mysql_warning_count() doesn't
//!< appear to work with NDB cluster
} rlm_sql_mysql_config_t;
{ "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_certificate_file), NULL },
{ "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_private_key_file), NULL },
+#if HAVE_CRL_OPTIONS
+ { "crl_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_crl_file), NULL },
+ { "crl_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_crl_path), NULL },
+#endif
/*
* MySQL Specific TLS attributes
*/
{ "cipher", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_mysql_config_t, tls_cipher), NULL },
+
+ /*
+ * The closest thing we have to these options in other modules is
+ * in rlm_rest. rlm_ldap has its own bizarre option set.
+ *
+ * There, the options can be toggled independently, here they can't
+ * but for consistency we break them out anyway, and warn if the user
+ * has provided an invalid list of flags.
+ */
+#if HAVE_TLS_OPTIONS
+ { "tls_required", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mysql_config_t, tls_required), "no" },
+# if HAVE_TLS_VERIFY_OPTIONS
+ { "check_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mysql_config_t, tls_check_cert), "no" },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mysql_config_t, tls_check_cert_cn), "no" },
+# endif
+#endif
CONF_PARSER_TERMINATOR
};
{
if (--mysql_instance_count == 0) mysql_library_end();
+#if HAVE_TLS_VERIFY_OPTIONS
+ if (driver->tls_check_cert && !driver->tls_required) {
+ WARN("Implicitly setting tls_required = yes, as tls_check_cert = yes");
+ driver->tls_required = true;
+ }
+ if (driver->tls_check_cert_cn) {
+ if (!driver->tls_required) {
+ WARN("Implicitly setting tls_required = yes, as check_cert_cn = yes");
+ driver->tls_required = true;
+ }
+
+ if (!driver->tls_check_cert) {
+ WARN("Implicitly setting check_cert = yes, as check_cert_cn = yes");
+ driver->tls_check_cert = true;
+ }
+ }
+#endif
return 0;
}
driver->tls_ca_file, driver->tls_ca_path, driver->tls_cipher);
}
+#if HAVE_TLS_OPTIONS
+ {
+ unsigned int ssl_mode = 0;
+ bool ssl_mode_isset = false;
+
+ if (driver->tls_required) {
+ ssl_mode = SSL_MODE_REQUIRED;
+ ssl_mode_isset = true;
+ }
+# if HAVE_TLS_VERIFY_OPTIONS
+ if (driver->tls_check_cert) {
+ ssl_mode = SSL_MODE_VERIFY_CA;
+ ssl_mode_isset = true;
+ }
+ if (driver->tls_check_cert_cn) {
+ ssl_mode = SSL_MODE_VERIFY_IDENTITY;
+ ssl_mode_isset = true;
+ }
+# endif
+ if (ssl_mode_isset) mysql_options(&(conn->db), MYSQL_OPT_SSL_MODE, &ssl_mode);
+ }
+#endif
+
+#if HAVE_CRL_OPTIONS
+ if (driver->tls_crl_file) mysql_options(&(conn->db), MYSQL_OPT_SSL_CRL, driver->tls_crl_file);
+ if (driver->tls_crl_path) mysql_options(&(conn->db), MYSQL_OPT_SSL_CRLPATH, driver->tls_crl_path);
+#endif
+
mysql_options(&(conn->db), MYSQL_READ_DEFAULT_GROUP, "freeradius");
/*
* We need to know about connection errors, and are capable
* of reconnecting automatically.
*/
-#ifdef MYSQL_OPT_RECONNECT
+#if MYSQL_VERSION_ID >= 50013
{
int reconnect = 0;
mysql_options(&(conn->db), MYSQL_OPT_RECONNECT, &reconnect);