
void session_enable_log(SESSION* ses, logfile_id_t id) and void session_disable_log(SESSION* ses, logfile_id_t id) Which switch specific log type on/off if the log type in question is not generally enabled. Each thread carries a thread-specific struct log_info_t which includes members for current session id and bitfield for enabled log types for the current session. That information is checked before actual log write functions are called. Each file where session-specific logging is used, must include the following exports: /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; extern size_t log_ses_count[]; extern __thread log_info_t tls_log_info;
398 lines
11 KiB
C
398 lines
11 KiB
C
/*
|
|
* This file is distributed as part of the MariaDB Corporation MaxScale. It is free
|
|
* software: you can redistribute it and/or modify it under the terms of the
|
|
* GNU General Public License as published by the Free Software Foundation,
|
|
* version 2.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc., 51
|
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright MariaDB Corporation Ab 2013-2014
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#define _XOPEN_SOURCE
|
|
#include <unistd.h>
|
|
#include <crypt.h>
|
|
#include <users.h>
|
|
#include <adminusers.h>
|
|
#include <skygw_utils.h>
|
|
#include <log_manager.h>
|
|
|
|
/** Defined in log_manager.cc */
|
|
extern int lm_enabled_logfiles_bitmask;
|
|
extern size_t log_ses_count[];
|
|
extern __thread log_info_t tls_log_info;
|
|
|
|
/**
|
|
* @file adminusers.c - Administration user account management
|
|
*
|
|
* @verbatim
|
|
* Revision History
|
|
*
|
|
* Date Who Description
|
|
* 18/07/13 Mark Riddoch Initial implementation
|
|
* 23/07/13 Mark Riddoch Addition of error mechanism to add user
|
|
*
|
|
* @endverbatim
|
|
*/
|
|
static USERS *loadUsers();
|
|
static void initialise();
|
|
|
|
static USERS *users = NULL;
|
|
static int admin_init = 0;
|
|
|
|
static char *ADMIN_ERR_NOMEM = "Out of memory";
|
|
static char *ADMIN_ERR_FILEOPEN = "Unable to create password file";
|
|
static char *ADMIN_ERR_DUPLICATE = "Duplicate username specified";
|
|
static char *ADMIN_ERR_USERNOTFOUND = "User not found";
|
|
static char *ADMIN_ERR_AUTHENTICATION = "Authentication failed";
|
|
static char *ADMIN_ERR_FILEAPPEND = "Unable to append to password file";
|
|
static char *ADMIN_ERR_PWDFILEOPEN = "Failed to open password file";
|
|
static char *ADMIN_ERR_TMPFILEOPEN = "Failed to open temporary password file";
|
|
static char *ADMIN_ERR_PWDFILEACCESS = "Failed to access password file";
|
|
static char *ADMIN_ERR_DELLASTUSER = "Deleting the last user is forbidden";
|
|
static char *ADMIN_SUCCESS = NULL;
|
|
|
|
static const int LINELEN=80;
|
|
|
|
/**
|
|
* Admin Users initialisation
|
|
*/
|
|
static void
|
|
initialise()
|
|
{
|
|
if (admin_init)
|
|
return;
|
|
admin_init = 1;
|
|
users = loadUsers();
|
|
}
|
|
|
|
/**
|
|
* 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, "skysql") == 0)
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if ((pw = users_fetch(users, username)) == NULL)
|
|
return 0;
|
|
if (strcmp(pw, crypt(password, ADMIN_SALT)) == 0)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Load the admin users
|
|
*
|
|
* @return Table of users
|
|
*/
|
|
static USERS *
|
|
loadUsers()
|
|
{
|
|
USERS *rval;
|
|
FILE *fp;
|
|
char fname[1024], *home;
|
|
char uname[80], passwd[80];
|
|
|
|
initialise();
|
|
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){
|
|
sprintf(fname, "%s/etc/passwd", home);
|
|
}
|
|
else{
|
|
sprintf(fname, "/usr/local/skysql/MaxScale/etc/passwd");
|
|
}
|
|
if ((fp = fopen(fname, "r")) == NULL)
|
|
return NULL;
|
|
if ((rval = users_alloc()) == NULL)
|
|
{
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
while (fscanf(fp, "%[^:]:%s\n", uname, passwd) == 2)
|
|
{
|
|
users_add(rval, uname, passwd);
|
|
}
|
|
fclose(fp);
|
|
|
|
return rval;
|
|
}
|
|
|
|
/**
|
|
* Add user
|
|
*
|
|
* @param uname Name of the new user
|
|
* @param passwd Password for the new user
|
|
* @return NULL on success or an error string on failure
|
|
*/
|
|
char *
|
|
admin_add_user(char *uname, char *passwd)
|
|
{
|
|
FILE *fp;
|
|
char fname[1024], *home, *cpasswd;
|
|
|
|
initialise();
|
|
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){
|
|
sprintf(fname, "%s/etc/passwd", home);
|
|
}
|
|
else{
|
|
sprintf(fname, "/usr/local/skysql/MaxScale/etc/passwd");
|
|
}
|
|
|
|
if (users == NULL)
|
|
{
|
|
LOGIF(LM,
|
|
(skygw_log_write(LOGFILE_MESSAGE,
|
|
"Create initial password file.")));
|
|
|
|
if ((users = users_alloc()) == NULL)
|
|
return ADMIN_ERR_NOMEM;
|
|
if ((fp = fopen(fname, "w")) == NULL)
|
|
{
|
|
LOGIF(LE,
|
|
(skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to create password file %s.",
|
|
fname)));
|
|
return ADMIN_ERR_PWDFILEOPEN;
|
|
}
|
|
fclose(fp);
|
|
}
|
|
if (users_fetch(users, uname) != NULL)
|
|
{
|
|
return ADMIN_ERR_DUPLICATE;
|
|
}
|
|
cpasswd = crypt(passwd, ADMIN_SALT);
|
|
users_add(users, uname, cpasswd);
|
|
if ((fp = fopen(fname, "a")) == NULL)
|
|
{
|
|
LOGIF(LE,
|
|
(skygw_log_write_flush(LOGFILE_ERROR,
|
|
"Error : Unable to append to password file %s.",
|
|
fname)));
|
|
return ADMIN_ERR_FILEAPPEND;
|
|
}
|
|
fprintf(fp, "%s:%s\n", uname, cpasswd);
|
|
fclose(fp);
|
|
return ADMIN_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove maxscale user from in-memory structure and from password file
|
|
*
|
|
* @param uname Name of the new user
|
|
* @param passwd Password for the new user
|
|
* @return NULL on success or an error string on failure
|
|
*/
|
|
char* admin_remove_user(
|
|
char* uname,
|
|
char* passwd)
|
|
{
|
|
FILE* fp;
|
|
FILE* fp_tmp;
|
|
char fname[1024];
|
|
char fname_tmp[1024];
|
|
char* home;
|
|
char fusr[LINELEN];
|
|
char fpwd[LINELEN];
|
|
char line[LINELEN];
|
|
fpos_t rpos;
|
|
int n_deleted;
|
|
|
|
if (!admin_search_user(uname)) {
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Couldn't find user %s. Removing user failed",
|
|
uname)));
|
|
return ADMIN_ERR_USERNOTFOUND;
|
|
}
|
|
|
|
if (admin_verify(uname, passwd) == 0) {
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Authentication failed, wrong user/password "
|
|
"combination. Removing user failed.")));
|
|
return ADMIN_ERR_AUTHENTICATION;
|
|
}
|
|
|
|
|
|
/** Remove user from in-memory structure */
|
|
n_deleted = users_delete(users, uname);
|
|
|
|
if (n_deleted == 0) {
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Deleting the only user is forbidden. Add new "
|
|
"user before deleting the one.")));
|
|
return ADMIN_ERR_DELLASTUSER;
|
|
}
|
|
/**
|
|
* Open passwd file and remove user from the file.
|
|
*/
|
|
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024) {
|
|
sprintf(fname, "%s/etc/passwd", home);
|
|
sprintf(fname_tmp, "%s/etc/passwd_tmp", home);
|
|
} else {
|
|
sprintf(fname, "/usr/local/skysql/MaxScale/etc/passwd");
|
|
sprintf(fname_tmp, "/usr/local/skysql/MaxScale/etc/passwd_tmp");
|
|
}
|
|
/**
|
|
* Rewrite passwd file from memory.
|
|
*/
|
|
if ((fp = fopen(fname, "r")) == NULL)
|
|
{
|
|
int err = errno;
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to open password file %s : errno %d.\n"
|
|
"Removing user from file failed; it must be done "
|
|
"manually.",
|
|
fname,
|
|
err)));
|
|
return ADMIN_ERR_PWDFILEOPEN;
|
|
}
|
|
/**
|
|
* Open temporary passwd file.
|
|
*/
|
|
if ((fp_tmp = fopen(fname_tmp, "w")) == NULL)
|
|
{
|
|
int err = errno;
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to open tmp file %s : errno %d.\n"
|
|
"Removing user from passwd file failed; it must be done "
|
|
"manually.",
|
|
fname_tmp,
|
|
err)));
|
|
fclose(fp);
|
|
return ADMIN_ERR_TMPFILEOPEN;
|
|
}
|
|
|
|
/**
|
|
* Scan passwd and copy all but matching lines to temp file.
|
|
*/
|
|
if (fgetpos(fp, &rpos) != 0) {
|
|
int err = errno;
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to process passwd file %s : errno %d.\n"
|
|
"Removing user from file failed, and must be done "
|
|
"manually.",
|
|
fname,
|
|
err)));
|
|
fclose(fp);
|
|
fclose(fp_tmp);
|
|
unlink(fname_tmp);
|
|
return ADMIN_ERR_PWDFILEACCESS;
|
|
}
|
|
|
|
while (fscanf(fp, "%[^:]:%s\n", fusr, fpwd) == 2)
|
|
{
|
|
/**
|
|
* Compare username what was found from passwd file.
|
|
* Unmatching lines are copied to tmp file.
|
|
*/
|
|
if (strncmp(uname, fusr, strlen(uname)+1) != 0) {
|
|
if(fsetpos(fp, &rpos) != 0){ /** one step back */
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to set stream position. ")));
|
|
|
|
}
|
|
fgets(line, LINELEN, fp);
|
|
fputs(line, fp_tmp);
|
|
}
|
|
|
|
if (fgetpos(fp, &rpos) != 0) {
|
|
int err = errno;
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to process passwd file %s : "
|
|
"errno %d.\n"
|
|
"Removing user from file failed, and must be "
|
|
"done manually.",
|
|
fname,
|
|
err)));
|
|
fclose(fp);
|
|
fclose(fp_tmp);
|
|
unlink(fname_tmp);
|
|
return ADMIN_ERR_PWDFILEACCESS;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
/**
|
|
* Replace original passwd file with new.
|
|
*/
|
|
if (rename(fname_tmp, fname)) {
|
|
int err = errno;
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to rename new passwd file %s : errno "
|
|
"%d.\n"
|
|
"Rename it to %s manually.",
|
|
fname_tmp,
|
|
err,
|
|
fname)));
|
|
unlink(fname_tmp);
|
|
fclose(fp_tmp);
|
|
return ADMIN_ERR_PWDFILEACCESS;
|
|
}
|
|
fclose(fp_tmp);
|
|
return ADMIN_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Check for existance of the user
|
|
*
|
|
* @param user The user name to test
|
|
* @return Non-zero if the user exists
|
|
*/
|
|
int
|
|
admin_search_user(char *user)
|
|
{
|
|
initialise();
|
|
if (users == NULL)
|
|
return 0;
|
|
return users_fetch(users, user) != NULL;
|
|
}
|
|
|
|
/**
|
|
* Print the statistics and user names of the administration users
|
|
*
|
|
* @param dcb A DCB to send the output to
|
|
*/
|
|
void
|
|
dcb_PrintAdminUsers(DCB *dcb)
|
|
{
|
|
if (users)
|
|
dcb_usersPrint(dcb, users);
|
|
else
|
|
dcb_printf(dcb, "No administration users have been defined.\n");
|
|
}
|