From 5ca0c730a1633ff8e6b8b5d194c5e422cb62cf69 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Fri, 28 Oct 2016 13:48:22 +0300 Subject: [PATCH] MXS-960: In BRL, accept passwords with "," in them. strtok_r replaced with a function that ignores delims that appear within any of the MySQL quotes. --- server/modules/routing/binlog/blr_slave.c | 155 +++++++++++++++++++++- 1 file changed, 149 insertions(+), 6 deletions(-) diff --git a/server/modules/routing/binlog/blr_slave.c b/server/modules/routing/binlog/blr_slave.c index c6b851904..f42606ac2 100644 --- a/server/modules/routing/binlog/blr_slave.c +++ b/server/modules/routing/binlog/blr_slave.c @@ -84,6 +84,7 @@ #include #include +static char* get_next_token(char *str, const char* delim, char **saveptr); extern int load_mysql_users(SERVICE *service); extern void blr_master_close(ROUTER_INSTANCE* router); extern int blr_file_new_binlog(ROUTER_INSTANCE *router, char *file); @@ -4282,6 +4283,148 @@ blr_set_master_password(ROUTER_INSTANCE *router, char *password) return 0; } +/** + * Get next token + * + * Works exactly like strtok_t except that a delim character which appears + * anywhere within quotes is ignored. For instance, if delim is "," then + * a string like "MASTER_USER='maxscale_repl_user',MASTER_PASSWORD='a,a'" + * will be tokenized into the following two tokens: + * + * MASTER_USER='maxscale_repl_user' + * MASTER_PASSWORD='a,a' + * + * @see strtok_r + */ +static char* get_next_token(char *str, const char* delim, char **saveptr) +{ + if (str) + { + *saveptr = str; + } + + if (!*saveptr) + { + return NULL; + } + + bool delim_found = true; + + // Skip any delims in the beginning. + while (**saveptr && delim_found) + { + const char* d = delim; + + while (*d) + { + if (*d == **saveptr) + { + break; + } + + ++d; + } + + if (*d == 0) + { + delim_found = false; + } + else + { + ++*saveptr; + } + } + + if (!**saveptr) + { + return NULL; + } + + delim_found = false; + + char *token = *saveptr; + char *p = *saveptr; + + char quote = 0; + + while (*p && !delim_found) + { + switch (*p) + { + case '\'': + case '"': + case '`': + if (!quote) + { + quote = *p; + } + else if (quote == *p) + { + quote = 0; + } + break; + + default: + if (!quote) + { + const char *d = delim; + while (*d && !delim_found) + { + if (*p == *d) + { + delim_found = true; + *p = 0; + } + else + { + ++d; + } + } + } + } + + ++p; + } + + if (*p == 0) + { + *saveptr = NULL; + } + else if (delim_found) + { + *saveptr = p; + + delim_found = true; + + while (**saveptr && delim_found) + { + const char *d = delim; + while (*d) + { + if (**saveptr == *d) + { + break; + } + else + { + ++d; + } + } + + if (*d == 0) + { + delim_found = false; + } + else + { + ++*saveptr; + } + } + } + + return token; +} + /** * Parse a CHANGE MASTER TO SQL command * @@ -4296,7 +4439,7 @@ blr_parse_change_master_command(char *input, char *error_string, CHANGE_MASTER_O char *sep = ","; char *word, *brkb; - if ((word = strtok_r(input, sep, &brkb)) == NULL) + if ((word = get_next_token(input, sep, &brkb)) == NULL) { sprintf(error_string, "Unable to parse query [%s]", input); return 1; @@ -4310,7 +4453,7 @@ blr_parse_change_master_command(char *input, char *error_string, CHANGE_MASTER_O } } - while ((word = strtok_r(NULL, sep, &brkb)) != NULL) + while ((word = get_next_token(NULL, sep, &brkb)) != NULL) { /* parse options key=val */ if (blr_handle_change_master_token(word, error_string, config)) @@ -4334,12 +4477,12 @@ static int blr_handle_change_master_token(char *input, char *error, CHANGE_MASTER_OPTIONS *config) { /* space+TAB+= */ - char *sep = " ="; + char *sep = " \t="; char *word, *brkb; char *value = NULL; char **option_field = NULL; - if ((word = strtok_r(input, sep, &brkb)) == NULL) + if ((word = get_next_token(input, sep, &brkb)) == NULL) { sprintf(error, "error parsing %s", brkb); return 1; @@ -4378,7 +4521,7 @@ static char * blr_get_parsed_command_value(char *input) { /* space+TAB+= */ - char *sep = " ="; + char *sep = " \t="; char *ret = NULL; char *word; char *value = NULL; @@ -4392,7 +4535,7 @@ blr_get_parsed_command_value(char *input) return ret; } - if ((word = strtok_r(NULL, sep, &input)) != NULL) + if ((word = get_next_token(NULL, sep, &input)) != NULL) { char *ptr;