From d938f0e72fb9238afdcd7c2bb144a0c0e8e4c87e Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 18 Oct 2016 10:40:06 +0300 Subject: [PATCH] Add custom cache directory for MySQLAuth The MySQLAuth authenticator can now store the cached credentials in a custom location. This is intended for the binlogrouter, which currently uses a different location for the user cache. The MySQL authentication modules now have their own document in the Authenticators directory. Right now this document only describes the general details of the MySQL authentication and the new option. --- .../Authenticators/MySQL-Authenticator.md | 34 ++++++++ server/modules/authenticator/mysql_auth.c | 84 +++++++++++++++++-- 2 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 Documentation/Authenticators/MySQL-Authenticator.md diff --git a/Documentation/Authenticators/MySQL-Authenticator.md b/Documentation/Authenticators/MySQL-Authenticator.md new file mode 100644 index 000000000..aee19d778 --- /dev/null +++ b/Documentation/Authenticators/MySQL-Authenticator.md @@ -0,0 +1,34 @@ +# MySQL Authenticator + +The _MySQLAuth_ and _MySQLBackendAuth_ modules implement the client and +backend authentication for the MySQL native password authentication. This +is the default authentication plugin used by both MariaDB and MySQL. + +These modules are the default authenticators for all MySQL connections and +needs no further configuration to work. + +## Authenticator options + +The client authentication module, _MySQLAuth_, supports authenticator options. + +### `cache_dir` + +The location where the user credential cache is stored. The default value +for this is `///cache/` where +`` by default is `/var/cache`. + +Each listener has its own user cache where the user credential information +queried from the backends is stored. This information is used to +authenticate users if a connection to the backend servers can't be made. + +#### Example configuration + +``` +[Read-Write Listener] +type=listener +service=Read-Write Service +protocol=MySQLClient +port=4006 +authenticator=MySQLAuth +authenticator_options=cache_dir=/tmp +``` diff --git a/server/modules/authenticator/mysql_auth.c b/server/modules/authenticator/mysql_auth.c index 6e5710736..9e0cb9214 100644 --- a/server/modules/authenticator/mysql_auth.c +++ b/server/modules/authenticator/mysql_auth.c @@ -35,6 +35,12 @@ #include #include +typedef struct mysql_auth +{ + char *cache_dir; /**< Custom cache directory location */ +} MYSQL_AUTH; + + /* @see function load_module in load_utils.c for explanation of the following * lint directives. */ @@ -50,6 +56,7 @@ MODULE_INFO info = static char *version_str = "V1.1.0"; +static void* mysql_auth_init(char **options); static int mysql_auth_set_protocol_data(DCB *dcb, GWBUF *buf); static bool mysql_auth_is_client_ssl_capable(DCB *dcb); static int mysql_auth_authenticate(DCB *dcb); @@ -61,7 +68,7 @@ static int mysql_auth_load_users(SERV_LISTENER *port); */ static GWAUTHENTICATOR MyObject = { - NULL, /* No initialize entry point */ + mysql_auth_init, /* Initialize the authenticator */ NULL, /* No create entry point */ mysql_auth_set_protocol_data, /* Extract data into structure */ mysql_auth_is_client_ssl_capable, /* Check if client supports SSL */ @@ -121,6 +128,60 @@ GWAUTHENTICATOR* GetModuleObject() } /*lint +e14 */ +/** + * @brief Initialize the authenticator instance + * + * @param options Authenticator options + * @return New MYSQL_AUTH instance or NULL on error + */ +static void* mysql_auth_init(char **options) +{ + MYSQL_AUTH *instance = MXS_MALLOC(sizeof(*instance)); + + if (instance) + { + bool error = false; + instance->cache_dir = NULL; + + for (int i = 0; options[i]; i++) + { + char *value = strchr(options[i], '='); + + if (value) + { + *value++ = '\0'; + + if (strcmp(options[i], "cache_dir") == 0) + { + if ((instance->cache_dir = MXS_STRDUP(value)) == NULL) + { + error = true; + } + } + else + { + MXS_ERROR("Unknown authenticator option: %s", options[i]); + error = true; + } + } + else + { + MXS_ERROR("Unknown authenticator option: %s", options[i]); + error = true; + } + } + + if (error) + { + MXS_FREE(instance->cache_dir); + MXS_FREE(instance); + instance = NULL; + } + } + + return instance; +} + /** * @brief Authenticates a MySQL user who is a client to MaxScale. * @@ -781,21 +842,29 @@ static int mysql_auth_load_users(SERV_LISTENER *port) { int rc = MXS_AUTH_LOADUSERS_OK; SERVICE *service = port->listener->service; + MYSQL_AUTH *instance = (MYSQL_AUTH*)port->auth_instance; int loaded = replace_mysql_users(port); + char path[PATH_MAX]; + + if (instance->cache_dir) + { + strcpy(path, instance->cache_dir); + } + else + { + sprintf(path, "%s/%s/%s/%s/", get_cachedir(), service->name, port->name, DBUSERS_DIR); + } if (loaded < 0) { MXS_ERROR("[%s] Unable to load users for listener %s listening at %s:%d.", service->name, port->name, port->address ? port->address : "0.0.0.0", port->port); - /* Try loading authentication data from file cache */ - char path[PATH_MAX]; - sprintf(path, "%s/%s/%s/%s/%s", get_cachedir(), service->name, port->name, - DBUSERS_DIR, DBUSERS_FILE); + strcat(path, DBUSERS_FILE); if ((loaded = dbusers_load(port->users, path)) == -1) { - MXS_ERROR("[%s] Failed to load cached users from '%s'.", service->name, path);; + MXS_ERROR("[%s] Failed to load cached users from '%s'.", service->name, path); rc = MXS_AUTH_LOADUSERS_ERROR; } else @@ -806,9 +875,6 @@ static int mysql_auth_load_users(SERV_LISTENER *port) else { /* Users loaded successfully, save authentication data to file cache */ - char path[PATH_MAX]; - sprintf(path, "%s/%s/%s/%s/", get_cachedir(), service->name, port->name, DBUSERS_DIR); - if (mxs_mkdir_all(path, 0777)) { strcat(path, DBUSERS_FILE);