Merge branch 'develop' into binlog_server_wait_data

This commit is contained in:
MassimilianoPinto
2016-09-12 09:03:06 +02:00
55 changed files with 1694 additions and 577 deletions

View File

@ -37,13 +37,25 @@
* 23/07/13 Mark Riddoch Addition of error mechanism to add user
* 23/05/16 Massimiliano Pinto admin_add_user and admin_remove_user
* no longer accept password parameter
* 02/09/16 Johan Wikman Enabled Linux accounts and MaxScale users
*
* @endverbatim
*/
static USERS *loadUsers();
static void initialise();
static USERS *users = NULL;
static USERS *loadLinuxUsers();
static USERS *loadInetUsers();
static const char *admin_add_user(USERS** pusers, const char* fname,
const char* uname, const char* password);
static const char* admin_remove_user(USERS *users, const char* fname,
const char *uname, const char *passwd);
static bool admin_search_user(USERS *users, const char *uname);
static USERS *linux_users = NULL;
static USERS *inet_users = NULL;
static int admin_init = 0;
static char *ADMIN_ERR_NOMEM = "Out of memory";
@ -61,7 +73,11 @@ static char *ADMIN_SUCCESS = NULL;
static const int LINELEN = 80;
static const char USERS_FILE_NAME[] = "maxadmin-users";
static const char LINUX_USERS_FILE_NAME[] = "maxadmin-users";
static const char INET_USERS_FILE_NAME[] = "passwd";
static const char INET_DEFAULT_USERNAME[] = "admin";
static const char INET_DEFAULT_PASSWORD[] = "mariadb";
/**
* Admin Users initialisation
@ -75,125 +91,15 @@ initialise()
}
admin_init = 1;
users = loadUsers();
linux_users = loadLinuxUsers();
inet_users = loadInetUsers();
}
/**
* Verify a username and password
*
* @param username Username to verify
* @param password Password to verify
* @return Non-zero if the username/password combination is valid
*/
int
admin_verify(char *username, char *password)
{
char *pw;
initialise();
if (users == NULL)
{
if (strcmp(username, "admin") == 0 && strcmp(password, "mariadb") == 0)
{
return 1;
}
}
else
{
if ((pw = users_fetch(users, username)) == NULL)
{
return 0;
}
struct crypt_data cdata;
cdata.initialized = 0;
if (strcmp(pw, crypt_r(password, ADMIN_SALT, &cdata)) == 0)
{
return 1;
}
}
return 0;
}
/**
* Load the admin users
*
* @return Table of users
*/
static USERS *
loadUsers()
{
USERS *rval;
FILE *fp;
char fname[PATH_MAX], *home;
char uname[80];
int added_users = 0;
initialise();
snprintf(fname, sizeof(fname), "%s/%s", get_datadir(), USERS_FILE_NAME);
if ((fp = fopen(fname, "r")) == NULL)
{
return NULL;
}
if ((rval = users_alloc()) == NULL)
{
fclose(fp);
return NULL;
}
while (fgets(uname, sizeof(uname), fp))
{
char *nl = strchr(uname, '\n');
if (nl)
{
*nl = '\0';
}
else if (!feof(fp))
{
MXS_ERROR("Line length exceeds %d characters, possible corrupted "
"'passwd' file in: %s", LINELEN, fname);
users_free(rval);
rval = NULL;
break;
}
char *tmp_ptr = strchr(uname, ':');
if (tmp_ptr)
{
*tmp_ptr = '\0';
MXS_WARNING("Found user '%s' with password. "
"This user might not be compatible with new maxadmin in MaxScale 2.0. "
"Remove it with \"remove user %s\" through MaxAdmin", uname, uname);
}
if (users_add(rval, uname, ""))
{
added_users++;
}
}
fclose(fp);
if (!added_users)
{
users_free(rval);
rval = NULL;
}
return rval;
}
/**
* Add user
*
* @param uname Name of the new user
* @return NULL on success or an error string on failure
*/
char *
admin_add_user(char *uname)
static const char *admin_add_user(USERS** pusers, const char* fname,
const char* uname, const char* password)
{
FILE *fp;
char fname[PATH_MAX], *home;
initialise();
char path[PATH_MAX], *home;
if (access(get_datadir(), F_OK) != 0)
{
@ -203,51 +109,51 @@ admin_add_user(char *uname)
}
}
snprintf(fname, sizeof(fname), "%s/%s", get_datadir(), USERS_FILE_NAME);
if (users == NULL)
snprintf(path, sizeof(path), "%s/%s", get_datadir(), fname);
if (*pusers == NULL)
{
MXS_NOTICE("Create initial password file.");
if ((users = users_alloc()) == NULL)
if ((*pusers = users_alloc()) == NULL)
{
return ADMIN_ERR_NOMEM;
}
if ((fp = fopen(fname, "w")) == NULL)
if ((fp = fopen(path, "w")) == NULL)
{
MXS_ERROR("Unable to create password file %s.", fname);
MXS_ERROR("Unable to create password file %s.", path);
return ADMIN_ERR_PWDFILEOPEN;
}
fclose(fp);
}
if (users_fetch(users, uname) != NULL)
if (users_fetch(*pusers, (char*)uname) != NULL) // TODO: Make users const correct.
{
return ADMIN_ERR_DUPLICATE;
}
users_add(users, uname, "");
if ((fp = fopen(fname, "a")) == NULL)
users_add(*pusers, (char*)uname, password ? (char*)password : ""); // TODO: Make users const correct.
if ((fp = fopen(path, "a")) == NULL)
{
MXS_ERROR("Unable to append to password file %s.", fname);
MXS_ERROR("Unable to append to password file %s.", path);
return ADMIN_ERR_FILEAPPEND;
}
fprintf(fp, "%s\n", uname);
if (password)
{
fprintf(fp, "%s:%s\n", uname, password);
}
else
{
fprintf(fp, "%s\n", uname);
}
fclose(fp);
return ADMIN_SUCCESS;
}
/**
* Remove maxscale user from in-memory structure and from password file
*
* @param uname Name of the new user
* @return NULL on success or an error string on failure
*/
char* admin_remove_user(
char* uname)
static const char* admin_remove_user(USERS *users, const char* fname,
const char *uname, const char *passwd)
{
FILE* fp;
FILE* fp_tmp;
char fname[PATH_MAX];
char fname_tmp[PATH_MAX];
char path[PATH_MAX];
char path_tmp[PATH_MAX];
char* home;
char fusr[LINELEN];
char fpwd[LINELEN];
@ -260,43 +166,53 @@ char* admin_remove_user(
return ADMIN_ERR_DELROOT;
}
if (!admin_search_user(uname))
if (!admin_search_user(users, uname))
{
MXS_ERROR("Couldn't find user %s. Removing user failed.", uname);
return ADMIN_ERR_USERNOTFOUND;
}
if (passwd)
{
if (admin_verify_inet_user(uname, passwd) == 0)
{
MXS_ERROR("Authentication failed, wrong user/password "
"combination. Removing user failed.");
return ADMIN_ERR_AUTHENTICATION;
}
}
/** Remove user from in-memory structure */
users_delete(users, uname);
users_delete(users, (char*)uname); // TODO: Make users const correct.
/**
* Open passwd file and remove user from the file.
*/
snprintf(fname, sizeof(fname), "%s/%s", get_datadir(), USERS_FILE_NAME);
snprintf(fname_tmp, sizeof(fname_tmp), "%s/%s_tmp", get_datadir(), USERS_FILE_NAME);
snprintf(path, sizeof(path), "%s/%s", get_datadir(), fname);
snprintf(path_tmp, sizeof(path_tmp), "%s/%s_tmp", get_datadir(), fname);
/**
* Rewrite passwd file from memory.
*/
if ((fp = fopen(fname, "r")) == NULL)
if ((fp = fopen(path, "r")) == NULL)
{
int err = errno;
MXS_ERROR("Unable to open password file %s : errno %d.\n"
"Removing user from file failed; it must be done "
"manually.",
fname,
path,
err);
return ADMIN_ERR_PWDFILEOPEN;
}
/**
* Open temporary passwd file.
*/
if ((fp_tmp = fopen(fname_tmp, "w")) == NULL)
if ((fp_tmp = fopen(path_tmp, "w")) == NULL)
{
int err = errno;
MXS_ERROR("Unable to open tmp file %s : errno %d.\n"
"Removing user from passwd file failed; it must be done "
"manually.",
fname_tmp,
path_tmp,
err);
fclose(fp);
return ADMIN_ERR_TMPFILEOPEN;
@ -311,11 +227,11 @@ char* admin_remove_user(
MXS_ERROR("Unable to process passwd file %s : errno %d.\n"
"Removing user from file failed, and must be done "
"manually.",
fname,
path,
err);
fclose(fp);
fclose(fp_tmp);
unlink(fname_tmp);
unlink(path_tmp);
return ADMIN_ERR_PWDFILEACCESS;
}
@ -330,7 +246,7 @@ char* admin_remove_user(
else if (!feof(fp))
{
MXS_ERROR("Line length exceeds %d characters, possible corrupted "
"'passwd' file in: %s", LINELEN, fname);
"'passwd' file in: %s", LINELEN, path);
fclose(fp);
fclose(fp_tmp);
return ADMIN_ERR_PWDFILEACCESS;
@ -358,11 +274,11 @@ char* admin_remove_user(
"errno %d.\n"
"Removing user from file failed, and must be "
"done manually.",
fname,
path,
err);
fclose(fp);
fclose(fp_tmp);
unlink(fname_tmp);
unlink(path_tmp);
return ADMIN_ERR_PWDFILEACCESS;
}
}
@ -370,16 +286,16 @@ char* admin_remove_user(
/**
* Replace original passwd file with new.
*/
if (rename(fname_tmp, fname))
if (rename(path_tmp, path))
{
int err = errno;
MXS_ERROR("Unable to rename new passwd file %s : errno "
"%d.\n"
"Rename it to %s manually.",
fname_tmp,
path_tmp,
err,
fname);
unlink(fname_tmp);
path);
unlink(path_tmp);
fclose(fp_tmp);
return ADMIN_ERR_PWDFILEACCESS;
}
@ -387,47 +303,284 @@ char* admin_remove_user(
return ADMIN_SUCCESS;
}
/**
* Check for existance of the user
*
* @param user The user name to test
* @return Non-zero if the user exists
* @param uname The user name to test
* @return True if the user exists
*/
int
admin_search_user(char *user)
static bool admin_search_user(USERS *users, const char *uname)
{
return (users_fetch(users, (char*)uname) != NULL); // TODO: Make users const correct.
}
/**
*/
void dcb_print_users(DCB *dcb, const char* heading, USERS *users)
{
dcb_printf(dcb, "%s", heading);
if (users)
{
HASHITERATOR *iter = hashtable_iterator(users->data);
if (iter)
{
char *sep = "";
const char *user;
while ((user = hashtable_next(iter)) != NULL)
{
dcb_printf(dcb, "%s%s", sep, user);
sep = ", ";
}
hashtable_iterator_free(iter);
}
}
dcb_printf(dcb, "%s", "\n");
}
/**
* Load the admin users
*
* @return Table of users
*/
static USERS *
loadUsers(const char *fname)
{
USERS *rval;
FILE *fp;
char path[PATH_MAX], *home;
char uname[80];
int added_users = 0;
initialise();
snprintf(path, sizeof(path), "%s/%s", get_datadir(), fname);
if ((fp = fopen(path, "r")) == NULL)
{
return NULL;
}
if ((rval = users_alloc()) == NULL)
{
fclose(fp);
return NULL;
}
while (fgets(uname, sizeof(uname), fp))
{
char *nl = strchr(uname, '\n');
if (nl)
{
*nl = '\0';
}
else if (!feof(fp))
{
MXS_ERROR("Line length exceeds %d characters, possibly corrupted "
"'passwd' file in: %s", LINELEN, path);
users_free(rval);
rval = NULL;
break;
}
char *password;
char *colon = strchr(uname, ':');
if (colon)
{
// Inet case
*colon = 0;
password = colon + 1;
}
else
{
// Linux case.
password = "";
}
if (users_add(rval, uname, password))
{
added_users++;
}
}
fclose(fp);
if (!added_users)
{
users_free(rval);
rval = NULL;
}
return rval;
}
static USERS *loadLinuxUsers()
{
return loadUsers(LINUX_USERS_FILE_NAME);
}
static USERS *loadInetUsers()
{
return loadUsers(INET_USERS_FILE_NAME);
}
/**
* Enable Linux account
*
* @param uname Name of Linux user
*
* @return NULL on success or an error string on failure.
*/
const char *admin_enable_linux_account(const char *uname)
{
initialise();
int rv = 0;
return admin_add_user(&linux_users, LINUX_USERS_FILE_NAME, uname, NULL);
}
if (strcmp(user, DEFAULT_ADMIN_USER) == 0)
/**
* Disable Linux account
*
* @param uname Name of Linux user
*
* @return NULL on success or an error string on failure.
*/
const char* admin_disable_linux_account(const char* uname)
{
initialise();
return admin_remove_user(linux_users, LINUX_USERS_FILE_NAME, uname, NULL);
}
/**
* Check whether Linux account is enabled
*
* @param uname The user name
*
* @return True if the account is enabled, false otherwise.
*/
bool admin_linux_account_enabled(const char *uname)
{
initialise();
bool rv = false;
if (strcmp(uname, DEFAULT_ADMIN_USER) == 0)
{
rv = 1;
rv = true;
}
else if (users)
else if (linux_users)
{
rv = (users_fetch(users, user) != NULL);
rv = admin_search_user(linux_users, uname);
}
return rv;
}
/**
* Print the statistics and user names of the administration users
* Add insecure remote (network) user.
*
* @param dcb A DCB to send the output to
* @param uname Name of the new user.
* @param password Password of the new user.
*
* @return NULL on success or an error string on failure.
*/
void
dcb_PrintAdminUsers(DCB *dcb)
const char *admin_add_inet_user(const char *uname, const char* password)
{
if (users)
initialise();
struct crypt_data cdata;
cdata.initialized = 0;
char *cpassword = crypt_r(password, ADMIN_SALT, &cdata);
return admin_add_user(&inet_users, INET_USERS_FILE_NAME, uname, cpassword);
}
/**
* Remove insecure remote (network) user
*
* @param uname Name of user to be removed.
* @param password Password of user to be removed.
*
* @return NULL on success or an error string on failure.
*/
const char* admin_remove_inet_user(const char* uname, const char *password)
{
initialise();
return admin_remove_user(inet_users, INET_USERS_FILE_NAME, uname, password);
}
/**
* Check for existance of remote user.
*
* @param user The user name to test.
*
* @return True if the user exists, false otherwise.
*/
bool admin_inet_user_exists(const char *uname)
{
initialise();
bool rv = false;
if (inet_users)
{
dcb_usersPrint(dcb, users);
rv = admin_search_user(inet_users, uname);
}
return rv;
}
/**
* Verify a remote user name and password
*
* @param username Username to verify
* @param password Password to verify
*
* @return True if the username/password combination is valid
*/
bool
admin_verify_inet_user(const char *username, const char *password)
{
bool rv = false;
initialise();
if (inet_users)
{
const char* pw = users_fetch(inet_users, (char*)username); // TODO: Make users const-correct.
if (pw)
{
struct crypt_data cdata;
cdata.initialized = 0;
if (strcmp(pw, crypt_r(password, ADMIN_SALT, &cdata)) == 0)
{
rv = true;
}
}
}
else
{
dcb_printf(dcb, "No administration users have been defined.\n");
if (strcmp(username, INET_DEFAULT_USERNAME) == 0
&& strcmp(password, INET_DEFAULT_PASSWORD) == 0)
{
rv = true;
}
}
return rv;
}
/**
* Print Linux and and inet users
*
* @param dcb A DCB to send the output to.
*/
void dcb_PrintAdminUsers(DCB *dcb)
{
dcb_print_users(dcb, "Enabled Linux accounts (secure) : ", linux_users);
dcb_print_users(dcb, "Created network accounts (insecure): ", inet_users);
}

View File

@ -84,6 +84,7 @@ static bool process_config_context(CONFIG_CONTEXT *);
static int process_config_update(CONFIG_CONTEXT *);
static void free_config_context(CONFIG_CONTEXT *);
static char *config_get_value(CONFIG_PARAMETER *, const char *);
static char *config_get_password(CONFIG_PARAMETER *);
static const char *config_get_value_string(CONFIG_PARAMETER *, const char *);
static int handle_global_item(const char *, const char *);
static int handle_feedback_item(const char *, const char *);
@ -119,7 +120,8 @@ static char *service_params[] =
"router_options",
"servers",
"user",
"passwd",
"passwd", // DEPRECATE: See config_get_password.
"password",
"enable_root_user",
"max_connections",
"max_queued_connections",
@ -139,6 +141,7 @@ static char *service_params[] =
"ignore_databases_regex",
"log_auth_warnings",
"source", /**< Avrorouter only */
"retry_on_failure",
NULL
};
@ -166,7 +169,8 @@ static char *monitor_params[] =
"module",
"servers",
"user",
"passwd",
"passwd", // DEPRECATE: See config_get_password.
"password",
"script",
"events",
"mysql51_replication",
@ -594,6 +598,30 @@ config_get_value(CONFIG_PARAMETER *params, const char *name)
return NULL;
}
// DEPRECATE: In 2.1 complain but accept if "passwd" is provided, in 2.2
// DEPRECATE: drop support for "passwd".
/**
* Get the value of the password parameter
*
* The words looked for are "password" and "passwd".
*
* @param params The linked list of config parameters
* @return the parameter value or NULL if not found
*/
static char *
config_get_password(CONFIG_PARAMETER *params)
{
char *password = config_get_value(params, "password");
char *passwd = config_get_value(params, "passwd");
if (password && passwd)
{
MXS_WARNING("Both 'password' and 'passwd' specified. Using value of 'password'.");
}
return passwd ? passwd : password;
}
/**
* Get the value of a config parameter as a string
*
@ -1386,7 +1414,7 @@ process_config_update(CONFIG_CONTEXT *context)
max_queued_connections = config_get_value_string(obj->parameters, "max_queued_connections");
queued_connection_timeout = config_get_value_string(obj->parameters, "queued_connection_timeout");
user = config_get_value(obj->parameters, "user");
auth = config_get_value(obj->parameters, "passwd");
auth = config_get_password(obj->parameters);
auth_all_servers = config_get_value(obj->parameters, "auth_all_servers");
strip_db_esc = config_get_value(obj->parameters, "strip_db_esc");
@ -2318,7 +2346,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
}
char *user = config_get_value(obj->parameters, "user");
char *auth = config_get_value(obj->parameters, "passwd");
char *auth = config_get_password(obj->parameters);
if (user && auth)
{
@ -2331,7 +2359,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
obj->object,
user ? "" : "the 'user' parameter",
!user && !auth ? " and " : "",
auth ? "" : "the 'passwd' parameter");
auth ? "" : "the 'password' or 'passwd' parameter");
}
char *subservices = config_get_value(obj->parameters, "subservices");
@ -2736,7 +2764,7 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE*
}
char *user = config_get_value(obj->parameters, "user");
char *passwd = config_get_value(obj->parameters, "passwd");
char *passwd = config_get_password(obj->parameters);
if (user && passwd)
{
monitorAddUser(obj->element, user, passwd);

View File

@ -137,6 +137,7 @@ static struct option long_options[] =
{"execdir", required_argument, 0, 'E'},
{"language", required_argument, 0, 'N'},
{"piddir", required_argument, 0, 'P'},
{"basedir", required_argument, 0, 'R'},
{"user", required_argument, 0, 'U'},
{"syslog", required_argument, 0, 's'},
{"maxlog", required_argument, 0, 'S'},
@ -164,7 +165,7 @@ static void write_footer(void);
static int ntfw_cb(const char*, const struct stat*, int, struct FTW*);
static bool file_is_readable(const char* absolute_pathname);
static bool file_is_writable(const char* absolute_pathname);
bool handle_path_arg(char** dest, char* path, char* arg, bool rd, bool wr);
bool handle_path_arg(char** dest, const char* path, char* arg, bool rd, bool wr);
static void set_log_augmentation(const char* value);
static void usage(void);
static char* get_expanded_pathname(
@ -697,30 +698,27 @@ static void print_log_n_stderr(
const char* fprstr, /*< string to be printed to stderr */
int eno) /*< errno, if it is set, zero, otherwise */
{
char* log_err = "Error :";
char* fpr_err = "*\n* Error :";
char* fpr_end = "\n*\n";
if (do_log)
{
mxs_log_init(NULL, get_logdir(), MXS_LOG_TARGET_FS);
char errbuf[STRERROR_BUFLEN];
MXS_ERROR("%s %s %s %s",
log_err,
logstr,
eno == 0 ? " " : "Error :",
eno == 0 ? " " : strerror_r(eno, errbuf, sizeof(errbuf)));
if (mxs_log_init(NULL, get_logdir(), MXS_LOG_TARGET_FS))
{
char errbuf[STRERROR_BUFLEN];
MXS_ERROR("%s%s%s%s",
logstr,
eno == 0 ? "" : " (",
eno == 0 ? "" : strerror_r(eno, errbuf, sizeof(errbuf)),
eno == 0 ? "" : ")");
}
}
if (do_stderr)
{
char errbuf[STRERROR_BUFLEN];
fprintf(stderr,
"%s %s %s %s %s",
fpr_err,
"* Error: %s%s%s%s\n",
fprstr,
eno == 0 ? " " : "Error :",
eno == 0 ? " " : strerror_r(eno, errbuf, sizeof(errbuf)),
fpr_end);
eno == 0 ? "" : " (",
eno == 0 ? "" : strerror_r(eno, errbuf, sizeof(errbuf)),
eno == 0 ? "" : ")");
}
}
@ -887,32 +885,52 @@ static void usage(void)
{
fprintf(stderr,
"\nUsage : %s [OPTION]...\n\n"
" -c, --config-check Validate configuration file and exit\n"
" -d, --nodaemon enable running in terminal process (default:disabled)\n"
" -f, --config=FILE relative or absolute pathname of MaxScale configuration file\n"
" (default:/etc/maxscale.cnf)\n"
" -l, --log=[file|shm|stdout] log to file, shared memory or stdout (default: file)\n"
" -L, --logdir=PATH path to log file directory (default: /var/log/maxscale)\n"
" -A, --cachedir=PATH path to cache directory (default: /var/cache/maxscale)\n"
" -B, --libdir=PATH path to module directory (default: /usr/lib64/maxscale)\n"
" -C, --configdir=PATH path to configuration file directory (default: /etc/)\n"
" -D, --datadir=PATH path to data directory, stored embedded mysql tables\n"
" (default: /var/cache/maxscale)\n"
" -c, --config-check validate configuration file and exit\n"
" -d, --nodaemon enable running in terminal process\n"
" -f, --config=FILE relative or absolute pathname of config file\n"
" -l, --log=[file|shm|stdout] log to file, shared memory or stdout\n"
" (default: file)\n"
" -L, --logdir=PATH path to log file directory\n"
" -A, --cachedir=PATH path to cache directory\n"
" -B, --libdir=PATH path to module directory\n"
" -C, --configdir=PATH path to configuration file directory\n"
" -D, --datadir=PATH path to data directory,\n"
" stored embedded mysql tables\n"
" -E, --execdir=PATH path to the maxscale and other executable files\n"
" (default: /usr/bin)\n"
" -N, --language=PATH path to errmsg.sys file (default: /var/lib/maxscale)\n"
" -P, --piddir=PATH path to PID file directory (default: /var/run/maxscale)\n"
" -U, --user=USER run MaxScale as another user.\n"
" The user ID and group ID of this user are used to run MaxScale.\n"
" -N, --language=PATH path to errmsg.sys file\n"
" -P, --piddir=PATH path to PID file directory\n"
" -R, --basedir=PATH base path for all other paths\n"
" -U, --user=USER user ID and group ID of specified user are used to\n"
" run MaxScale\n"
" -s, --syslog=[yes|no] log messages to syslog (default:yes)\n"
" -S, --maxlog=[yes|no] log messages to MaxScale log (default: yes)\n"
" -G, --log_augmentation=0|1 augment messages with the name of the function where\n"
" the message was logged (default: 0). Primarily for \n"
" development purposes.\n"
" -G, --log_augmentation=0|1 augment messages with the name of the function\n"
" where the message was logged (default: 0)\n"
" -v, --version print version info and exit\n"
" -V, --version-full print full version info and exit\n"
" -?, --help show this help\n"
, progname);
"\n"
"Defaults paths:\n"
" config file: %s/%s\n"
" configdir : %s\n"
" logdir : %s\n"
" cachedir : %s\n"
" libdir : %s\n"
" datadir : %s\n"
" execdir : %s\n"
" language : %s\n"
" piddir : %s\n"
"\n"
"If '--basedir' is provided then all other paths, including the default\n"
"configuration file path, are defined relative to that. As an example,\n"
"if '--basedir /path/maxscale' is specified, then, for instance, the log\n"
"dir will be '/path/maxscale/var/log/maxscale', the config dir will be\n"
"'/path/maxscale/etc' and the default config file will be\n"
"'/path/maxscale/etc/maxscale.cnf'.\n",
progname,
get_configdir(), default_cnf_fname,
get_configdir(), get_logdir(), get_cachedir(), get_libdir(),
get_datadir(), get_execdir(), get_langdir(), get_piddir());
}
@ -1135,6 +1153,61 @@ bool configure_signals(void)
return true;
}
/**
* Set the directories of MaxScale relative to a basedir
*
* @param basedir The base directory relative to which the other are set.
*
* @return True if the directories could be set, false otherwise.
*/
bool set_dirs(const char *basedir)
{
bool rv = true;
char *path;
if (rv && (rv = handle_path_arg(&path, basedir, "var/" MXS_DEFAULT_LOG_SUBPATH, true, false)))
{
set_logdir(path);
}
if (rv && (rv = handle_path_arg(&path, basedir, "var/" MXS_DEFAULT_CACHE_SUBPATH, true, true)))
{
set_cachedir(path);
}
if (rv && (rv = handle_path_arg(&path, basedir, MXS_DEFAULT_LIB_SUBPATH, true, false)))
{
set_libdir(path);
}
if (rv && (rv = handle_path_arg(&path, basedir, MXS_DEFAULT_CONFIG_SUBPATH, true, false)))
{
set_configdir(path);
}
if (rv && (rv = handle_path_arg(&path, basedir, "var/" MXS_DEFAULT_DATA_SUBPATH, true, false)))
{
set_datadir(path);
}
if (rv && (rv = handle_path_arg(&path, basedir, MXS_DEFAULT_EXEC_SUBPATH, true, false)))
{
set_execdir(path);
}
if (rv && (rv = handle_path_arg(&path, basedir, "var/" MXS_DEFAULT_LANG_SUBPATH, true, false)))
{
set_langdir(path);
}
if (rv && (rv = handle_path_arg(&path, basedir, "var/" MXS_DEFAULT_PID_SUBPATH, true, true)))
{
set_piddir(path);
}
return rv;
}
/**
* @mainpage
* The main entry point into MaxScale
@ -1304,7 +1377,6 @@ int main(int argc, char **argv)
}
break;
case 'L':
if (handle_path_arg(&tmp_path, optarg, NULL, true, false))
{
set_logdir(tmp_path);
@ -1381,6 +1453,17 @@ int main(int argc, char **argv)
succp = false;
}
break;
case 'R':
if (handle_path_arg(&tmp_path, optarg, NULL, true, false))
{
succp = set_dirs(tmp_path);
free(tmp_path);
}
else
{
succp = false;
}
break;
case 'S':
{
@ -2252,7 +2335,7 @@ static int write_pid_file()
return 0;
}
bool handle_path_arg(char** dest, char* path, char* arg, bool rd, bool wr)
bool handle_path_arg(char** dest, const char* path, char* arg, bool rd, bool wr)
{
char pathbuffer[PATH_MAX + 2];
char* errstr;

View File

@ -584,7 +584,7 @@ return_succ:
{
/** This releases memory of all created objects */
logmanager_done_nomutex();
LOG_ERROR("MaxScale Log: Error, initialization failed.\n");
fprintf(stderr, "* Error: Initializing the log manager failed.\n");
}
return succ;
}
@ -1693,7 +1693,7 @@ static bool logfile_open_file(filewriter_t* fw,
if (fw->fwr_file == NULL)
{
LOG_ERROR("MaxScale Log: Error, opening log file %s failed.\n", lf->lf_full_file_name);
// Error logged by skygw_file_init to stderr.
rv = false;
}
@ -2125,9 +2125,6 @@ static void filewriter_done(filewriter_t* fw, bool write_footer)
{
case RUN:
CHK_FILEWRITER(fw);
case INIT:
fw->fwr_logmes = NULL;
fw->fwr_clientmes = NULL;
if (log_config.use_stdout)
{
skygw_file_free(fw->fwr_file);
@ -2141,7 +2138,11 @@ static void filewriter_done(filewriter_t* fw, bool write_footer)
skygw_file_close(fw->fwr_file);
}
case INIT:
fw->fwr_logmes = NULL;
fw->fwr_clientmes = NULL;
fw->fwr_state = DONE;
break;
case DONE:
case UNINIT:
default:

View File

@ -826,7 +826,9 @@ mon_status_changed(MONITOR_SERVERS* mon_srv)
{
/* Previous status is -1 if not yet set */
return (mon_srv->mon_prev_status != -1
&& mon_srv->mon_prev_status != mon_srv->server->status);
&& mon_srv->mon_prev_status != mon_srv->server->status
/** If the server is going into maintenance or coming out of it, don't trigger a state change */
&& ((mon_srv->mon_prev_status | mon_srv->server->status) & SERVER_MAINT) == 0);
}
/**

View File

@ -225,7 +225,7 @@ poll_init()
bitmask_init(&poll_mask);
n_threads = config_threadcount();
thread_data = (THREAD_DATA *)MXS_MALLOC(n_threads * sizeof(THREAD_DATA));
if (thread_data);
if (thread_data)
{
for (i = 0; i < n_threads; i++)
{

View File

@ -89,7 +89,6 @@ server_alloc(char *servname, char *protocol, unsigned short port)
server->rlag = -2;
server->master_id = -1;
server->depth = -1;
server->slaves = NULL;
server->parameters = NULL;
server->server_string = NULL;
spinlock_init(&server->lock);
@ -144,7 +143,6 @@ server_free(SERVER *tofreeserver)
MXS_FREE(tofreeserver->protocol);
MXS_FREE(tofreeserver->unique_name);
MXS_FREE(tofreeserver->server_string);
MXS_FREE(tofreeserver->slaves);
server_parameter_free(tofreeserver->parameters);
if (tofreeserver->persistent)

View File

@ -384,6 +384,9 @@ int serviceStartAllPorts(SERVICE* service)
(void*) service, retry_after);
MXS_NOTICE("Failed to start service %s, retrying in %d seconds.",
service->name, retry_after);
/** This will prevent MaxScale from shutting down if service start is retried later */
listeners = 1;
}
}
else

View File

@ -50,12 +50,12 @@
static int
test1()
{
if (admin_verify("admin", "mariadb") == 0)
if (admin_verify_inet_user("admin", "mariadb") == 0)
{
fprintf(stderr, "admin_verify: test 1.1 (default user) failed.\n");
return 1;
}
if (admin_verify("bad", "user"))
if (admin_verify_inet_user("bad", "user"))
{
fprintf(stderr, "admin_verify: test 1.2 (wrong user) failed.\n");
return 1;
@ -74,15 +74,15 @@ test1()
static int
test2()
{
char *err;
const char *err;
if ((err = admin_add_user("user0")) != NULL)
if ((err = admin_enable_linux_account("user0")) != NULL)
{
fprintf(stderr, "admin_add_user: test 2.1 (add user) failed, %s.\n", err);
return 1;
}
if (admin_add_user("user0") == NULL)
if (admin_enable_linux_account("user0") == NULL)
{
fprintf(stderr, "admin_add_user: test 2.2 (add user) failed, duplicate.\n");
@ -90,7 +90,7 @@ test2()
}
/* Deleting the last user is not forbidden so we expect this to succeed */
if ((err = admin_remove_user("user0")) != NULL)
if ((err = admin_disable_linux_account("user0")) != NULL)
{
fprintf(stderr, "admin_remove_user: test 2.3 (add user) failed, %s.\n", err);
@ -98,7 +98,7 @@ test2()
}
/* Add the user back, for test5. */
if ((err = admin_add_user("user0")) != NULL)
if ((err = admin_enable_linux_account("user0")) != NULL)
{
fprintf(stderr, "admin_add_user: test 2.4 (add user) failed, %s.\n", err);
@ -120,37 +120,37 @@ test2()
static int
test3()
{
char *err;
const char *err;
if ((err = admin_add_user("user1")) != NULL)
if ((err = admin_enable_linux_account("user1")) != NULL)
{
fprintf(stderr, "admin_add_user: test 3.1 (add user) failed, %s.\n", err);
return 1;
}
if (admin_search_user("user1") == 0)
if (admin_linux_account_enabled("user1") == 0)
{
fprintf(stderr, "admin_search_user: test 3.2 (search user) failed.\n");
return 1;
}
if (admin_search_user("user2") != 0)
if (admin_linux_account_enabled("user2") != 0)
{
fprintf(stderr, "admin_search_user: test 3.3 (search user) failed, unexpeted user found.\n");
return 1;
}
if ((err = admin_remove_user("user1")) != NULL)
if ((err = admin_disable_linux_account("user1")) != NULL)
{
fprintf(stderr, "admin_remove_user: test 3.4 (add user) failed, %s.\n", err);
return 1;
}
if (admin_search_user("user1"))
if (admin_linux_account_enabled("user1"))
{
fprintf(stderr, "admin_search_user: test 3.5 (search user) failed - user was deleted.\n");
@ -173,13 +173,14 @@ test3()
static int
test4()
{
char *err, user[40], passwd[40];
const char *err;
char user[40], passwd[40];
int i, n_users = 50;
for (i = 1; i < n_users; i++)
{
sprintf(user, "user%d", i);
if ((err = admin_add_user(user)) != NULL)
if ((err = admin_enable_linux_account(user)) != NULL)
{
fprintf(stderr, "admin_add_user: test 4.1 (add user) failed, %s.\n", err);
@ -190,7 +191,7 @@ test4()
for (i = 1; i < n_users; i++)
{
sprintf(user, "user%d", i);
if (admin_search_user(user) == 0)
if (admin_linux_account_enabled(user) == 0)
{
fprintf(stderr, "admin_search_user: test 4.2 (search user) failed.\n");
@ -201,7 +202,7 @@ test4()
for (i = 1; i < n_users; i++)
{
sprintf(user, "user%d", i);
if ((err = admin_remove_user(user)) != NULL)
if ((err = admin_disable_linux_account(user)) != NULL)
{
fprintf(stderr, "admin_remove_user: test 4.3 (add user) failed, %s.\n", err);
@ -221,16 +222,16 @@ test4()
static int
test5()
{
char *err;
const char *err;
if ((err = admin_add_user("user")) != NULL)
if ((err = admin_enable_linux_account("user")) != NULL)
{
fprintf(stderr, "admin_add_user: test 5.1 (add user) failed, %s.\n", err);
return 1;
}
if ((err = admin_remove_user("user0")) != NULL)
if ((err = admin_disable_linux_account("user0")) != NULL)
{
fprintf(stderr, "admin_remove_user: test 5.2 (add user) failed, %s.\n", err);

View File

@ -51,12 +51,16 @@ typedef struct admin_session
#endif
} ADMIN_session;
extern int admin_verify(char *, char *);
extern char *admin_add_user(char *);
extern int admin_search_user(char *);
extern void dcb_PrintAdminUsers(DCB *dcb);
extern const char *admin_enable_linux_account(const char *uname);
extern const char *admin_disable_linux_account(const char *uname);
extern bool admin_linux_account_enabled(const char *uname);
char* admin_remove_user(char* uname);
extern const char *admin_add_inet_user(const char *uname, const char *password);
extern const char *admin_remove_inet_user(const char *uname, const char *password);
extern bool admin_inet_user_exists(const char *uname);
extern bool admin_verify_inet_user(const char *uname, const char *password);
extern void dcb_PrintAdminUsers(DCB *dcb);
#endif

View File

@ -21,19 +21,30 @@
EXTERN_C_BLOCK_BEGIN
// NOTE: If you make changes here, ensure they are compatible with the
// situation in <root>/CMakeLists.txt, where directories are installed.
#define MXS_DEFAULT_PID_SUBPATH "run/maxscale"
#define MXS_DEFAULT_LOG_SUBPATH "log/maxscale"
#define MXS_DEFAULT_DATA_SUBPATH "lib/maxscale"
#define MXS_DEFAULT_LIB_SUBPATH "@MAXSCALE_LIBDIR@"
#define MXS_DEFAULT_CACHE_SUBPATH "cache/maxscale"
#define MXS_DEFAULT_LANG_SUBPATH "lib/maxscale"
#define MXS_DEFAULT_EXEC_SUBPATH "@MAXSCALE_BINDIR@"
#define MXS_DEFAULT_CONFIG_SUBPATH "etc"
/** Default file locations, configured by CMake */
static const char* default_cnf_fname = "maxscale.cnf";
static const char* default_configdir = "/etc";
static const char* default_configdir = "/" MXS_DEFAULT_CONFIG_SUBPATH;
/*< This should be changed to just /run eventually,
* the /var/run folder is an old standard and the newer FSH 3.0
* uses /run for PID files.*/
static const char* default_piddir = "@MAXSCALE_VARDIR@/run/maxscale";
static const char* default_logdir = "@MAXSCALE_VARDIR@/log/maxscale";
static const char* default_datadir = "@MAXSCALE_VARDIR@/lib/maxscale";
static const char* default_libdir = "@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@";
static const char* default_cachedir = "@MAXSCALE_VARDIR@/cache/maxscale";
static const char* default_langdir = "@MAXSCALE_VARDIR@/lib/maxscale";
static const char* default_execdir = "@CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@";
static const char* default_piddir = "@MAXSCALE_VARDIR@/" MXS_DEFAULT_PID_SUBPATH;
static const char* default_logdir = "@MAXSCALE_VARDIR@/" MXS_DEFAULT_LOG_SUBPATH;
static const char* default_datadir = "@MAXSCALE_VARDIR@/" MXS_DEFAULT_DATA_SUBPATH;
static const char* default_libdir = "@CMAKE_INSTALL_PREFIX@/" MXS_DEFAULT_LIB_SUBPATH;
static const char* default_cachedir = "@MAXSCALE_VARDIR@/" MXS_DEFAULT_CACHE_SUBPATH;
static const char* default_langdir = "@MAXSCALE_VARDIR@/" MXS_DEFAULT_LANG_SUBPATH;
static const char* default_execdir = "@CMAKE_INSTALL_PREFIX@/" MXS_DEFAULT_EXEC_SUBPATH;
static char* configdir = NULL;
static char* logdir = NULL;

View File

@ -133,7 +133,6 @@ typedef enum
#define MONITOR_INTERVAL 10000 // in milliseconds
#define MONITOR_DEFAULT_ID 1UL // unsigned long value
#define MONITOR_MAX_NUM_SLAVES 20 //number of MySQL slave servers associated to a MySQL master server
/*
* Create declarations of the enum for monitor events and also the array of

View File

@ -45,6 +45,7 @@
*/
#define MAX_SERVER_NAME_LEN 1024
#define MAX_NUM_SLAVES 128 /**< Maximum number of slaves under a single server*/
/**
* The server parameters used for weighting routing decissions
@ -99,7 +100,7 @@ typedef struct server
SERVER_PARAM *parameters; /**< Parameters of a server that may be used to weight routing decisions */
long master_id; /**< Master server id of this node */
int depth; /**< Replication level in the tree */
long *slaves; /**< Slaves of this node */
long slaves[MAX_NUM_SLAVES]; /**< Slaves of this node */
bool master_err_is_logged; /*< If node failed, this indicates whether it is logged */
DCB *persistent; /**< List of unused persistent connections to the server */
SPINLOCK persistlock; /**< Lock for adjusting the persistent connections list */

View File

@ -406,14 +406,6 @@ typedef enum skygw_chk_t
lf->lf_name_suffix != NULL && \
lf->lf_full_file_name != NULL, \
"NULL in name variable\n"); \
ss_debug( \
(lf->lf_chk_top != CHK_NUM_LOGFILE || \
lf->lf_chk_tail != CHK_NUM_LOGFILE ? \
false : \
(lf->lf_filepath == NULL || \
lf->lf_name_prefix == NULL || \
lf->lf_name_suffix == NULL || \
lf->lf_full_file_name == NULL ? false : true));) \
}
#define CHK_FILEWRITER(fwr) { \

View File

@ -145,7 +145,7 @@ max_admin_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
dcb->data = (void *)session_data;
/* Check for existance of the user */
if (admin_search_user(session_data->user))
if (admin_linux_account_enabled(session_data->user))
{
session_data->validated = true;
return 0;

View File

@ -73,7 +73,7 @@ version()
/*
* The filter entry points
*/
static FILTER *createInstance(char **options, FILTER_PARAMETER **);
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **);
static void *newSession(FILTER *instance, SESSION *session);
static void closeSession(FILTER *instance, void *session);
static void freeSession(FILTER *instance, void *session);
@ -169,7 +169,7 @@ ModuleInit()
* @return The instance data for this new instance
*/
static FILTER *
createInstance(char **options, FILTER_PARAMETER **params)
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
{
LUA_INSTANCE *my_instance;
bool error = false;

View File

@ -13,12 +13,19 @@
* Public License.
*/
#define MAXADMIN_DEFAULT_SOCKET "/tmp/maxadmin.sock"
#define MAXADMIN_DEFAULT_SOCKET "/tmp/maxadmin.sock"
#define MAXADMIN_CONFIG_DEFAULT_SOCKET_TAG_LEN 7
#define MAXADMIN_CONFIG_DEFAULT_SOCKET_TAG "default"
#define MAXADMIN_GETPWUID_BUF_LEN 255
#define MAXADMIN_AUTH_REPLY_LEN 6
#define MAXADMIN_FAILED_AUTH_MESSAGE "FAILED"
#define MAXADMIN_CONFIG_DEFAULT_SOCKET_TAG "default"
#define MAXADMIN_AUTH_REPLY_LEN 6
#define MAXADMIN_AUTH_FAILED_REPLY "FAILED"
#define MAXADMIN_AUTH_SUCCESS_REPLY "OK----"
#define MAXADMIN_AUTH_USER_PROMPT "USER"
#define MAXADMIN_AUTH_USER_PROMPT_LEN 4
#define MAXADMIN_AUTH_PASSWORD_PROMPT "PASSWORD"
#define MAXADMIN_AUTH_PASSWORD_PROMPT_LEN 8
#endif

View File

@ -28,16 +28,17 @@
#include <spinlock.h>
#include <housekeeper.h>
/**
* The telnetd specific protocol structure to put in the DCB.
* The maxscaled specific protocol structure to put in the DCB.
*/
typedef struct maxscaled
typedef struct maxscaled
{
SPINLOCK lock; /**< Protocol structure lock */
int state; /**< The connection state */
char *username; /**< The login name of the user */
SPINLOCK lock; /**< Protocol structure lock */
int state; /**< The connection state */
char *username; /**< The login name of the user */
} MAXSCALED;
#define MAXSCALED_STATE_LOGIN 1 /**< Waiting for credentials */
#define MAXSCALED_STATE_DATA 2 /**< User logged in */
#define MAXSCALED_STATE_LOGIN 1 /**< Waiting for user */
#define MAXSCALED_STATE_PASSWD 2 /**< Waiting for password */
#define MAXSCALED_STATE_DATA 3 /**< User logged in */
#endif

View File

@ -547,7 +547,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon)
if (mysql_num_rows(result) > 0)
{
ismaster = true;
while (nslaves < MONITOR_MAX_NUM_SLAVES && (row = mysql_fetch_row(result)))
while (nslaves < MAX_NUM_SLAVES && (row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
database->server->slaves[nslaves] = atol(row[0]);
@ -835,13 +835,7 @@ monitorMain(void *arg)
monitorDatabase(mon, ptr);
/* reset the slave list of current node */
if (ptr->server->slaves)
{
MXS_FREE(ptr->server->slaves);
}
/* create a new slave list */
ptr->server->slaves = (long *) MXS_CALLOC(MONITOR_MAX_NUM_SLAVES, sizeof(long));
MXS_ABORT_IF_NULL(ptr->server->slaves);
memset(&ptr->server->slaves, 0, sizeof(ptr->server->slaves));
num_servers++;
@ -1448,7 +1442,8 @@ static MONITOR_SERVERS *get_replication_tree(MONITOR *mon, int num_servers)
master = getServerByNodeId(mon->databases, current->master_id);
if (master && master->server && master->server->node_id > 0)
{
add_slave_to_master(master->server->slaves, MONITOR_MAX_NUM_SLAVES, current->node_id);
add_slave_to_master(master->server->slaves, sizeof(master->server->slaves),
current->node_id);
master->server->depth = current->depth - 1;
monitor_set_pending_status(master, SERVER_MASTER);
handle->master = master;
@ -1509,7 +1504,7 @@ static int add_slave_to_master(long *slaves_list, int list_size, long node_id)
{
if (slaves_list[i] == 0)
{
memcpy(&slaves_list[i], &node_id, sizeof(long));
slaves_list[i] = node_id;
return 1;
}
}

View File

@ -1,5 +1,6 @@
if(BUILD_CDC)
add_subdirectory(CDC)
add_subdirectory(examples)
endif()
add_subdirectory(HTTPD)
@ -8,7 +9,6 @@ add_subdirectory(MySQLBackend)
add_subdirectory(MySQLClient)
add_subdirectory(telnetd)
if(BUILD_TESTS)
add_subdirectory(testprotocol)
endif()

View File

@ -0,0 +1,5 @@
install_script(cdc.py core)
install_script(cdc_users.py core)
install_script(cdc_last_transaction.py core)
install_script(cdc_kafka_producer.py core)
install_file(cdc_schema.go core)

View File

@ -66,6 +66,8 @@ MODULE_INFO info =
static char *version_str = "V2.0.0";
#define GETPWUID_BUF_LEN 255
static int maxscaled_read_event(DCB* dcb);
static int maxscaled_write_event(DCB *dcb);
static int maxscaled_write(DCB *dcb, GWBUF *queue);
@ -76,6 +78,100 @@ static int maxscaled_close(DCB *dcb);
static int maxscaled_listen(DCB *dcb, char *config);
static char *mxsd_default_auth();
static bool authenticate_unix_socket(MAXSCALED *protocol, DCB *dcb)
{
bool authenticated = false;
struct ucred ucred;
socklen_t len = sizeof(struct ucred);
/* Get UNIX client credentials from socket*/
if (getsockopt(dcb->fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0)
{
struct passwd pw_entry;
struct passwd *pw_tmp;
char buf[GETPWUID_BUF_LEN];
/* Fetch username from UID */
if (getpwuid_r(ucred.uid, &pw_entry, buf, sizeof(buf), &pw_tmp) == 0)
{
GWBUF *username;
/* Set user in protocol */
protocol->username = strdup(pw_entry.pw_name);
username = gwbuf_alloc(strlen(protocol->username) + 1);
strcpy(GWBUF_DATA(username), protocol->username);
/* Authenticate the user */
if (dcb->authfunc.extract(dcb, username) == 0 &&
dcb->authfunc.authenticate(dcb) == 0)
{
dcb_printf(dcb, MAXADMIN_AUTH_SUCCESS_REPLY);
protocol->state = MAXSCALED_STATE_DATA;
dcb->user = strdup(protocol->username);
}
else
{
dcb_printf(dcb, MAXADMIN_AUTH_FAILED_REPLY);
}
gwbuf_free(username);
authenticated = true;
}
else
{
MXS_ERROR("Failed to get UNIX user %ld details for 'MaxScale Admin'",
(unsigned long)ucred.uid);
}
}
else
{
MXS_ERROR("Failed to get UNIX domain socket credentials for 'MaxScale Admin'.");
}
return authenticated;
}
static bool authenticate_inet_socket(MAXSCALED *protocol, DCB *dcb)
{
dcb_printf(dcb, MAXADMIN_AUTH_USER_PROMPT);
return true;
}
static bool authenticate_socket(MAXSCALED *protocol, DCB *dcb)
{
bool authenticated = false;
struct sockaddr address;
socklen_t address_len = sizeof(address);
if (getsockname(dcb->fd, &address, &address_len) == 0)
{
if (address.sa_family == AF_UNIX)
{
authenticated = authenticate_unix_socket(protocol, dcb);
}
else
{
authenticated = authenticate_inet_socket(protocol, dcb);
}
}
else
{
char errbuf[STRERROR_BUFLEN];
MXS_ERROR("Could not get socket family of client connection: %s",
strerror_r(errno, errbuf, sizeof(errbuf)));
}
return authenticated;
}
/**
* The "module object" for the maxscaled protocol module.
*/
@ -161,10 +257,41 @@ static int maxscaled_read_event(DCB* dcb)
{
if (GWBUF_LENGTH(head))
{
if (maxscaled->state == MAXSCALED_STATE_DATA)
switch (maxscaled->state)
{
SESSION_ROUTE_QUERY(dcb->session, head);
dcb_printf(dcb, "OK");
case MAXSCALED_STATE_LOGIN:
{
maxscaled->username = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head));
maxscaled->state = MAXSCALED_STATE_PASSWD;
dcb_printf(dcb, MAXADMIN_AUTH_PASSWORD_PROMPT);
gwbuf_free(head);
}
break;
case MAXSCALED_STATE_PASSWD:
{
char *password = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head));
if (admin_verify_inet_user(maxscaled->username, password))
{
dcb_printf(dcb, MAXADMIN_AUTH_SUCCESS_REPLY);
maxscaled->state = MAXSCALED_STATE_DATA;
}
else
{
dcb_printf(dcb, MAXADMIN_AUTH_FAILED_REPLY);
maxscaled->state = MAXSCALED_STATE_LOGIN;
}
gwbuf_free(head);
free(password);
}
break;
case MAXSCALED_STATE_DATA:
{
SESSION_ROUTE_QUERY(dcb->session, head);
dcb_printf(dcb, "OK");
}
break;
}
}
else
@ -241,9 +368,9 @@ static int maxscaled_accept(DCB *listener)
while ((client_dcb = dcb_accept(listener, &MyObject)) != NULL)
{
MAXSCALED *maxscaled_protocol = NULL;
MAXSCALED *maxscaled_protocol = (MAXSCALED *)calloc(1, sizeof(MAXSCALED));
if ((maxscaled_protocol = (MAXSCALED *)MXS_CALLOC(1, sizeof(MAXSCALED))) == NULL)
if (!maxscaled_protocol)
{
dcb_close(client_dcb);
continue;
@ -252,52 +379,14 @@ static int maxscaled_accept(DCB *listener)
maxscaled_protocol->username = NULL;
maxscaled_protocol->state = MAXSCALED_STATE_LOGIN;
/* Get UNIX client credentials from socket*/
if (getsockopt(client_dcb->fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
bool authenticated = false;
if (!authenticate_socket(maxscaled_protocol, client_dcb))
{
MXS_ERROR("Failed to get UNIX socket credentials for 'MaxScale Admin'");
dcb_close(client_dcb);
free(maxscaled_protocol);
continue;
}
else
{
struct passwd pw_entry;
struct passwd *pw_tmp;
char buf[MAXADMIN_GETPWUID_BUF_LEN];
/* Fetch username from UID */
if (!getpwuid_r(ucred.uid, &pw_entry, buf, sizeof(buf), &pw_tmp))
{
GWBUF *username;
/* Set user in protocol */
maxscaled_protocol->username = MXS_STRDUP_A(pw_entry.pw_name);
username = gwbuf_alloc(strlen(maxscaled_protocol->username) + 1);
strcpy(GWBUF_DATA(username), maxscaled_protocol->username);
/* Authenticate the user */
if (client_dcb->authfunc.extract(client_dcb, username) == 0 &&
client_dcb->authfunc.authenticate(client_dcb) == 0)
{
dcb_printf(client_dcb, "OK----");
maxscaled_protocol->state = MAXSCALED_STATE_DATA;
client_dcb->user = MXS_STRDUP_A(maxscaled_protocol->username);
}
else
{
dcb_printf(client_dcb, "FAILED");
}
}
else
{
MXS_ERROR("Failed to get UNIX user %ld details for 'MaxScale Admin'",
(unsigned long)ucred.uid);
dcb_close(client_dcb);
continue;
}
}
spinlock_init(&maxscaled_protocol->lock);
client_dcb->protocol = (void *)maxscaled_protocol;
@ -350,7 +439,7 @@ static int maxscaled_close(DCB *dcb)
*/
static int maxscaled_listen(DCB *listener, char *config)
{
char *socket_path;
char *socket_path = NULL;
/* check for default UNIX socket */
if (strncmp(config, MAXADMIN_CONFIG_DEFAULT_SOCKET_TAG, MAXADMIN_CONFIG_DEFAULT_SOCKET_TAG_LEN) == 0)
@ -359,19 +448,8 @@ static int maxscaled_listen(DCB *listener, char *config)
}
else
{
socket_path = config;
socket_path = config;
}
/* check for UNIX socket path*/
if (strchr(socket_path,'/') == NULL)
{
MXS_ERROR("Failed to start listening on '%s' with 'MaxScale Admin' protocol,"
" only UNIX domain sockets are supported. Remove all 'port' and 'address'"
" parameters from this listener and add 'socket=default' to enable UNIX domain sockets.", socket_path);
return -1;
}
else
{
return (dcb_listen(listener, socket_path, "MaxScale Admin") < 0) ? 0 : 1;
}
return (dcb_listen(listener, socket_path, "MaxScale Admin") < 0) ? 0 : 1;
}

View File

@ -203,7 +203,7 @@ static int telnetd_read_event(DCB* dcb)
{
*t = 0;
}
if (admin_verify(telnetd->username, password))
if (admin_verify_inet_user(telnetd->username, password))
{
telnetd_echo(dcb, 1);
telnetd->state = TELNETD_STATE_DATA;

View File

@ -5,11 +5,6 @@ if(AVRO_FOUND)
set_target_properties(avrorouter PROPERTIES LINK_FLAGS -Wl,-z,defs)
target_link_libraries(avrorouter maxscale-common jansson ${AVRO_LIBRARIES} maxavro sqlite3 lzma)
install_module(avrorouter core)
install_script(cdc core)
install_script(cdc_users core)
install_script(cdc_last_transaction core)
install_script(cdc_kafka_producer core)
install_file(cdc_schema.go core)
else()
message(STATUS "Avro C libraries were not found, avrorouter will not be built.")
endif()

View File

@ -223,8 +223,8 @@ struct subcommand showoptions[] = {
"Show the status of the polling threads in MaxScale",
{0, 0, 0} },
{ "users", 0, telnetdShowUsers,
"Show statistics and user names for the debug interface",
"Show statistics and user names for the debug interface",
"Show all maxadmin enabled Linux accounts and created maxadmin users",
"Show all maxadmin enabled Linux accounts and created maxadmin users",
{0, 0, 0} },
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
@ -449,6 +449,8 @@ static void enable_syslog();
static void disable_syslog();
static void enable_maxlog();
static void disable_maxlog();
static void enable_account(DCB *, char *user);
static void disable_account(DCB *, char *user);
/**
* * The subcommands of the enable command
@ -536,6 +538,16 @@ struct subcommand enableoptions[] = {
"Enable maxlog logging",
{0, 0, 0}
},
{
"account",
1,
enable_account,
"Enable maxadmin usage for Linux user. E.g.:\n"
" MaxScale> enable account alice",
"Enable maxadmin usage for Linux user. E.g.:\n"
" MaxScale> enable account alice",
{ARG_TYPE_STRING, 0, 0}
},
{
NULL,
0,
@ -634,6 +646,16 @@ struct subcommand disableoptions[] = {
"Disable maxlog logging",
{0, 0, 0}
},
{
"account",
1,
disable_account,
"Disable maxadmin usage for Linux user. E.g.:\n"
" MaxScale> disable account alice",
"Disable maxadmin usage for Linux user. E.g.:\n"
" MaxScale> disable account alice",
{ARG_TYPE_STRING, 0, 0}
},
{
NULL,
0,
@ -688,32 +710,38 @@ struct subcommand failoptions[] = {
};
#endif /* FAKE_CODE */
static void telnetdAddUser(DCB *, char *);
static void telnetdAddUser(DCB *, char *user, char *password);
/**
* The subcommands of the add command
*/
struct subcommand addoptions[] = {
{ "user", 1, telnetdAddUser,
"Add a new user for the debug interface. E.g. add user john",
"Add a new user for the debug interface. E.g. add user john",
{ARG_TYPE_STRING, 0, 0} },
{ "user", 2, telnetdAddUser,
"Add insecure account for using maxadmin over the network. E.g.:\n"
" MaxScale> add user bob somepass",
"Add insecure account for using maxadmin over the network. E.g.:\n"
" MaxScale> add user bob somepass",
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0} },
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
};
static void telnetdRemoveUser(DCB *, char *);
static void telnetdRemoveUser(DCB *, char *user, char *password);
/**
* The subcommands of the remove command
*/
struct subcommand removeoptions[] = {
{
"user",
1,
2,
telnetdRemoveUser,
"Remove existing maxscale user. Example : remove user john",
"Remove existing maxscale user. Example : remove user john",
{ARG_TYPE_STRING, 0, 0}
"Remove account for using maxadmin over the network. E.g.:\n"
" MaxAdmin> remove user bob somepass",
"Remove account for using maxadmin over the network. E.g.:\n"
" MaxAdmin> remove user bob somepass",
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
},
{
NULL, 0, NULL, NULL, NULL, {0, 0, 0}
@ -1302,63 +1330,61 @@ reload_config(DCB *dcb)
}
/**
* Add a new maxscale admin user
* Add a new remote (insecure, over the network) maxscale admin user
*
* @param dcb The DCB for messages
* @param user The user name
* @param dcb The DCB for messages
* @param user The user name
* @param user The user password
*/
static void
telnetdAddUser(DCB *dcb, char *user)
telnetdAddUser(DCB *dcb, char *user, char *password)
{
char *err;
const char *err;
if (admin_search_user(user))
if (admin_inet_user_exists(user))
{
dcb_printf(dcb, "User %s already exists.\n", user);
dcb_printf(dcb, "Account %s for remote (network) usage already exists.\n", user);
return;
}
if ((err = admin_add_user(user)) == NULL)
if ((err = admin_add_inet_user(user, password)) == NULL)
{
dcb_printf(dcb, "User %s has been successfully added.\n", user);
dcb_printf(dcb, "Account %s for remote (network) usage has been successfully added.\n", user);
}
else
{
dcb_printf(dcb, "Failed to add new user. %s\n", err);
dcb_printf(dcb, "Failed to add new remote account %s: %s.\n", user, err);
}
}
/**
* Remove a maxscale admin user
* Remove a remote (insecure, over the network) maxscale admin user
*
* @param dcb The DCB for messages
* @param user The user name
* @param dcb The DCB for messages
* @param user The user name
* @param user The user password
*/
static void telnetdRemoveUser(
DCB* dcb,
char* user)
static void telnetdRemoveUser(DCB *dcb, char *user, char *password)
{
char* err;
const char* err;
if (!admin_search_user(user))
if (!admin_inet_user_exists(user))
{
dcb_printf(dcb, "User %s doesn't exist.\n", user);
dcb_printf(dcb, "Account %s for remote (network) usage does not exist.\n", user);
return;
}
if ((err = admin_remove_user(user)) == NULL)
if ((err = admin_remove_inet_user(user, password)) == NULL)
{
dcb_printf(dcb, "User %s has been successfully removed.\n", user);
dcb_printf(dcb, "Account %s for remote (network) usage has been successfully removed.\n", user);
}
else
{
dcb_printf(dcb, "Failed to remove user %s. %s\n", user, err);
dcb_printf(dcb, "Failed to remove remote account %s: %s\n", user, err);
}
}
/**
* Print the adminsitration users
*
@ -1367,7 +1393,6 @@ static void telnetdRemoveUser(
static void
telnetdShowUsers(DCB *dcb)
{
dcb_printf(dcb, "Administration interface users:\n");
dcb_PrintAdminUsers(dcb);
}
@ -1869,6 +1894,60 @@ disable_maxlog()
mxs_log_set_maxlog_enabled(false);
}
/**
* Enable a Linux account
*
* @param dcb The DCB for messages
* @param user The Linux user name
*/
static void
enable_account(DCB *dcb, char *user)
{
const char *err;
if (admin_linux_account_enabled(user))
{
dcb_printf(dcb, "The Linux user %s has already been enabled.\n", user);
return;
}
if ((err = admin_enable_linux_account(user)) == NULL)
{
dcb_printf(dcb, "The Linux user %s has successfully been enabled.\n", user);
}
else
{
dcb_printf(dcb, "Failed to enable the Linux user %s: %s\n", user, err);
}
}
/**
* Disable a Linux account
*
* @param dcb The DCB for messages
* @param user The Linux user name
*/
static void
disable_account(DCB *dcb, char *user)
{
const char* err;
if (!admin_linux_account_enabled(user))
{
dcb_printf(dcb, "The Linux user %s has not been enabled.\n", user);
return;
}
if ((err = admin_disable_linux_account(user)) == NULL)
{
dcb_printf(dcb, "The Linux user %s has successfully been disabled.\n", user);
}
else
{
dcb_printf(dcb, "Failed to disable the Linux user %s: %s\n", user, err);
}
}
#if defined(FAKE_CODE)
static void fail_backendfd(void)
{

View File

@ -1016,12 +1016,18 @@ static BACKEND *get_root_master(BACKEND **servers)
{
if (servers[i] && (servers[i]->server->status & (SERVER_MASTER | SERVER_MAINT)) == SERVER_MASTER)
{
if (master_host && servers[i]->server->depth < master_host->server->depth)
if (master_host == NULL)
{
master_host = servers[i];
}
else if (master_host == NULL)
else if (servers[i]->server->depth < master_host->server->depth ||
(servers[i]->server->depth == master_host->server->depth &&
servers[i]->weight > master_host->weight))
{
/**
* This master has a lower depth than the candidate master or
* the depths are equal but this master has a higher weight
*/
master_host = servers[i];
}
}

View File

@ -942,7 +942,7 @@ static void closeSession(ROUTER *instance, void *router_session)
}
#endif
/** Clean operation counter in bref and in SERVER */
while (BREF_IS_WAITING_RESULT(bref))
if (BREF_IS_WAITING_RESULT(bref))
{
bref_clear_state(bref, BREF_WAITING_RESULT);
}
@ -955,6 +955,10 @@ static void closeSession(ROUTER *instance, void *router_session)
/** decrease server current connection counters */
atomic_add(&bref->bref_backend->backend_conn_count, -1);
}
else
{
ss_dassert(!BREF_IS_WAITING_RESULT(bref));
}
}
/** Unlock */
rses_end_locked_router_action(router_cli_ses);
@ -1384,7 +1388,6 @@ static route_target_t get_route_target(ROUTER_CLIENT_SES *rses,
}
else
{
/** hints don't affect on routing */
ss_dassert(trx_active ||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_WRITE) ||
QUERY_IS_TYPE(qtype, QUERY_TYPE_MASTER_READ) ||
@ -2795,11 +2798,8 @@ static void bref_clear_state(backend_ref_t *bref, bref_state_t state)
MXS_ERROR("[%s] Error: NULL parameter.", __FUNCTION__);
return;
}
if (state != BREF_WAITING_RESULT)
{
bref->bref_state &= ~state;
}
else
if ((state & BREF_WAITING_RESULT) && (bref->bref_state & BREF_WAITING_RESULT))
{
int prev1;
int prev2;
@ -2824,6 +2824,8 @@ static void bref_clear_state(backend_ref_t *bref, bref_state_t state)
}
}
}
bref->bref_state &= ~state;
}
static void bref_set_state(backend_ref_t *bref, bref_state_t state)
@ -2833,11 +2835,8 @@ static void bref_set_state(backend_ref_t *bref, bref_state_t state)
MXS_ERROR("[%s] Error: NULL parameter.", __FUNCTION__);
return;
}
if (state != BREF_WAITING_RESULT)
{
bref->bref_state |= state;
}
else
if ((state & BREF_WAITING_RESULT) && (bref->bref_state & BREF_WAITING_RESULT) == 0)
{
int prev1;
int prev2;
@ -2863,6 +2862,8 @@ static void bref_set_state(backend_ref_t *bref, bref_state_t state)
bref->bref_backend->backend_server->port);
}
}
bref->bref_state |= state;
}
/**