Merge branch 'develop' into 1.2.1-binlog_router_trx
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
if(BUILD_TESTS OR BUILD_TOOLS)
|
||||
add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c gwdirs.c externcmd.c)
|
||||
add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c gwdirs.c externcmd.c maxscale_pcre2.c)
|
||||
if(WITH_JEMALLOC)
|
||||
target_link_libraries(fullcore ${JEMALLOC_LIBRARIES})
|
||||
elseif(WITH_TCMALLOC)
|
||||
@ -12,7 +12,7 @@ add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c
|
||||
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c
|
||||
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c
|
||||
monitor.c adminusers.c secrets.c filter.c modutil.c hint.c
|
||||
housekeeper.c memlog.c resultset.c gwdirs.c externcmd.c)
|
||||
housekeeper.c memlog.c resultset.c gwdirs.c externcmd.c maxscale_pcre2.c)
|
||||
|
||||
if(WITH_JEMALLOC)
|
||||
target_link_libraries(maxscale ${JEMALLOC_LIBRARIES})
|
||||
|
||||
@ -75,6 +75,9 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <pcre.h>
|
||||
#include <dbusers.h>
|
||||
#include <gw.h>
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
|
||||
/** According to the PCRE manual, this should be a multiple of 3 */
|
||||
#define MAXSCALE_PCRE_BUFSZ 24
|
||||
@ -95,12 +98,14 @@ static int handle_feedback_item(const char *, const char *);
|
||||
static void global_defaults();
|
||||
static void feedback_defaults();
|
||||
static void check_config_objects(CONFIG_CONTEXT *context);
|
||||
static int maxscale_getline(char** dest, int* size, FILE* file);
|
||||
int config_truth_value(char *str);
|
||||
bool isInternalService(char *router);
|
||||
int config_get_ifaddr(unsigned char *output);
|
||||
int config_get_release_string(char* release);
|
||||
FEEDBACK_CONF * config_get_feedback_data();
|
||||
void config_add_param(CONFIG_CONTEXT*,char*,char*);
|
||||
bool config_has_duplicate_sections(const char* config);
|
||||
static char *config_file = NULL;
|
||||
static GATEWAY_CONF gateway;
|
||||
static FEEDBACK_CONF feedback;
|
||||
@ -274,6 +279,10 @@ config_load(char *file)
|
||||
CONFIG_CONTEXT config;
|
||||
int rval, ini_rval;
|
||||
|
||||
if (config_has_duplicate_sections(file))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
MYSQL *conn;
|
||||
conn = mysql_init(NULL);
|
||||
if (conn) {
|
||||
@ -356,6 +365,11 @@ int rval;
|
||||
if (!config_file)
|
||||
return 0;
|
||||
|
||||
if (config_has_duplicate_sections(config_file))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gateway.version_string)
|
||||
free(gateway.version_string);
|
||||
|
||||
@ -1541,7 +1555,16 @@ handle_global_item(const char *name, const char *value)
|
||||
int i;
|
||||
if (strcmp(name, "threads") == 0)
|
||||
{
|
||||
gateway.n_threads = atoi(value);
|
||||
int thrcount = atoi(value);
|
||||
if (thrcount > 0)
|
||||
{
|
||||
gateway.n_threads = thrcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Warning: Invalid value for 'threads': %s.", value);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (strcmp(name, "non_blocking_polls") == 0)
|
||||
{
|
||||
@ -1644,7 +1667,7 @@ global_defaults()
|
||||
{
|
||||
uint8_t mac_addr[6]="";
|
||||
struct utsname uname_data;
|
||||
gateway.n_threads = 1;
|
||||
gateway.n_threads = get_processor_count();
|
||||
gateway.n_nbpoll = DEFAULT_NBPOLLS;
|
||||
gateway.pollsleep = DEFAULT_POLLSLEEP;
|
||||
gateway.auth_conn_timeout = DEFAULT_AUTH_CONNECT_TIMEOUT;
|
||||
@ -2629,3 +2652,137 @@ GATEWAY_CONF* config_get_global_options()
|
||||
{
|
||||
return &gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if sections are defined multiple times in the configuration file.
|
||||
* @param config Path to the configuration file
|
||||
* @return True if duplicate sections were found or an error occurred
|
||||
*/
|
||||
bool config_has_duplicate_sections(const char* config)
|
||||
{
|
||||
bool rval = false;
|
||||
const int table_size = 10;
|
||||
int errcode;
|
||||
PCRE2_SIZE erroffset;
|
||||
HASHTABLE *hash = hashtable_alloc(table_size, simple_str_hash, strcmp);
|
||||
pcre2_code *re = pcre2_compile((PCRE2_SPTR) "^\\s*\\[(.+)\\]\\s*$", PCRE2_ZERO_TERMINATED,
|
||||
0, &errcode, &erroffset, NULL);
|
||||
pcre2_match_data *mdata;
|
||||
int size = 1024;
|
||||
char *buffer = malloc(size * sizeof(char));
|
||||
|
||||
if (buffer && hash && re &&
|
||||
(mdata = pcre2_match_data_create_from_pattern(re, NULL)))
|
||||
{
|
||||
hashtable_memory_fns(hash, (HASHMEMORYFN) strdup, NULL,
|
||||
(HASHMEMORYFN) free, NULL);
|
||||
FILE* file = fopen(config, "r");
|
||||
|
||||
if (file)
|
||||
{
|
||||
while (maxscale_getline(&buffer, &size, file) > 0)
|
||||
{
|
||||
if (pcre2_match(re, (PCRE2_SPTR) buffer,
|
||||
PCRE2_ZERO_TERMINATED, 0, 0,
|
||||
mdata, NULL) > 0)
|
||||
{
|
||||
/**
|
||||
* Neither of the PCRE2 calls will fail since we know the pattern
|
||||
* beforehand and we allocate enough memory from the stack
|
||||
*/
|
||||
PCRE2_SIZE len;
|
||||
pcre2_substring_length_bynumber(mdata, 1, &len);
|
||||
len += 1; /** one for the null terminator */
|
||||
PCRE2_UCHAR section[len];
|
||||
pcre2_substring_copy_bynumber(mdata, 1, section, &len);
|
||||
|
||||
if (hashtable_add(hash, section, "") == 0)
|
||||
{
|
||||
skygw_log_write(LE, "Error: Duplicate section found: %s",
|
||||
section);
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
skygw_log_write(LE, "Error: Failed to open file '%s': %s", config,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Error: Failed to allocate enough memory when checking"
|
||||
" for duplicate sections in configuration file.");
|
||||
rval = true;
|
||||
}
|
||||
|
||||
hashtable_free(hash);
|
||||
pcre2_code_free(re);
|
||||
pcre2_match_data_free(mdata);
|
||||
free(buffer);
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from a FILE pointer until a newline character or the end of the file is found.
|
||||
* The provided buffer will be reallocated if it is too small to store the whole
|
||||
* line. The size after the reallocation will be stored in @c size. The read line
|
||||
* will be stored in @c dest and it will always be null terminated. The newline
|
||||
* character will not be copied into the buffer.
|
||||
* @param dest Pointer to a buffer of at least @c size bytes
|
||||
* @param size Size of the buffer
|
||||
* @param file A valid file stream
|
||||
* @return When a complete line was successfully read the function returns 1. If
|
||||
* the end of the file was reached before any characters were read the return value
|
||||
* will be 0. If the provided buffer could not be reallocated to store the complete
|
||||
* line the original size will be retained, everything read up to this point
|
||||
* will be stored in it as a null terminated string and -1 will be returned.
|
||||
*/
|
||||
int maxscale_getline(char** dest, int* size, FILE* file)
|
||||
{
|
||||
char* destptr = *dest;
|
||||
int offset = 0;
|
||||
|
||||
if (feof(file))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (*size <= offset)
|
||||
{
|
||||
char* tmp = (char*) realloc(destptr, *size * 2);
|
||||
if (tmp)
|
||||
{
|
||||
destptr = tmp;
|
||||
*size *= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Error: Failed to reallocate memory from %d"
|
||||
" bytes to %d bytes when reading from file.",
|
||||
*size, *size * 2);
|
||||
destptr[offset - 1] = '\0';
|
||||
*dest = destptr;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((destptr[offset] = fgetc(file)) == '\n' || feof(file))
|
||||
{
|
||||
destptr[offset] = '\0';
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
*dest = destptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -80,6 +80,8 @@
|
||||
#include <hashtable.h>
|
||||
#include <hk_heartbeat.h>
|
||||
|
||||
#define SSL_ERRBUF_LEN 140
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
@ -1480,8 +1482,8 @@ dcb_write_SSL_error_report (DCB *dcb, int ret, int ssl_errno)
|
||||
}
|
||||
do
|
||||
{
|
||||
char errbuf[140];
|
||||
ERR_error_string_n(ssl_errno,errbuf,140);
|
||||
char errbuf[SSL_ERRBUF_LEN];
|
||||
ERR_error_string_n(ssl_errno,errbuf, sizeof(errbuf));
|
||||
skygw_log_write(LE,"%d:%s",ssl_errno,errbuf);
|
||||
} while((ssl_errno = ERR_get_error()) != 0);
|
||||
}
|
||||
@ -1490,8 +1492,8 @@ dcb_write_SSL_error_report (DCB *dcb, int ret, int ssl_errno)
|
||||
{
|
||||
do
|
||||
{
|
||||
char errbuf[140];
|
||||
ERR_error_string_n(ssl_errno,errbuf,140);
|
||||
char errbuf[SSL_ERRBUF_LEN];
|
||||
ERR_error_string_n(ssl_errno,errbuf,sizeof(errbuf));
|
||||
skygw_log_write(LE,"%d:%s",ssl_errno,errbuf);
|
||||
} while((ssl_errno = ERR_get_error()) != 0);
|
||||
}
|
||||
@ -1646,8 +1648,8 @@ dcb_drain_writeq_SSL(DCB *dcb)
|
||||
case SSL_ERROR_SYSCALL:
|
||||
while((ssl_errno = ERR_get_error()) != 0)
|
||||
{
|
||||
char errbuf[140];
|
||||
ERR_error_string_n(ssl_errno,errbuf,140);
|
||||
char errbuf[SSL_ERRBUF_LEN];
|
||||
ERR_error_string_n(ssl_errno,errbuf,sizeof(errbuf));
|
||||
skygw_log_write(LE,"%s",errbuf);
|
||||
}
|
||||
if(errno != 0)
|
||||
@ -2865,8 +2867,9 @@ int dcb_create_SSL(DCB* dcb)
|
||||
*/
|
||||
int dcb_accept_SSL(DCB* dcb)
|
||||
{
|
||||
int rval = 0,ssl_rval,errnum = 0,fd,b = 0,pending;
|
||||
char errbuf[140];
|
||||
int rval = 0,ssl_rval,ssl_errnum = 0,fd,b = 0,pending;
|
||||
int err_errnum;
|
||||
char errbuf[SSL_ERRBUF_LEN];
|
||||
fd = dcb->fd;
|
||||
|
||||
do
|
||||
@ -2874,22 +2877,20 @@ int dcb_accept_SSL(DCB* dcb)
|
||||
ssl_rval = SSL_accept(dcb->ssl);
|
||||
|
||||
LOGIF(LD,(skygw_log_write_flush(LD,"[dcb_accept_SSL] SSL_accept %d, error %d",
|
||||
ssl_rval,errnum)));
|
||||
ssl_rval,ssl_errnum)));
|
||||
switch(ssl_rval)
|
||||
{
|
||||
case 0:
|
||||
errnum = SSL_get_error(dcb->ssl,ssl_rval);
|
||||
ssl_errnum = SSL_get_error(dcb->ssl,ssl_rval);
|
||||
skygw_log_write(LE,"Error: SSL authentication failed (SSL error %d):",
|
||||
dcb,
|
||||
dcb->remote,
|
||||
errnum);
|
||||
ssl_errnum);
|
||||
|
||||
if(errnum == SSL_ERROR_SSL ||
|
||||
errnum == SSL_ERROR_SYSCALL)
|
||||
if(ssl_errnum == SSL_ERROR_SSL ||
|
||||
ssl_errnum == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
while((errnum = ERR_get_error()) != 0)
|
||||
while((err_errnum = ERR_get_error()) != 0)
|
||||
{
|
||||
ERR_error_string_n(errnum,errbuf,140);
|
||||
ERR_error_string_n(err_errnum,errbuf,sizeof(errbuf));
|
||||
skygw_log_write(LE,"%s",errbuf);
|
||||
}
|
||||
}
|
||||
@ -2903,9 +2904,9 @@ int dcb_accept_SSL(DCB* dcb)
|
||||
|
||||
case -1:
|
||||
|
||||
errnum = SSL_get_error(dcb->ssl,ssl_rval);
|
||||
ssl_errnum = SSL_get_error(dcb->ssl,ssl_rval);
|
||||
|
||||
if(errnum == SSL_ERROR_WANT_READ || errnum == SSL_ERROR_WANT_WRITE)
|
||||
if(ssl_errnum == SSL_ERROR_WANT_READ || ssl_errnum == SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
/** Not all of the data has been read. Go back to the poll
|
||||
queue and wait for more.*/
|
||||
@ -2921,17 +2922,22 @@ int dcb_accept_SSL(DCB* dcb)
|
||||
"Error: Fatal error in SSL_accept for %s: (SSL version: %s SSL error code: %d)",
|
||||
dcb->remote,
|
||||
SSL_get_version(dcb->ssl),
|
||||
errnum);
|
||||
if(errnum == SSL_ERROR_SSL ||
|
||||
errnum == SSL_ERROR_SYSCALL)
|
||||
ssl_errnum);
|
||||
if(ssl_errnum == SSL_ERROR_SSL ||
|
||||
ssl_errnum == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
while((errnum = ERR_get_error()) != 0)
|
||||
while((err_errnum = ERR_get_error()) != 0)
|
||||
{
|
||||
ERR_error_string_n(errnum,errbuf,140);
|
||||
ERR_error_string_n(err_errnum,errbuf,sizeof(errbuf));
|
||||
skygw_log_write(LE,
|
||||
"%s",
|
||||
errbuf);
|
||||
}
|
||||
if(errno)
|
||||
{
|
||||
skygw_log_write(LE, "Error: SSL authentication failed due to system"
|
||||
" error %d: %s", errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2965,7 +2971,7 @@ int dcb_accept_SSL(DCB* dcb)
|
||||
int dcb_connect_SSL(DCB* dcb)
|
||||
{
|
||||
int rval,errnum;
|
||||
char errbuf[140];
|
||||
char errbuf[SSL_ERRBUF_LEN];
|
||||
rval = SSL_connect(dcb->ssl);
|
||||
|
||||
switch(rval)
|
||||
@ -3000,7 +3006,7 @@ int dcb_connect_SSL(DCB* dcb)
|
||||
else
|
||||
{
|
||||
rval = -1;
|
||||
ERR_error_string_n(errnum,errbuf,140);
|
||||
ERR_error_string_n(errnum,errbuf,sizeof(errbuf));
|
||||
skygw_log_write_flush(LE,
|
||||
"Error: Fatal error in SSL_accept for %s@%s: (SSL error code: %d) %s",
|
||||
dcb->user,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -226,3 +226,23 @@ struct hostent *hp;
|
||||
addr->sin_port = htons(pnum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of processors available.
|
||||
* @return Number of processors or 1 if the required definition of _SC_NPROCESSORS_CONF
|
||||
* is not found
|
||||
*/
|
||||
long get_processor_count()
|
||||
{
|
||||
long processors = 1;
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
if ((processors = sysconf(_SC_NPROCESSORS_ONLN)) <= 0)
|
||||
{
|
||||
skygw_log_write(LE, "Unable to establish the number of available cores. Defaulting to 4.");
|
||||
processors = 4;
|
||||
}
|
||||
#else
|
||||
#error _SC_NPROCESSORS_ONLN not available.
|
||||
#endif
|
||||
return processors;
|
||||
}
|
||||
139
server/core/maxscale_pcre2.c
Normal file
139
server/core/maxscale_pcre2.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* This file is distributed as part of the MariaDB Corporation MaxScale. It is free
|
||||
* software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation,
|
||||
* version 2.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright MariaDB Corporation Ab 2015
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file maxscale_pcre2.c - Utility functions for regular expression matching
|
||||
* with the bundled PCRE2 library.
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 30-10-2015 Markus Makela Initial implementation
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#include <maxscale_pcre2.h>
|
||||
|
||||
/**
|
||||
* Utility wrapper for PCRE2 library function call pcre2_substitute.
|
||||
*
|
||||
* This function replaces all occurences of a pattern with the provided replacement
|
||||
* and places the end result into @c dest. This buffer must be allocated by the caller.
|
||||
* If the size of @c dest is not large enough it will be reallocated to a larger size.
|
||||
* The size of @c dest is stored in @c size if any reallocation takes place.
|
||||
*
|
||||
* @param re Compiled pattern to use
|
||||
* @param subject Subject string
|
||||
* @param replace Replacement string
|
||||
* @param dest Destination buffer
|
||||
* @param size Size of the desination buffer
|
||||
* @return MXS_PCRE2_MATCH if replacements were made, MXS_PCRE2_NOMATCH if nothing
|
||||
* was replaced or MXS_PCRE2_ERROR if memory reallocation failed
|
||||
*/
|
||||
mxs_pcre2_result_t mxs_pcre2_substitute(pcre2_code *re, const char *subject, const char *replace,
|
||||
char** dest, size_t* size)
|
||||
{
|
||||
int rc;
|
||||
mxs_pcre2_result_t rval = MXS_PCRE2_ERROR;
|
||||
pcre2_match_data *mdata = pcre2_match_data_create_from_pattern(re, NULL);
|
||||
|
||||
if (mdata)
|
||||
{
|
||||
while ((rc = pcre2_substitute(re, (PCRE2_SPTR) subject, PCRE2_ZERO_TERMINATED, 0,
|
||||
PCRE2_SUBSTITUTE_GLOBAL, mdata, NULL,
|
||||
(PCRE2_SPTR) replace, PCRE2_ZERO_TERMINATED,
|
||||
(PCRE2_UCHAR*) *dest, size)) == PCRE2_ERROR_NOMEMORY)
|
||||
{
|
||||
char *tmp = realloc(*dest, *size * 2);
|
||||
if (tmp == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
*dest = tmp;
|
||||
*size *= 2;
|
||||
}
|
||||
|
||||
if (rc > 0)
|
||||
{
|
||||
rval = MXS_PCRE2_MATCH;
|
||||
}
|
||||
else if (rc == 0)
|
||||
{
|
||||
rval = MXS_PCRE2_NOMATCH;
|
||||
}
|
||||
pcre2_match_data_free(mdata);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a simple matching of a pattern to a string.
|
||||
*
|
||||
* This function compiles the given pattern and checks if the subject string matches
|
||||
* it.
|
||||
* @param pattern Pattern used for matching
|
||||
* @param subject Subject string to match
|
||||
* @param options PCRE2 compilation options
|
||||
* @param error The PCRE2 error code is stored here if one is available
|
||||
* @return MXS_PCRE2_MATCH if @c subject matches @c pattern, MXS_PCRE2_NOMATCH if
|
||||
* they do not match and MXS_PCRE2_ERROR if an error occurred. If an error occurred
|
||||
* within the PCRE2 library, @c error will contain the error code. Otherwise it is
|
||||
* set to 0.
|
||||
*/
|
||||
mxs_pcre2_result_t mxs_pcre2_simple_match(const char* pattern, const char* subject,
|
||||
int options, int *error)
|
||||
{
|
||||
int err;
|
||||
size_t erroff;
|
||||
mxs_pcre2_result_t rval = MXS_PCRE2_ERROR;
|
||||
pcre2_code *re = pcre2_compile((PCRE2_SPTR) pattern, PCRE2_ZERO_TERMINATED,
|
||||
options, &err, &erroff, NULL);
|
||||
if (re)
|
||||
{
|
||||
pcre2_match_data *mdata = pcre2_match_data_create_from_pattern(re, NULL);
|
||||
if (mdata)
|
||||
{
|
||||
int rc = pcre2_match(re, (PCRE2_SPTR) subject, PCRE2_ZERO_TERMINATED,
|
||||
0, 0, mdata, NULL);
|
||||
if (rc == PCRE2_ERROR_NOMATCH)
|
||||
{
|
||||
rval = MXS_PCRE2_NOMATCH;
|
||||
}
|
||||
else if (rc > 0)
|
||||
{
|
||||
/** Since we used the pattern to create the matching data,
|
||||
* pcre2_match will never return 0 */
|
||||
rval = MXS_PCRE2_MATCH;
|
||||
}
|
||||
pcre2_match_data_free(mdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
*error = 0;
|
||||
}
|
||||
pcre2_code_free(re);
|
||||
}
|
||||
else
|
||||
{
|
||||
*error = err;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
@ -38,6 +38,19 @@ extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/** These are used when converting MySQL wildcards to regular expressions */
|
||||
static SPINLOCK re_lock = SPINLOCK_INIT;
|
||||
static bool pattern_init = false;
|
||||
static pcre2_code *re_percent = NULL;
|
||||
static pcre2_code *re_single = NULL;
|
||||
static pcre2_code *re_escape = NULL;
|
||||
static const PCRE2_SPTR pattern_percent = (PCRE2_SPTR) "%";
|
||||
static const PCRE2_SPTR pattern_single = (PCRE2_SPTR) "([^\\\\]|^)_";
|
||||
static const PCRE2_SPTR pattern_escape = (PCRE2_SPTR) "[.]";
|
||||
static const char* sub_percent = ".*";
|
||||
static const char* sub_single = "$1.";
|
||||
static const char* sub_escape = "\\.";
|
||||
|
||||
static void modutil_reply_routing_error(
|
||||
DCB* backend_dcb,
|
||||
int error,
|
||||
@ -842,3 +855,117 @@ int modutil_count_statements(GWBUF* buffer)
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the PCRE2 patterns used when converting MySQL wildcards to PCRE syntax.
|
||||
*/
|
||||
void prepare_pcre2_patterns()
|
||||
{
|
||||
spinlock_acquire(&re_lock);
|
||||
if (!pattern_init)
|
||||
{
|
||||
int err;
|
||||
size_t erroff;
|
||||
PCRE2_UCHAR errbuf[STRERROR_BUFLEN];
|
||||
|
||||
if ((re_percent = pcre2_compile(pattern_percent, PCRE2_ZERO_TERMINATED,
|
||||
0, &err, &erroff, NULL)) &&
|
||||
(re_single = pcre2_compile(pattern_single, PCRE2_ZERO_TERMINATED,
|
||||
0, &err, &erroff, NULL)) &&
|
||||
(re_escape = pcre2_compile(pattern_escape, PCRE2_ZERO_TERMINATED,
|
||||
0, &err, &erroff, NULL)))
|
||||
{
|
||||
assert(!pattern_init);
|
||||
pattern_init = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcre2_get_error_message(err, errbuf, sizeof(errbuf));
|
||||
skygw_log_write(LE, "Error: Failed to compile PCRE2 pattern: %s",
|
||||
errbuf);
|
||||
}
|
||||
|
||||
if (!pattern_init)
|
||||
{
|
||||
pcre2_code_free(re_percent);
|
||||
pcre2_code_free(re_single);
|
||||
pcre2_code_free(re_escape);
|
||||
re_percent = NULL;
|
||||
re_single = NULL;
|
||||
re_escape = NULL;
|
||||
}
|
||||
}
|
||||
spinlock_release(&re_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if @c string matches @c pattern according to the MySQL wildcard rules.
|
||||
* The wildcard character @c '%%' is replaced with @c '.*' and @c '_' is replaced
|
||||
* with @c '.'. All Regular expression special characters are escaped before
|
||||
* matching is made.
|
||||
* @param pattern Wildcard pattern
|
||||
* @param string String to match
|
||||
* @return MXS_PCRE2_MATCH if the pattern matches, MXS_PCRE2_NOMATCH if it does
|
||||
* not match and MXS_PCRE2_ERROR if an error occurred
|
||||
* @see maxscale_pcre2.h
|
||||
*/
|
||||
mxs_pcre2_result_t modutil_mysql_wildcard_match(const char* pattern, const char* string)
|
||||
{
|
||||
prepare_pcre2_patterns();
|
||||
mxs_pcre2_result_t rval = MXS_PCRE2_ERROR;
|
||||
bool err = false;
|
||||
PCRE2_SIZE matchsize = strlen(string) + 1;
|
||||
PCRE2_SIZE tempsize = matchsize;
|
||||
char* matchstr = (char*) malloc(matchsize);
|
||||
char* tempstr = (char*) malloc(tempsize);
|
||||
|
||||
pcre2_match_data *mdata_percent = pcre2_match_data_create_from_pattern(re_percent, NULL);
|
||||
pcre2_match_data *mdata_single = pcre2_match_data_create_from_pattern(re_single, NULL);
|
||||
pcre2_match_data *mdata_escape = pcre2_match_data_create_from_pattern(re_escape, NULL);
|
||||
|
||||
if (matchstr && tempstr && mdata_percent && mdata_single && mdata_escape)
|
||||
{
|
||||
if (mxs_pcre2_substitute(re_escape, pattern, sub_escape,
|
||||
&matchstr, &matchsize) == MXS_PCRE2_ERROR ||
|
||||
mxs_pcre2_substitute(re_single, matchstr, sub_single,
|
||||
&tempstr, &tempsize) == MXS_PCRE2_ERROR ||
|
||||
mxs_pcre2_substitute(re_percent, tempstr, sub_percent,
|
||||
&matchstr, &matchsize) == MXS_PCRE2_ERROR)
|
||||
{
|
||||
err = true;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
int errcode;
|
||||
rval = mxs_pcre2_simple_match(matchstr, string, PCRE2_CASELESS, &errcode);
|
||||
if (rval == MXS_PCRE2_ERROR)
|
||||
{
|
||||
if (errcode != 0)
|
||||
{
|
||||
PCRE2_UCHAR errbuf[STRERROR_BUFLEN];
|
||||
pcre2_get_error_message(errcode, errbuf, sizeof(errbuf));
|
||||
skygw_log_write(LE, "Error: Failed to match pattern: %s",
|
||||
errbuf);
|
||||
}
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = true;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
skygw_log_write(LE, "Error: Fatal error when matching wildcard patterns.");
|
||||
}
|
||||
|
||||
pcre2_match_data_free(mdata_percent);
|
||||
pcre2_match_data_free(mdata_single);
|
||||
pcre2_match_data_free(mdata_escape);
|
||||
free(matchstr);
|
||||
free(tempstr);
|
||||
return rval;
|
||||
}
|
||||
|
||||
@ -471,7 +471,8 @@ serviceStart(SERVICE *service)
|
||||
|
||||
if (check_service_permissions(service))
|
||||
{
|
||||
if (service->ssl_mode == SSL_DISABLED || (service->ssl_mode != SSL_DISABLED && serviceInitSSL(service) != 0))
|
||||
if (service->ssl_mode == SSL_DISABLED ||
|
||||
(service->ssl_mode != SSL_DISABLED && serviceInitSSL(service) == 0))
|
||||
{
|
||||
if ((service->router_instance = service->router->createInstance(
|
||||
service,service->routerOptions)))
|
||||
@ -1999,11 +2000,11 @@ int *data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the servce's SSL context. This sets up the generated RSA
|
||||
* Initialize the service's SSL context. This sets up the generated RSA
|
||||
* encryption keys, chooses the server encryption level and configures the server
|
||||
* certificate, private key and certificate authority file.
|
||||
* @param service
|
||||
* @return
|
||||
* @param service Service to initialize
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int serviceInitSSL(SERVICE* service)
|
||||
{
|
||||
@ -2043,7 +2044,11 @@ int serviceInitSSL(SERVICE* service)
|
||||
break;
|
||||
}
|
||||
|
||||
service->ctx = SSL_CTX_new(service->method);
|
||||
if((service->ctx = SSL_CTX_new(service->method)) == NULL)
|
||||
{
|
||||
skygw_log_write(LE, "Error: SSL context initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Enable all OpenSSL bug fixes */
|
||||
SSL_CTX_set_options(service->ctx,SSL_OP_ALL);
|
||||
@ -2053,13 +2058,19 @@ int serviceInitSSL(SERVICE* service)
|
||||
{
|
||||
rsa_512 = RSA_generate_key(512,RSA_F4,NULL,NULL);
|
||||
if (rsa_512 == NULL)
|
||||
skygw_log_write(LE,"Error: 512-bit RSA key generation failed.");
|
||||
{
|
||||
skygw_log_write(LE,"Error: 512-bit RSA key generation failed.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(rsa_1024 == NULL)
|
||||
{
|
||||
rsa_1024 = RSA_generate_key(1024,RSA_F4,NULL,NULL);
|
||||
if (rsa_1024 == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: 1024-bit RSA key generation failed.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(rsa_512 != NULL && rsa_1024 != NULL)
|
||||
|
||||
Reference in New Issue
Block a user