Merge branch 'develop' into binlog_server_wait_data
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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++)
|
||||
{
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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) { \
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
5
server/modules/protocol/examples/CMakeLists.txt
Normal file
5
server/modules/protocol/examples/CMakeLists.txt
Normal 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)
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user