]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Expose more TLS options in MySQL driver 2481/head
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 11 Feb 2019 04:26:52 +0000 (09:56 +0530)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 12 Feb 2019 15:52:17 +0000 (17:52 +0200)
Availability of TLS and reconnect options in MySQL driver checked by using MySQL version instead of ifdefs

src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c

index 2b05db8182fc995fb09957e7b962f5e04b6436c3..1be5ebf36bafa7529de0439b411bc4d1ab4bcadd 100644 (file)
@@ -45,6 +45,20 @@ RCSID("$Id$")
 #  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;
@@ -69,14 +83,24 @@ typedef struct rlm_sql_mysql_conn {
 } 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;
@@ -87,10 +111,30 @@ static CONF_PARSER tls_config[] = {
        { "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
 };
 
@@ -119,6 +163,23 @@ static int _mod_destructor(UNUSED rlm_sql_mysql_config_t *driver)
 {
        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;
 }
 
@@ -186,13 +247,41 @@ static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *c
                              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);