 fd11e6a7f5
			
		
	
	fd11e6a7f5
	
	
	
		
			
			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");
 | |
| }
 |