From fb8212543a2050d616de0abe048a46d9711df907 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Wed, 5 Feb 2014 10:48:52 +0100 Subject: [PATCH 01/10] Fixed issue with MaxScale crash if a configuration unknown section without a type is added. This is Bgzilla bug 378. --- server/core/config.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/server/core/config.c b/server/core/config.c index b48c7905a..221226678 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -837,17 +837,19 @@ int i; obj = context; while (obj) { - type = config_get_value(obj->parameters, "type"); - if (!strcmp(type, "service")) - param_set = service_params; - else if (!strcmp(type, "server")) - param_set = server_params; - else if (!strcmp(type, "listener")) - param_set = listener_params; - else if (!strcmp(type, "monitor")) - param_set = monitor_params; - else - param_set = NULL; + param_set = NULL; + if (obj->parameters && + (type = config_get_value(obj->parameters, "type"))) + { + if (!strcmp(type, "service")) + param_set = service_params; + else if (!strcmp(type, "server")) + param_set = server_params; + else if (!strcmp(type, "listener")) + param_set = listener_params; + else if (!strcmp(type, "monitor")) + param_set = monitor_params; + } if (param_set != NULL) { params = obj->parameters; From fa79a121e6bac2f86fcbfc6f3de46cac44f65e47 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Wed, 5 Feb 2014 11:29:20 +0100 Subject: [PATCH 02/10] Updated server version added to the prompt and in the log files. See Bugzilla bug 376. --- VERSION | 1 + server/core/Makefile | 8 ++++++-- server/core/gateway.c | 7 +++++-- server/modules/include/mysql_client_server_protocol.h | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 VERSION diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..8f0916f76 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.5.0 diff --git a/server/core/Makefile b/server/core/Makefile index 48b657657..bd96df614 100644 --- a/server/core/Makefile +++ b/server/core/Makefile @@ -63,7 +63,7 @@ HDRS= ../include/atomic.h ../include/buffer.h ../include/dcb.h \ ../include/session.h ../include/spinlock.h ../include/thread.h \ ../include/modules.h ../include/poll.h ../include/config.h \ ../include/users.h ../include/hashtable.h ../include/gwbitmask.h \ - ../include/adminusers.h + ../include/adminusers.h ../include/version.h OBJ=$(SRCS:.c=.o) @@ -89,6 +89,10 @@ maxpasswd: $(POBJS) .c.o: $(CC) $(CFLAGS) $< -o $@ + +../include/version.h: ../../VERSION + echo '#define MAXSCALE_VERSION "'`cat ../../VERSION`'"' > ../include/version.h + clean: rm -f $(OBJ) maxscale - rm *.so @@ -96,7 +100,7 @@ clean: tags: ctags $(SRCS) $(HDRS) -depend: +depend: ../include/version.h @rm -f depend.mk cc -M $(CFLAGS) $(SRCS) > depend.mk diff --git a/server/core/gateway.c b/server/core/gateway.c index 53065de11..f5ea14056 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -34,6 +34,7 @@ * 28/06/13 Vilho Raatikka Added necessary headers, example functions and * calls to log manager and to query classifier. * Put example code behind SS_DEBUG macros. + * 05/02/14 Mark Riddoch Addition of version string * * @endverbatim */ @@ -53,6 +54,7 @@ #include #include #include +#include #include #include @@ -313,7 +315,7 @@ static bool file_write_header( *t = time(NULL); *tm = *localtime(t); - header_buf1 = "\n\nSkySQL MaxScale\t"; + header_buf1 = "\n\nSkySQL MaxScale " MAXSCALE_VERSION "\t"; header_buf2 = strdup(asctime(tm)); if (header_buf2 == NULL) { @@ -1294,7 +1296,8 @@ int main(int argc, char **argv) } LOGIF(LM, (skygw_log_write( LOGFILE_MESSAGE, - "SkySQL MaxScale (C) SkySQL Ab 2013"))); + "SkySQL MaxScale %s (C) SkySQL Ab 2013,2014", + MAXSCALE_VERSION))); LOGIF(LM, (skygw_log_write( LOGFILE_MESSAGE, "MaxScale is running in process %i", diff --git a/server/modules/include/mysql_client_server_protocol.h b/server/modules/include/mysql_client_server_protocol.h index 3cbd72849..e23519da3 100644 --- a/server/modules/include/mysql_client_server_protocol.h +++ b/server/modules/include/mysql_client_server_protocol.h @@ -49,9 +49,9 @@ #include #include #include +#include -#define GW_VERSION "0.1.0" -#define GW_MYSQL_VERSION "5.5.22-SKYSQL-" GW_VERSION +#define GW_MYSQL_VERSION "MaxScale " MAXSCALE_VERSION #define GW_MYSQL_LOOP_TIMEOUT 300000000 #define GW_MYSQL_READ 0 #define GW_MYSQL_WRITE 1 From e97ab939660be439be5728d361e854a72a9da451 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Wed, 5 Feb 2014 12:20:53 +0100 Subject: [PATCH 03/10] Tidy up of the exit status based on the issues founf during startup. See Bugzilla 370. --- server/core/Makefile | 2 +- server/core/gateway.c | 33 +++++++++++++++--------------- server/include/maxscale.h | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 server/include/maxscale.h diff --git a/server/core/Makefile b/server/core/Makefile index bd96df614..4e02c493e 100644 --- a/server/core/Makefile +++ b/server/core/Makefile @@ -63,7 +63,7 @@ HDRS= ../include/atomic.h ../include/buffer.h ../include/dcb.h \ ../include/session.h ../include/spinlock.h ../include/thread.h \ ../include/modules.h ../include/poll.h ../include/config.h \ ../include/users.h ../include/hashtable.h ../include/gwbitmask.h \ - ../include/adminusers.h ../include/version.h + ../include/adminusers.h ../include/version.h ../include/maxscale.h OBJ=$(SRCS:.c=.o) diff --git a/server/core/gateway.c b/server/core/gateway.c index f5ea14056..2e23ba2a9 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -867,7 +868,7 @@ static void usage(void) */ int main(int argc, char **argv) { - int rc = 0; + int rc = MAXSCALE_SHUTDOWN; int l; int i; int n; @@ -916,7 +917,7 @@ int main(int argc, char **argv) { char* fprerr = "Failed to register exit functions for MaxScale"; print_log_n_stderr(false, true, NULL, fprerr, 0); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } } @@ -994,7 +995,7 @@ int main(int argc, char **argv) if (!succp) { - rc = 1; + rc = MAXSCALE_BADARG; goto return_main; } } @@ -1026,7 +1027,7 @@ int main(int argc, char **argv) eno = errno; errno = 0; print_log_n_stderr(true, true, fprerr, fprerr, eno); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } r = sigdelset(&sigset, SIGHUP); @@ -1038,7 +1039,7 @@ int main(int argc, char **argv) eno = errno; errno = 0; print_log_n_stderr(true, true, fprerr, logerr, eno); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } r = sigdelset(&sigset, SIGTERM); @@ -1050,7 +1051,7 @@ int main(int argc, char **argv) eno = errno; errno = 0; print_log_n_stderr(true, true, fprerr, logerr, eno); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } r = sigprocmask(SIG_SETMASK, &sigset, NULL); @@ -1061,7 +1062,7 @@ int main(int argc, char **argv) eno = errno; errno = 0; print_log_n_stderr(true, true, fprerr, logerr, eno); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } gw_daemonize(); @@ -1103,7 +1104,7 @@ int main(int argc, char **argv) errno = 0; print_log_n_stderr(true, !daemon_mode, logerr, fprerr, eno); free(logerr); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } } @@ -1114,7 +1115,7 @@ int main(int argc, char **argv) char* logerr = "Failed to initialise signal mask for MaxScale. " "Exiting."; print_log_n_stderr(true, true, logerr, logerr, eno); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } l = atexit(libmysqld_done); @@ -1125,7 +1126,7 @@ int main(int argc, char **argv) char* logerr = "Failed to register exit function libmysql_done " "for MaxScale. Exiting."; print_log_n_stderr(true, true, logerr, fprerr, 0); - rc = 1; + rc = MAXSCALE_INTERNALERROR; goto return_main; } /*< @@ -1138,7 +1139,7 @@ int main(int argc, char **argv) if (!resolve_maxscale_homedir(&home_dir)) { ss_dassert(home_dir == NULL); - rc = 1; + rc = MAXSCALE_HOMELESS; goto return_main; } sprintf(mysql_home, "%s/mysql", home_dir); @@ -1176,7 +1177,7 @@ int main(int argc, char **argv) if (!resolve_maxscale_conf_fname(&cnf_file_path, home_dir, cnf_file_arg)) { ss_dassert(cnf_file_path == NULL); - rc = 1; + rc = MAXSCALE_BADCONFIG; goto return_main; } @@ -1276,7 +1277,7 @@ int main(int argc, char **argv) mysql_error(NULL), __FILE__, __LINE__))); - rc = 1; + rc = MAXSCALE_NOLIBRARY; goto return_main; } libmysqld_started = TRUE; @@ -1291,7 +1292,7 @@ int main(int argc, char **argv) "Error : Failed to load MaxScale configuration file %s. " "Exiting.", cnf_file_path))); - rc = 1; + rc = MAXSCALE_BADCONFIG; goto return_main; } LOGIF(LM, (skygw_log_write( @@ -1313,7 +1314,7 @@ int main(int argc, char **argv) { char* logerr = "Failed to start any MaxScale services. Exiting."; print_log_n_stderr(true, !daemon_mode, logerr, logerr, 0); - rc = 1; + rc = MAXSCALE_NOSERVICES; goto return_main; } /*< @@ -1370,7 +1371,7 @@ int main(int argc, char **argv) "MaxScale shutdown completed."))); return_main: - return 0; + return rc; } /*< End of main */ /*< diff --git a/server/include/maxscale.h b/server/include/maxscale.h new file mode 100644 index 000000000..4fb5dd75f --- /dev/null +++ b/server/include/maxscale.h @@ -0,0 +1,43 @@ +#ifndef _MAXSCALE_H +#define _MAXSCALE_H +/* + * This file is distributed as part of the SkySQL Gateway. 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 SkySQL Ab 2014 + */ + +/** + * @file maxscale.h + * + * Some general definitions for MaxScale + * + * @verbatim + * Revision History + * + * Date Who Description + * 05/02/14 Mark Riddoch Initial implementation + * + * @endverbatim + */ + +/* Exit status for MaxScale */ +#define MAXSCALE_SHUTDOWN 0 /* Good shutdown */ +#define MAXSCALE_BADCONFIG 1 /* Configuration fiel error */ +#define MAXSCALE_NOLIBRARY 2 /* No embedded library found */ +#define MAXSCALE_NOSERVICES 3 /* No servics are running */ +#define MAXSCALE_HOMELESS 4 /* No MaxScale Home */ +#define MAXSCALE_BADARG 5 /* Bad command line argument */ +#define MAXSCALE_INTERNALERROR 6 /* Internal error, see error log */ +#endif From 3edea0afc44d7642445f6daa7bb3d0468c7c8616 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Wed, 5 Feb 2014 14:49:05 +0100 Subject: [PATCH 04/10] Updated gitignore files --- .gitignore | 9 ++++----- log_manager/.gitignore | 5 +++++ query_classifier/.gitignore | 5 +++++ server/core/.gitignore | 3 +++ server/include/.gitignore | 1 + server/inih/.gitignore | 3 +++ server/modules/monitor/.gitignore | 3 +++ server/modules/protocol/.gitignore | 3 +++ server/modules/routing/.gitignore | 3 +++ server/modules/routing/readwritesplit/.gitignore | 3 +++ utils/.gitignore | 1 + 11 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 log_manager/.gitignore create mode 100644 query_classifier/.gitignore create mode 100644 server/core/.gitignore create mode 100644 server/include/.gitignore create mode 100644 server/inih/.gitignore create mode 100644 server/modules/monitor/.gitignore create mode 100644 server/modules/protocol/.gitignore create mode 100644 server/modules/routing/.gitignore create mode 100644 server/modules/routing/readwritesplit/.gitignore create mode 100644 utils/.gitignore diff --git a/.gitignore b/.gitignore index 5ae09b517..b680e25df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ -core/tags -gateway -core/maxscale -core/maxkeys -core/maxpasswd +server/core/tags +server/core/maxscale +server/core/maxkeys +server/core/maxpasswd diff --git a/log_manager/.gitignore b/log_manager/.gitignore new file mode 100644 index 000000000..d5a8be98b --- /dev/null +++ b/log_manager/.gitignore @@ -0,0 +1,5 @@ +*.o +*.so +*.so.* +depend.mk + diff --git a/query_classifier/.gitignore b/query_classifier/.gitignore new file mode 100644 index 000000000..d5a8be98b --- /dev/null +++ b/query_classifier/.gitignore @@ -0,0 +1,5 @@ +*.o +*.so +*.so.* +depend.mk + diff --git a/server/core/.gitignore b/server/core/.gitignore new file mode 100644 index 000000000..84590451f --- /dev/null +++ b/server/core/.gitignore @@ -0,0 +1,3 @@ +*.o +maxscale +depend.mk diff --git a/server/include/.gitignore b/server/include/.gitignore new file mode 100644 index 000000000..67020331b --- /dev/null +++ b/server/include/.gitignore @@ -0,0 +1 @@ +version.h diff --git a/server/inih/.gitignore b/server/inih/.gitignore new file mode 100644 index 000000000..2a5429025 --- /dev/null +++ b/server/inih/.gitignore @@ -0,0 +1,3 @@ +*.o +*.a +make.depend diff --git a/server/modules/monitor/.gitignore b/server/modules/monitor/.gitignore new file mode 100644 index 000000000..1f1cd4c04 --- /dev/null +++ b/server/modules/monitor/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +depend.mk diff --git a/server/modules/protocol/.gitignore b/server/modules/protocol/.gitignore new file mode 100644 index 000000000..1f1cd4c04 --- /dev/null +++ b/server/modules/protocol/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +depend.mk diff --git a/server/modules/routing/.gitignore b/server/modules/routing/.gitignore new file mode 100644 index 000000000..1f1cd4c04 --- /dev/null +++ b/server/modules/routing/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +depend.mk diff --git a/server/modules/routing/readwritesplit/.gitignore b/server/modules/routing/readwritesplit/.gitignore new file mode 100644 index 000000000..1f1cd4c04 --- /dev/null +++ b/server/modules/routing/readwritesplit/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +depend.mk diff --git a/utils/.gitignore b/utils/.gitignore new file mode 100644 index 000000000..5761abcfd --- /dev/null +++ b/utils/.gitignore @@ -0,0 +1 @@ +*.o From 0c4b53e9ef96ab08519c40e3cb47e3cae225c190 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Wed, 5 Feb 2014 15:17:36 +0100 Subject: [PATCH 05/10] Addition of warnign to the debug command line interface regarding passing bad arguments. --- server/modules/routing/debugcli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/modules/routing/debugcli.c b/server/modules/routing/debugcli.c index 8b54acfa6..9c21c66f2 100644 --- a/server/modules/routing/debugcli.c +++ b/server/modules/routing/debugcli.c @@ -177,6 +177,8 @@ CLI_SESSION *client; dcb_printf(session->client, "Welcome the SkySQL MaxScale Debug Interface (%s).\n", version_str); + dcb_printf(session->client, "WARNING: This interface is meant for developer usage,\n"); + dcb_printf(session->client, "passing incorrect addresses to commands can endanger your MaxScale server.\n\n"); dcb_printf(session->client, "Type help for a list of available commands.\n\n"); return (void *)client; From a91c595dbc6730085b26842642ce3cbb232c0bd4 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Thu, 6 Feb 2014 13:10:11 +0100 Subject: [PATCH 06/10] Fix for allDCB linked list corruption. --- server/core/dcb.c | 23 ++++++++++++++++++++++- server/core/service.c | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/server/core/dcb.c b/server/core/dcb.c index 2a86c04fa..d4361c54b 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -99,7 +99,7 @@ DCB * dcb_alloc( { DCB *rval; -if ((rval = calloc(1, sizeof(DCB))) == NULL) + if ((rval = calloc(1, sizeof(DCB))) == NULL) { return NULL; } @@ -122,6 +122,7 @@ if ((rval = calloc(1, sizeof(DCB))) == NULL) memset(&rval->stats, 0, sizeof(DCBSTATS)); // Zero the statistics rval->state = DCB_STATE_ALLOC; bitmask_init(&rval->memdata.bitmask); + rval->next = NULL; spinlock_acquire(&dcbspin); if (allDCBs == NULL) @@ -137,6 +138,26 @@ if ((rval = calloc(1, sizeof(DCB))) == NULL) return rval; } + +/** + * Free a DCB that has not been associated with a decriptor. + * + * @param dcb The DCB to free + */ +void +dcb_free(DCB *dcb) +{ + if (dcb->fd == -1) + dcb_final_free(dcb); + else + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Attempt to free a DCB via dcb_fee " + "that has been associated with a descriptor."))); + } +} + /** * Add the DCB to the end of zombies list. * diff --git a/server/core/service.c b/server/core/service.c index c07e95baa..7e6e32b62 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -121,7 +121,7 @@ GWPROTOCOL *funcs; if ((funcs = (GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL)) == NULL) { - free(port->listener); + dcb_free(port->listener); port->listener = NULL; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, From 1e25d304e73c76209bd0c577e6724e7e4d23b41e Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Thu, 6 Feb 2014 13:46:07 +0100 Subject: [PATCH 07/10] Add check that the argument to the -c option is a directory. --- server/core/gateway.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/server/core/gateway.c b/server/core/gateway.c index 2e23ba2a9..a7bcd2285 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -940,7 +940,23 @@ int main(int argc, char **argv) */ if (optarg[0] != '-') { - get_expanded_pathname(&home_dir, optarg, NULL); + struct stat sb; + + if (stat(optarg, &sb) != -1 + && (! S_ISDIR(sb.st_mode))) + { + char* logerr = "Home directory argument " + "identifier \'-c\' was specified but " + "the argument didn't specify a valid " + "a directory."; + print_log_n_stderr(true, true, logerr, logerr, 0); + usage(); + succp = false; + } + else + { + get_expanded_pathname(&home_dir, optarg, NULL); + } } if (home_dir != NULL) From e4876b3abbb3a335384d7629450207103e509ef8 Mon Sep 17 00:00:00 2001 From: MassimilianoPinto Date: Thu, 6 Feb 2014 15:58:37 +0100 Subject: [PATCH 08/10] Enable/disable root user in services Added support for enable/disable root user, this is currently used in MySQL authentication --- server/core/config.c | 29 +++++++++++++++++++++----- server/core/dbusers.c | 14 +++++++++++-- server/core/service.c | 24 ++++++++++++++++++++- server/include/service.h | 13 +++++++----- server/modules/protocol/mysql_common.c | 4 ---- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/server/core/config.c b/server/core/config.c index 221226678..826fd9b58 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -22,10 +22,11 @@ * @verbatim * Revision History * - * Date Who Description - * 21/06/13 Mark Riddoch Initial implementation - * 08/07/13 Mark Riddoch Addition on monitor module support - * 23/07/13 Mark Riddoch Addition on default monitor password + * Date Who Description + * 21/06/13 Mark Riddoch Initial implementation + * 08/07/13 Mark Riddoch Addition on monitor module support + * 23/07/13 Mark Riddoch Addition on default monitor password + * 06/02/14 Massimiliano Pinto Added support for enable/disable root user in services * * @endverbatim */ @@ -197,6 +198,12 @@ int error_count = 0; config_get_value(obj->parameters, "user"); char *auth = config_get_value(obj->parameters, "passwd"); + char *enable_root_user = + config_get_value(obj->parameters, "enable_root_user"); + + if (enable_root_user) + serviceEnableRootUser(obj->element, atoi(enable_root_user)); + if (!auth) auth = config_get_value(obj->parameters, "auth"); @@ -587,21 +594,31 @@ SERVER *server; { char *user; char *auth; + char *enable_root_user; + + enable_root_user = config_get_value(obj->parameters, "enable_root_user"); user = config_get_value(obj->parameters, "user"); auth = config_get_value(obj->parameters, "passwd"); - if (user && auth) + if (user && auth) { service_update(service, router, user, auth); + if (enable_root_user) + serviceEnableRootUser(service, atoi(enable_root_user)); + } + obj->element = service; } else { char *user; char *auth; + char *enable_root_user; + + enable_root_user = config_get_value(obj->parameters, "enable_root_user"); user = config_get_value(obj->parameters, "user"); @@ -615,6 +632,8 @@ SERVER *server; serviceSetUser(obj->element, user, auth); + if (enable_root_user) + serviceEnableRootUser(service, atoi(enable_root_user)); } } } diff --git a/server/core/dbusers.c b/server/core/dbusers.c index 2e65b019e..48ecee160 100644 --- a/server/core/dbusers.c +++ b/server/core/dbusers.c @@ -25,6 +25,7 @@ * Date Who Description * 24/06/2013 Massimiliano Pinto Initial implementation * 08/08/2013 Massimiliano Pinto Fixed bug for invalid memory access in row[1]+1 when row[1] is "" + * 06/02/2014 Massimiliano Pinto Mysql user root selected based on configuration flag * * @endverbatim */ @@ -39,6 +40,9 @@ #include #include +#define USERS_QUERY_NO_ROOT " WHERE user NOT IN ('root')" +#define LOAD_MYSQL_USERS_QUERY "SELECT user, password FROM mysql.user" + extern int lm_enabled_logfiles_bitmask; static int getUsers(SERVICE *service, struct users *users); @@ -101,7 +105,13 @@ getUsers(SERVICE *service, struct users *users) char *dpwd; int total_users = 0; SERVER *server; - + char *users_query; + + if(service->enable_root) + users_query = LOAD_MYSQL_USERS_QUERY; + else + users_query = LOAD_MYSQL_USERS_QUERY USERS_QUERY_NO_ROOT; + serviceGetUser(service, &service_user, &service_passwd); /** multi-thread environment requires that thread init succeeds. */ if (mysql_thread_init()) { @@ -159,7 +169,7 @@ getUsers(SERVICE *service, struct users *users) return -1; } - if (mysql_query(con, "SELECT user, password FROM mysql.user")) { + if (mysql_query(con, users_query)) { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Loading users for service %s encountered " diff --git a/server/core/service.c b/server/core/service.c index 7e6e32b62..2fb3f5e50 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -25,6 +25,7 @@ * Date Who Description * 18/06/13 Mark Riddoch Initial implementation * 24/06/13 Massimiliano Pinto Added: Loading users from mysql backend in serviceStart + * 06/02/14 Massimiliano Pinto Added: serviceEnableRootUser routine * @endverbatim */ #include @@ -78,6 +79,7 @@ SERVICE *service; service->credentials.name = NULL; service->credentials.authdata = NULL; service->users = users_alloc(); + service->enable_root = 0; service->routerOptions = NULL; service->databases = NULL; spinlock_init(&service->spin); @@ -496,7 +498,7 @@ serviceSetUser(SERVICE *service, char *user, char *auth) * @param service The service we are setting the data for * @param user The user name to use for connections * @param auth The authentication data we need, e.g. MySQL SHA1 password - * @return 0 on failure + * @return 0 on failure */ int serviceGetUser(SERVICE *service, char **user, char **auth) @@ -508,6 +510,26 @@ serviceGetUser(SERVICE *service, char **user, char **auth) return 1; } +/** + * Enable/Disable root user for this service + * associated with this service. + * + * @param service The service we are setting the data for + * @param action 1 for root enable, 0 for disable access + * @return 0 on failure + */ + +int +serviceEnableRootUser(SERVICE *service, int action) +{ + if (action != 0 && action != 1) + return 0; + + service->enable_root = action; + + return 1; +} + /** * Return a named service * diff --git a/server/include/service.h b/server/include/service.h index 5f9357192..ffa6a3dad 100644 --- a/server/include/service.h +++ b/server/include/service.h @@ -31,11 +31,12 @@ * @verbatim * Revision History * - * Date Who Description - * 14/06/13 Mark Riddoch Initial implementation - * 18/06/13 Mark Riddoch Addition of statistics and function - * prototypes - * 23/06/13 Mark Riddoch Added service user and users + * Date Who Description + * 14/06/13 Mark Riddoch Initial implementation + * 18/06/13 Mark Riddoch Addition of statistics and function + * prototypes + * 23/06/13 Mark Riddoch Added service user and users + * 06/02/14 Massimiliano Pinto Added service flag for root user access * * @endverbatim */ @@ -101,6 +102,7 @@ typedef struct service { SPINLOCK spin; /**< The service spinlock */ SERVICE_STATS stats; /**< The service statistics */ struct users *users; /**< The user data for this service */ + int enable_root; /**< Allow root user access */ struct service *next; /**< The next service in the linked list */ } SERVICE; @@ -123,6 +125,7 @@ extern int serviceStop(SERVICE *); extern int serviceRestart(SERVICE *); extern int serviceSetUser(SERVICE *, char *, char *); extern int serviceGetUser(SERVICE *, char **, char **); +extern int serviceEnableRootUser(SERVICE *, int ); extern void service_update(SERVICE *, char *, char *, char *); extern void printService(SERVICE *); extern void printAllServices(); diff --git a/server/modules/protocol/mysql_common.c b/server/modules/protocol/mysql_common.c index 1ee25db27..01fd75b27 100644 --- a/server/modules/protocol/mysql_common.c +++ b/server/modules/protocol/mysql_common.c @@ -1101,10 +1101,6 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, SERVICE *service = NULL; char *user_password = NULL; - if (strcmp(username , "root") == 0) { - return 1; - } - service = (SERVICE *) ((DCB *)repository)->service; user_password = (char *)users_fetch(service->users, username); From 7bda58894894351a26b27d8b279486dd7c1e2d98 Mon Sep 17 00:00:00 2001 From: MassimilianoPinto Date: Thu, 6 Feb 2014 16:24:21 +0100 Subject: [PATCH 09/10] "enable_root_user" option available in service configuration example In MaxScale_template.cnf "enable_root_user" added for valid service option --- server/MaxScale_template.cnf | 1 + 1 file changed, 1 insertion(+) diff --git a/server/MaxScale_template.cnf b/server/MaxScale_template.cnf index 89f65b9a0..bbda5451e 100644 --- a/server/MaxScale_template.cnf +++ b/server/MaxScale_template.cnf @@ -36,6 +36,7 @@ passwd=maxpwd # servers=,,... # user= # passwd= +# enable_root_user=<0 or 1, default is 0> # # Valid router modules currently are: # readwritesplit, readconnroute and debugcli From 1742372dd50d1c23f8aa94bc38e8868bee8be51c Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Thu, 6 Feb 2014 19:04:12 +0100 Subject: [PATCH 10/10] Added support for defining a bind address in the listener config. Also removed some compilation warnings. See Bugzilla bug 150 --- server/core/config.c | 6 +++ server/core/gw_utils.c | 69 +++++++++++++++++++++++++- server/core/service.c | 14 ++++-- server/include/gw.h | 4 +- server/include/service.h | 3 +- server/modules/protocol/httpd.c | 16 ++---- server/modules/protocol/mysql_client.c | 38 ++------------ server/modules/protocol/telnetd.c | 15 +----- 8 files changed, 98 insertions(+), 67 deletions(-) diff --git a/server/core/config.c b/server/core/config.c index 826fd9b58..316fa6ecf 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -340,11 +340,13 @@ int error_count = 0; else if (!strcmp(type, "listener")) { char *service; + char *address; char *port; char *protocol; service = config_get_value(obj->parameters, "service"); port = config_get_value(obj->parameters, "port"); + address = config_get_value(obj->parameters, "address"); protocol = config_get_value(obj->parameters, "protocol"); if (service && port && protocol) @@ -356,6 +358,7 @@ int error_count = 0; { serviceAddProtocol(ptr->element, protocol, + address, atoi(port)); } else @@ -758,8 +761,10 @@ SERVER *server; char *service; char *port; char *protocol; + char *address; service = config_get_value(obj->parameters, "service"); + address = config_get_value(obj->parameters, "address"); port = config_get_value(obj->parameters, "port"); protocol = config_get_value(obj->parameters, "protocol"); @@ -777,6 +782,7 @@ SERVER *server; { serviceAddProtocol(ptr->element, protocol, + address, atoi(port)); serviceStartProtocol(ptr->element, protocol, diff --git a/server/core/gw_utils.c b/server/core/gw_utils.c index ad81843a8..c3f230906 100644 --- a/server/core/gw_utils.c +++ b/server/core/gw_utils.c @@ -32,6 +32,7 @@ * 01-07-2013 Massimiliano Pinto Removed session->backends * from gw_read_gwbuff() * 25-09-2013 Massimiliano Pinto setipaddress uses getaddrinfo + * 06-02-2014 Mark Riddoch Added parse_bindconfig * *@endverbatim */ @@ -40,9 +41,14 @@ #include #include +#include +#include + SPINLOCK tmplock = SPINLOCK_INIT; -/** +extern int lm_enabled_logfiles_bitmask; + +/* * Set IP address in socket structure in_addr * * @param a Pointer to a struct in_addr into which the address is written @@ -184,3 +190,64 @@ int gw_read_gwbuff(DCB *dcb, GWBUF **head, int b) { return 0; } +/** + * Parse the bind config data. This is passed in a string as address:port. + * + * The address may be either a . seperated IP address or a hostname to + * lookup. The address 0.0.0.0 is the wildcard address for SOCKADR_ANY. + * The ':' and port may be omitted, in which case the default port is + * used. + * + * @param config The bind address and port seperated by a ':' + * @param def_port The default port to use + * @param addr The sockaddr_in in which the data is written + * @return 0 on failure + */ +int +parse_bindconfig(char *config, unsigned short def_port, struct sockaddr_in *addr) +{ +char *port, buf[1024]; +short pnum; +struct hostent *hp; + + + strncpy(buf, config, 1024); + port = strrchr(buf, ':'); + if (port) + { + *port = 0; + port++; + pnum = atoi(port); + } + else + { + pnum = def_port; + } + + if (!strcmp(buf, "0.0.0.0")) + { + addr->sin_addr.s_addr = htonl(INADDR_ANY); + } + else + { + if (!inet_aton(buf, &addr->sin_addr)) + { + if ((hp = gethostbyname(buf)) != NULL) + { + bcopy(hp->h_addr, &(addr->sin_addr.s_addr), hp->h_length); + } + else + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Failed to lookup host '%s'. ", + buf))); + return 0; + } + } + } + + addr->sin_family = AF_INET; + addr->sin_port = htons(pnum); + return 1; +} diff --git a/server/core/service.c b/server/core/service.c index 2fb3f5e50..f3a065441 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -135,7 +135,10 @@ GWPROTOCOL *funcs; } memcpy(&(port->listener->func), funcs, sizeof(GWPROTOCOL)); port->listener->session = NULL; - sprintf(config_bind, "0.0.0.0:%d", port->port); + if (port->address) + sprintf(config_bind, "%s:%d", port->address, port->port); + else + sprintf(config_bind, "0.0.0.0:%d", port->port); if (port->listener->func.listen(port->listener, config_bind)) { port->listener->session = session_alloc(service, port->listener); @@ -335,11 +338,12 @@ SERVICE *ptr; * * @param service The service * @param protocol The name of the protocol module + * @param address The address to listen with * @param port The port to listen on * @return TRUE if the protocol/port could be added */ int -serviceAddProtocol(SERVICE *service, char *protocol, unsigned short port) +serviceAddProtocol(SERVICE *service, char *protocol, char *address, unsigned short port) { SERV_PROTOCOL *proto; @@ -348,6 +352,10 @@ SERV_PROTOCOL *proto; return 0; } proto->protocol = strdup(protocol); + if (address) + proto->address = strdup(address); + else + proto->address = NULL; proto->port = port; spinlock_acquire(&service->spin); proto->next = service->ports; @@ -358,7 +366,7 @@ SERV_PROTOCOL *proto; } /** - * Check if a protocol/port pair si part of the service + * Check if a protocol/port pair is part of the service * * @param service The service * @param protocol The name of the protocol module diff --git a/server/include/gw.h b/server/include/gw.h index b03a924f7..98e48c60a 100644 --- a/server/include/gw.h +++ b/server/include/gw.h @@ -27,8 +27,6 @@ #define GW_BACKEND_SO_SNDBUF 1024 #define GW_NOINTR_CALL(A) do { errno = 0; A; } while (errno == EINTR) -#define GW_VERSION "0.1.0" -#define GW_MYSQL_VERSION "5.5.22-SKYSQL-" GW_VERSION #define GW_MYSQL_LOOP_TIMEOUT 300000000 #define GW_MYSQL_READ 0 #define GW_MYSQL_WRITE 1 @@ -51,7 +49,6 @@ void gw_daemonize(void); int do_read_dcb(DCB *dcb); void MySQLListener(int epfd, char *config_bind); int MySQLAccept(DCB *listener); -int gw_mysql_do_authentication(DCB *dcb, GWBUF *); char *gw_strend(register const char *s); int do_read_dcb(DCB *dcb); int do_read_10(DCB *dcb, uint8_t *buffer); @@ -61,3 +58,4 @@ int gw_read_backend_event(DCB *dcb); int setnonblocking(int fd); int gw_write(int fd, const void* buf, size_t nbytes); int gw_getsockerrno(int fd); +int parse_bindconfig(char *, unsigned short, struct sockaddr_in *); diff --git a/server/include/service.h b/server/include/service.h index ffa6a3dad..630bfdd8b 100644 --- a/server/include/service.h +++ b/server/include/service.h @@ -54,6 +54,7 @@ struct users; typedef struct servprotocol { char *protocol; /**< Protocol module to load */ unsigned short port; /**< Port to listen on */ + char *address; /**< Address to listen with */ DCB *listener; /**< The DCB for the listener */ struct servprotocol *next; /**< Next service protocol */ @@ -112,7 +113,7 @@ typedef struct service { extern SERVICE *service_alloc(char *, char *); extern int service_free(SERVICE *); extern SERVICE *service_find(char *); -extern int serviceAddProtocol(SERVICE *, char *, unsigned short); +extern int serviceAddProtocol(SERVICE *, char *, char *, unsigned short); extern int serviceHasProtocol(SERVICE *, char *, unsigned short); extern void serviceAddBackend(SERVICE *, SERVER *); extern int serviceHasBackend(SERVICE *, SERVER *); diff --git a/server/modules/protocol/httpd.c b/server/modules/protocol/httpd.c index cc4faf0a9..f92e49598 100644 --- a/server/modules/protocol/httpd.c +++ b/server/modules/protocol/httpd.c @@ -38,6 +38,7 @@ */ #include +#include #define ISspace(x) isspace((int)(x)) #define HTTP_SERVER_STRING "Gateway(c) v.1.0.0" @@ -364,23 +365,12 @@ static int httpd_listen(DCB *listener, char *config) { struct sockaddr_in addr; -char *port; int one = 1; -short pnum; int rc; memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL)); - - port = strrchr(config, ':'); - if (port) - port++; - else - port = "6442"; - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - pnum = atoi(port); - addr.sin_port = htons(pnum); + if (!parse_bindconfig(config, 6442, &addr)) + return 0; if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index 5d27f090f..a8cde7337 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -34,6 +34,7 @@ #include #include #include +#include extern int lm_enabled_logfiles_bitmask; @@ -793,42 +794,13 @@ int gw_MySQLListener( { int l_so; struct sockaddr_in serv_addr; - char *bind_address_and_port = NULL; - char *p; - char address[1024] = ""; - int port = 0; int one = 1; int rc; /* this gateway, as default, will bind on port 4404 for localhost only */ - if (config_bind != NULL) { - bind_address_and_port = config_bind; - } else { - bind_address_and_port = "127.0.0.1:4406"; - } + if (!parse_bindconfig(config_bind, 4406, &serv_addr)) + return 0; listen_dcb->fd = -1; - memset(&serv_addr, 0, sizeof serv_addr); - serv_addr.sin_family = AF_INET; - p = strchr(bind_address_and_port, ':'); - - if (p) { - strncpy(address, bind_address_and_port, sizeof(address)); - address[sizeof(address)-1] = '\0'; - p = strchr(address, ':'); - *p = '\0'; - port = atoi(p+1); - setipaddress(&serv_addr.sin_addr, address); - - snprintf(address, - (sizeof(address) - 1), - "%s", - inet_ntoa(serv_addr.sin_addr)); - } else { - port = atoi(bind_address_and_port); - serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - sprintf(address, "0.0.0.0"); - } - serv_addr.sin_port = htons(port); // socket create if ((l_so = socket(AF_INET, SOCK_STREAM, 0)) < 0) { @@ -852,7 +824,7 @@ int gw_MySQLListener( errno, strerror(errno)); fprintf(stderr, "* Can't bind to %s\n\n", - bind_address_and_port); + config_bind); return 0; } /* @@ -868,7 +840,7 @@ int gw_MySQLListener( if (rc == 0) { fprintf(stderr, "Listening MySQL connections at %s\n", - bind_address_and_port); + config_bind); } else { int eno = errno; errno = 0; diff --git a/server/modules/protocol/telnetd.c b/server/modules/protocol/telnetd.c index f76f0f7fe..f7d6c1815 100644 --- a/server/modules/protocol/telnetd.c +++ b/server/modules/protocol/telnetd.c @@ -280,8 +280,6 @@ int n_connect = 0; socklen_t addrlen = sizeof(struct sockaddr); DCB *client_dcb; TELNETD* telnetd_pr = NULL; - dcb_state_t old_state = DCB_STATE_UNDEFINED; - bool succp = FALSE; so = accept(dcb->fd, (struct sockaddr *)&addr, &addrlen); @@ -354,23 +352,14 @@ static int telnetd_listen(DCB *listener, char *config) { struct sockaddr_in addr; -char *port; int one = 1; -short pnum; int rc; memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL)); - port = strrchr(config, ':'); - if (port) - port++; - else - port = "4442"; + if (!parse_bindconfig(config, 4442, &addr)) + return 0; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - pnum = atoi(port); - addr.sin_port = htons(pnum); if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {