Whitespace and indentation changes.

Also changed line-endings from DOS CRLF to only LF.
In addition, made functions const correct.
This commit is contained in:
Johan Wikman
2015-11-09 13:55:59 +02:00
parent 14b8dbc4d8
commit 90a8646ac2
2 changed files with 437 additions and 425 deletions

View File

@ -1,415 +1,426 @@
/* /*
* This file is distributed as part of the MariaDB Corporation MaxScale. It is free * 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 * 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, * GNU General Public License as published by the Free Software Foundation,
* version 2. * version 2.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. * details.
* *
* You should have received a copy of the GNU General Public License along with * 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 * this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* *
* Copyright MariaDB Corporation Ab 2013-2014 * Copyright MariaDB Corporation Ab 2013-2014
*/ */
#include <secrets.h> #include <secrets.h>
#include <time.h> #include <time.h>
#include <skygw_utils.h> #include <skygw_utils.h>
#include <log_manager.h> #include <log_manager.h>
#include <ctype.h> #include <ctype.h>
#include <mysql_client_server_protocol.h> #include <mysql_client_server_protocol.h>
#include <gwdirs.h> #include <gwdirs.h>
/** /**
* Generate a random printable character * Generate a random printable character
* *
* @return A random printable character * @return A random printable character
*/ */
static unsigned char static unsigned char
secrets_randomchar() secrets_randomchar()
{ {
return (char)((rand() % ('~' - ' ')) + ' '); return (char)((rand() % ('~' - ' ')) + ' ');
} }
static int static int
secrets_random_str(unsigned char *output, int len) secrets_random_str(unsigned char *output, int len)
{ {
int i; int i;
srand((unsigned long )time(0L) ^ (unsigned long )output); srand((unsigned long )time(0L) ^ (unsigned long )output);
for ( i = 0; i < len; ++i ) for (i = 0; i < len; ++i)
{ {
output[i] = secrets_randomchar(); output[i] = secrets_randomchar();
} }
return 0; return 0;
} }
/** /**
* This routine reads data from a binary file named ".secrets" and extracts the AES encryption key * This routine reads data from a binary file named ".secrets" and extracts the AES encryption key
* and the AES Init Vector. * and the AES Init Vector.
* If the path parameter is not null the custom path is interpreted as a folder * If the path parameter is not null the custom path is interpreted as a folder
* containing the .secrets file. Otherwise the default location is used. * containing the .secrets file. Otherwise the default location is used.
* @return The keys structure or NULL on error * @return The keys structure or NULL on error
*/ */
static MAXKEYS * static MAXKEYS *
secrets_readKeys(char* path) secrets_readKeys(const char* path)
{ {
char secret_file[PATH_MAX+1]; char secret_file[PATH_MAX+1];
char *home; char *home;
MAXKEYS *keys; MAXKEYS *keys;
struct stat secret_stats; struct stat secret_stats;
int fd; int fd;
int len; int len;
static int reported = 0; static int reported = 0;
if(path != NULL)
snprintf(secret_file, PATH_MAX, "%s/.secrets", path); if (path != NULL)
else {
snprintf(secret_file, PATH_MAX, "%s/.secrets", get_datadir()); snprintf(secret_file, PATH_MAX, "%s/.secrets", path);
/* Try to access secrets file */ }
if (access(secret_file, R_OK) == -1) else
{ {
int eno = errno; snprintf(secret_file, PATH_MAX, "%s/.secrets", get_datadir());
errno = 0; }
if (eno == ENOENT)
{ /* Try to access secrets file */
if (!reported) if (access(secret_file, R_OK) == -1)
{ {
char errbuf[STRERROR_BUFLEN]; int eno = errno;
LOGIF(LM, (skygw_log_write( errno = 0;
LOGFILE_MESSAGE, if (eno == ENOENT)
"Encrypted password file %s can't be accessed " {
"(%s). Password encryption is not used.", if (!reported)
secret_file, {
strerror_r(eno, errbuf, sizeof(errbuf))))); char errbuf[STRERROR_BUFLEN];
reported = 1; LOGIF(LM, (skygw_log_write(
} LOGFILE_MESSAGE,
} "Encrypted password file %s can't be accessed "
else "(%s). Password encryption is not used.",
{ secret_file,
char errbuf[STRERROR_BUFLEN]; strerror_r(eno, errbuf, sizeof(errbuf)))));
LOGIF(LE, (skygw_log_write_flush( reported = 1;
LOGFILE_ERROR, }
"Error : access for secrets file " }
"[%s] failed. Error %d, %s.", else
secret_file, {
eno, char errbuf[STRERROR_BUFLEN];
strerror_r(eno, errbuf, sizeof(errbuf))))); LOGIF(LE, (skygw_log_write_flush(
} LOGFILE_ERROR,
return NULL; "Error : access for secrets file "
} "[%s] failed. Error %d, %s.",
secret_file,
/* open secret file */ eno,
if ((fd = open(secret_file, O_RDONLY)) < 0) strerror_r(eno, errbuf, sizeof(errbuf)))));
{ }
int eno = errno; return NULL;
errno = 0; }
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush( /* open secret file */
LOGFILE_ERROR, if ((fd = open(secret_file, O_RDONLY)) < 0)
"Error : Failed opening secret " {
"file [%s]. Error %d, %s.", int eno = errno;
secret_file, errno = 0;
eno, char errbuf[STRERROR_BUFLEN];
strerror_r(eno, errbuf, sizeof(errbuf))))); LOGIF(LE, (skygw_log_write_flush(
return NULL; LOGFILE_ERROR,
"Error : Failed opening secret "
} "file [%s]. Error %d, %s.",
secret_file,
/* accessing file details */ eno,
if (fstat(fd, &secret_stats) < 0) { strerror_r(eno, errbuf, sizeof(errbuf)))));
int eno = errno; return NULL;
errno = 0;
close(fd); }
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush( /* accessing file details */
LOGFILE_ERROR, if (fstat(fd, &secret_stats) < 0) {
"Error : fstat for secret file %s " int eno = errno;
"failed. Error %d, %s.", errno = 0;
secret_file, close(fd);
eno, char errbuf[STRERROR_BUFLEN];
strerror_r(eno, errbuf, sizeof(errbuf))))); LOGIF(LE, (skygw_log_write_flush(
return NULL; LOGFILE_ERROR,
} "Error : fstat for secret file %s "
"failed. Error %d, %s.",
if (secret_stats.st_size != sizeof(MAXKEYS)) secret_file,
{ eno,
int eno = errno; strerror_r(eno, errbuf, sizeof(errbuf)))));
errno = 0; return NULL;
close(fd); }
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush( if (secret_stats.st_size != sizeof(MAXKEYS))
LOGFILE_ERROR, {
"Error : Secrets file %s has " int eno = errno;
"incorrect size. Error %d, %s.", errno = 0;
secret_file, close(fd);
eno, char errbuf[STRERROR_BUFLEN];
strerror_r(eno, errbuf, sizeof(errbuf))))); LOGIF(LE, (skygw_log_write_flush(
return NULL; LOGFILE_ERROR,
} "Error : Secrets file %s has "
if (secret_stats.st_mode != (S_IRUSR|S_IFREG)) "incorrect size. Error %d, %s.",
{ secret_file,
close(fd); eno,
LOGIF(LE, (skygw_log_write_flush( strerror_r(eno, errbuf, sizeof(errbuf)))));
LOGFILE_ERROR, return NULL;
"Error : Ignoring secrets file " }
"%s, invalid permissions.",
secret_file))); if (secret_stats.st_mode != (S_IRUSR|S_IFREG))
return NULL; {
} close(fd);
LOGIF(LE, (skygw_log_write_flush(
if ((keys = (MAXKEYS *)malloc(sizeof(MAXKEYS))) == NULL) LOGFILE_ERROR,
{ "Error : Ignoring secrets file "
close(fd); "%s, invalid permissions.",
LOGIF(LE, (skygw_log_write_flush( secret_file)));
LOGFILE_ERROR, return NULL;
"Error : Memory allocation failed " }
"for key structure.")));
return NULL; if ((keys = (MAXKEYS *)malloc(sizeof(MAXKEYS))) == NULL)
} {
close(fd);
/** LOGIF(LE, (skygw_log_write_flush(
* Read all data from file. LOGFILE_ERROR,
* MAXKEYS (secrets.h) is struct for key, _not_ length-related macro. "Error : Memory allocation failed "
*/ "for key structure.")));
len = read(fd, keys, sizeof(MAXKEYS)); return NULL;
}
if (len != sizeof(MAXKEYS))
{ /**
int eno = errno; * Read all data from file.
errno = 0; * MAXKEYS (secrets.h) is struct for key, _not_ length-related macro.
close(fd); */
free(keys); len = read(fd, keys, sizeof(MAXKEYS));
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush( if (len != sizeof(MAXKEYS))
LOGFILE_ERROR, {
"Error : Read from secrets file " int eno = errno;
"%s failed. Read %d, expected %d bytes. Error %d, %s.", errno = 0;
secret_file, close(fd);
len, free(keys);
sizeof(MAXKEYS), char errbuf[STRERROR_BUFLEN];
eno, LOGIF(LE, (skygw_log_write_flush(
strerror_r(eno, errbuf, sizeof(errbuf))))); LOGFILE_ERROR,
return NULL; "Error : Read from secrets file "
} "%s failed. Read %d, expected %d bytes. Error %d, %s.",
secret_file,
/* Close the file */ len,
if (close(fd) < 0) { sizeof(MAXKEYS),
int eno = errno; eno,
errno = 0; strerror_r(eno, errbuf, sizeof(errbuf)))));
free(keys); return NULL;
char errbuf[STRERROR_BUFLEN]; }
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR, /* Close the file */
"Error : Failed closing the " if (close(fd) < 0) {
"secrets file %s. Error %d, %s.", int eno = errno;
secret_file, errno = 0;
eno, free(keys);
strerror_r(eno, errbuf, sizeof(errbuf))))); char errbuf[STRERROR_BUFLEN];
return NULL; LOGIF(LE, (skygw_log_write_flush(
} LOGFILE_ERROR,
ss_dassert(keys != NULL); "Error : Failed closing the "
return keys; "secrets file %s. Error %d, %s.",
} secret_file,
eno,
/** strerror_r(eno, errbuf, sizeof(errbuf)))));
* secrets_writeKeys return NULL;
* }
* This routine writes into a binary file the AES encryption key ss_dassert(keys != NULL);
* and the AES Init Vector return keys;
* }
* @param secret_file The file with secret keys
* @return 0 on success and 1 on failure /**
*/ * secrets_writeKeys
int secrets_writeKeys(char *path) *
{ * This routine writes into a binary file the AES encryption key
int fd,randfd; * and the AES Init Vector
unsigned int randval; *
MAXKEYS key; * @param secret_file The file with secret keys
char secret_file[PATH_MAX + 10]; * @return 0 on success and 1 on failure
*/
if(strlen(path) > PATH_MAX) int secrets_writeKeys(const char *path)
{ {
skygw_log_write(LOGFILE_ERROR,"Error: Pathname too long."); int fd,randfd;
return 1; unsigned int randval;
} MAXKEYS key;
char secret_file[PATH_MAX + 10];
snprintf(secret_file,PATH_MAX + 9,"%s/.secrets",path);
secret_file[PATH_MAX + 9] = '\0'; if (strlen(path) > PATH_MAX)
{
/* Open for writing | Create | Truncate the file for writing */ skygw_log_write(LOGFILE_ERROR,"Error: Pathname too long.");
if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0) return 1;
{ }
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush( snprintf(secret_file,PATH_MAX + 9,"%s/.secrets",path);
LOGFILE_ERROR, secret_file[PATH_MAX + 9] = '\0';
"Error : failed opening secret "
"file [%s]. Error %d, %s.", /* Open for writing | Create | Truncate the file for writing */
secret_file, if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0)
errno, {
strerror_r(errno, errbuf, sizeof(errbuf))))); char errbuf[STRERROR_BUFLEN];
return 1; LOGIF(LE, (skygw_log_write_flush(
} LOGFILE_ERROR,
"Error : failed opening secret "
/* Open for writing | Create | Truncate the file for writing */ "file [%s]. Error %d, %s.",
if ((randfd = open("/dev/random", O_RDONLY)) < 0) secret_file,
{ errno,
char errbuf[STRERROR_BUFLEN]; strerror_r(errno, errbuf, sizeof(errbuf)))));
LOGIF(LE, (skygw_log_write_flush( return 1;
LOGFILE_ERROR, }
"Error : failed opening /dev/random. Error %d, %s.",
errno, /* Open for writing | Create | Truncate the file for writing */
strerror_r(errno, errbuf, sizeof(errbuf))))); if ((randfd = open("/dev/random", O_RDONLY)) < 0)
close(fd); {
return 1; char errbuf[STRERROR_BUFLEN];
} LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
if(read(randfd,(void*)&randval,sizeof(unsigned int)) < 1) "Error : failed opening /dev/random. Error %d, %s.",
{ errno,
LOGIF(LE, (skygw_log_write_flush( strerror_r(errno, errbuf, sizeof(errbuf)))));
LOGFILE_ERROR, close(fd);
"Error : failed to read /dev/random."))); return 1;
close(fd); }
close(randfd);
return 1; if (read(randfd,(void*)&randval,sizeof(unsigned int)) < 1)
} {
LOGIF(LE, (skygw_log_write_flush(
close(randfd); LOGFILE_ERROR,
srand(randval); "Error : failed to read /dev/random.")));
secrets_random_str(key.enckey, MAXSCALE_KEYLEN); close(fd);
secrets_random_str(key.initvector, MAXSCALE_IV_LEN); close(randfd);
return 1;
/* Write data */ }
if (write(fd, &key, sizeof(key)) < 0)
{ close(randfd);
char errbuf[STRERROR_BUFLEN]; srand(randval);
LOGIF(LE, (skygw_log_write_flush( secrets_random_str(key.enckey, MAXSCALE_KEYLEN);
LOGFILE_ERROR, secrets_random_str(key.initvector, MAXSCALE_IV_LEN);
"Error : failed writing into "
"secret file [%s]. Error %d, %s.", /* Write data */
secret_file, if (write(fd, &key, sizeof(key)) < 0)
errno, {
strerror_r(errno, errbuf, sizeof(errbuf))))); char errbuf[STRERROR_BUFLEN];
close(fd); LOGIF(LE, (skygw_log_write_flush(
return 1; LOGFILE_ERROR,
} "Error : failed writing into "
"secret file [%s]. Error %d, %s.",
/* close file */ secret_file,
if (close(fd) < 0) errno,
{ strerror_r(errno, errbuf, sizeof(errbuf)))));
char errbuf[STRERROR_BUFLEN]; close(fd);
LOGIF(LE, (skygw_log_write_flush( return 1;
LOGFILE_ERROR, }
"Error : failed closing the "
"secret file [%s]. Error %d, %s.", /* close file */
secret_file, if (close(fd) < 0)
errno, {
strerror_r(errno, errbuf, sizeof(errbuf))))); char errbuf[STRERROR_BUFLEN];
} LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
if( chmod(secret_file, S_IRUSR) < 0) "Error : failed closing the "
{ "secret file [%s]. Error %d, %s.",
char errbuf[STRERROR_BUFLEN]; secret_file,
LOGIF(LE, (skygw_log_write_flush( errno,
LOGFILE_ERROR, strerror_r(errno, errbuf, sizeof(errbuf)))));
"Error : failed to change the permissions of the" }
"secret file [%s]. Error %d, %s.",
secret_file, if (chmod(secret_file, S_IRUSR) < 0)
errno, {
strerror_r(errno, errbuf, sizeof(errbuf))))); char errbuf[STRERROR_BUFLEN];
} LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
return 0; "Error : failed to change the permissions of the"
} "secret file [%s]. Error %d, %s.",
secret_file,
/** errno,
* Decrypt a password that is stored inthe MaxScale configuration file. strerror_r(errno, errbuf, sizeof(errbuf)))));
* If the password is not encrypted, ie is not a HEX string, then the }
* original is returned, this allows for backward compatibility with
* unencrypted password. return 0;
* }
* Note the return is always a malloc'd string that the caller must free
* /**
* @param crypt The encrypted password * Decrypt a password that is stored inthe MaxScale configuration file.
* @return The decrypted password * If the password is not encrypted, ie is not a HEX string, then the
*/ * original is returned, this allows for backward compatibility with
char * * unencrypted password.
decryptPassword(char *crypt) *
{ * Note the return is always a malloc'd string that the caller must free
MAXKEYS *keys; *
AES_KEY aeskey; * @param crypt The encrypted password
unsigned char *plain; * @return The decrypted password
char *ptr; */
unsigned char encrypted[80]; char *
int enlen; decryptPassword(const char *crypt)
{
keys = secrets_readKeys(NULL); MAXKEYS *keys;
if (!keys) AES_KEY aeskey;
return strdup(crypt); unsigned char *plain;
/* const char *ptr;
** If the input is not a HEX string return the input unsigned char encrypted[80];
** it probably was not encrypted int enlen;
*/
for (ptr = crypt; *ptr; ptr++) keys = secrets_readKeys(NULL);
{ if (!keys)
if (!isxdigit(*ptr)) {
{ return strdup(crypt);
free(keys); }
return strdup(crypt); /*
} ** If the input is not a HEX string return the input
} ** it probably was not encrypted
*/
enlen = strlen(crypt) / 2; for (ptr = crypt; *ptr; ptr++)
gw_hex2bin(encrypted, crypt, strlen(crypt)); {
if (!isxdigit(*ptr))
if ((plain = (unsigned char *)malloc(80)) == NULL) {
{ free(keys);
free(keys); return strdup(crypt);
return NULL; }
} }
AES_set_decrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey); enlen = strlen(crypt) / 2;
gw_hex2bin(encrypted, crypt, strlen(crypt));
AES_cbc_encrypt(encrypted, plain, enlen, &aeskey, keys->initvector, AES_DECRYPT);
free(keys); if ((plain = (unsigned char *)malloc(80)) == NULL)
{
return (char *)plain; free(keys);
} return NULL;
}
/**
* Encrypt a password that can be stored in the MaxScale configuration file. AES_set_decrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
*
* Note the return is always a malloc'd string that the caller must free AES_cbc_encrypt(encrypted, plain, enlen, &aeskey, keys->initvector, AES_DECRYPT);
* @param path Path the the .secrets file free(keys);
* @param password The password to encrypt
* @return The encrypted password return (char *)plain;
*/ }
char *
encryptPassword(char* path, char *password) /**
{ * Encrypt a password that can be stored in the MaxScale configuration file.
MAXKEYS *keys; *
AES_KEY aeskey; * Note the return is always a malloc'd string that the caller must free
int padded_len; * @param path Path the the .secrets file
char *hex_output; * @param password The password to encrypt
unsigned char padded_passwd[80]; * @return The encrypted password
unsigned char encrypted[80]; */
char *
if ((keys = secrets_readKeys(path)) == NULL) encryptPassword(const char* path, const char *password)
return NULL; {
MAXKEYS *keys;
memset(padded_passwd, 0, 80); AES_KEY aeskey;
strncpy((char *)padded_passwd, password, 79); int padded_len;
padded_len = ((strlen(password) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; char *hex_output;
unsigned char padded_passwd[80];
AES_set_encrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey); unsigned char encrypted[80];
AES_cbc_encrypt(padded_passwd, encrypted, padded_len, &aeskey, keys->initvector, AES_ENCRYPT); if ((keys = secrets_readKeys(path)) == NULL)
hex_output = (char *)malloc(padded_len * 2); {
gw_bin2hex(hex_output, encrypted, padded_len); return NULL;
free(keys); }
return hex_output; memset(padded_passwd, 0, 80);
} strncpy((char *)padded_passwd, password, 79);
padded_len = ((strlen(password) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
AES_set_encrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
AES_cbc_encrypt(padded_passwd, encrypted, padded_len, &aeskey, keys->initvector, AES_ENCRYPT);
hex_output = (char *)malloc(padded_len * 2);
gw_bin2hex(hex_output, encrypted, padded_len);
free(keys);
return hex_output;
}

View File

@ -24,8 +24,8 @@
* @verbatim * @verbatim
* Revision History * Revision History
* *
* Date Who Description * Date Who Description
* 23/06/2013 Massimiliano Pinto Initial implementation * 23/06/2013 Massimiliano Pinto Initial implementation
* *
* @endverbatim * @endverbatim
*/ */
@ -40,18 +40,19 @@
#include <openssl/aes.h> #include <openssl/aes.h>
#define MAXSCALE_KEYLEN 32 #define MAXSCALE_KEYLEN 32
#define MAXSCALE_IV_LEN 16 #define MAXSCALE_IV_LEN 16
/** /**
* The key structure held in the secrets file * The key structure held in the secrets file
*/ */
typedef struct maxkeys { typedef struct maxkeys
unsigned char enckey[MAXSCALE_KEYLEN]; {
unsigned char initvector[MAXSCALE_IV_LEN]; unsigned char enckey[MAXSCALE_KEYLEN];
unsigned char initvector[MAXSCALE_IV_LEN];
} MAXKEYS; } MAXKEYS;
extern int secrets_writeKeys(char *filename); extern int secrets_writeKeys(const char *filename);
extern char *decryptPassword(char *); extern char *decryptPassword(const char *);
extern char *encryptPassword(char*,char *); extern char *encryptPassword(const char*, const char *);
#endif #endif