Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authentication rework - draft2 - DONOTMERGE #4220

Draft
wants to merge 1 commit into
base: v2.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/MySQL_Authentication.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ typedef struct _account_details_t {
char *username;
char *password;
void *sha1_pass;
bool use_ssl;
int default_hostgroup;
char *clear_text_password;
char *default_schema;
int default_hostgroup;
bool use_ssl;
bool schema_locked;
bool transaction_persistent;
bool fast_forward;
Expand Down Expand Up @@ -79,6 +80,7 @@ class MySQL_Authentication {
void set_all_inactive(enum cred_username_type usertype);
void remove_inactives(enum cred_username_type usertype);
bool set_SHA1(char *username, enum cred_username_type usertype, void *sha_pass);
bool set_clear_text_password(char *username, enum cred_username_type usertype, const char *clear_text_password);
unsigned int memory_usage();
uint64_t get_runtime_checksum();
/**
Expand Down
3 changes: 2 additions & 1 deletion include/MySQL_Data_Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ class MySQL_Data_Stream
int status; // status . FIXME: make it a ORable variable

int switching_auth_stage;
int switching_auth_type;
enum proxysql_auth_plugins switching_auth_type;
int auth_in_progress; // if 0 , no authentication is in progress. Any value greater than 0 depends from the implementation
unsigned int tmp_charset;

short revents;
Expand Down
62 changes: 62 additions & 0 deletions include/MySQL_Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ extern MySQL_Variables mysql_variables;
#define CLIENT_DEPRECATE_EOF (1UL << 24)
#endif


enum proxysql_auth_plugins {
AUTH_UNKNOWN_PLUGIN = -1,
AUTH_MYSQL_NATIVE_PASSWORD = 0,
AUTH_MYSQL_CLEAR_PASSWORD,
AUTH_MYSQL_CACHING_SHA2_PASSWORD
};

class MySQL_ResultSet {
private:
bool deprecate_eof_active;
Expand Down Expand Up @@ -91,6 +99,36 @@ uint8_t mysql_decode_length(unsigned char *ptr, uint64_t *len);
*/
my_bool proxy_mysql_stmt_close(MYSQL_STMT* mysql_stmt);

class MyProt_tmp_auth_vars {
public:
unsigned char *user = NULL;
char *db = NULL;
char *db_tmp = NULL;
unsigned char *pass = NULL;
char *password = NULL;
unsigned char *auth_plugin = NULL;
void *sha1_pass=NULL;
unsigned char *_ptr = NULL;;
unsigned int charset;
uint32_t capabilities = 0;
uint32_t max_pkt;
uint32_t pass_len;
bool use_ssl = false;
enum proxysql_session_type session_type;
};

class MyProt_tmp_auth_attrs {
public:
char *default_schema = NULL;
char *attributes = NULL;
int default_hostgroup=-1;
int max_connections;
bool schema_locked;
bool transaction_persistent = true;
bool fast_forward = false;
bool _ret_use_ssl = false;
};

class MySQL_Protocol {
private:
MySQL_Connection_userinfo *userinfo;
Expand All @@ -101,10 +139,16 @@ class MySQL_Protocol {
bool dump_pkt;
#endif
MySQL_Prepared_Stmt_info *current_PreStmt;
enum proxysql_auth_plugins sent_auth_plugin_id;
enum proxysql_auth_plugins auth_plugin_id;
uint16_t prot_status;
bool more_data_needed;
MySQL_Data_Stream *get_myds() { return *myds; }
MySQL_Protocol() {
sent_auth_plugin_id = AUTH_MYSQL_NATIVE_PASSWORD;
auth_plugin_id = AUTH_UNKNOWN_PLUGIN;
prot_status=0;
more_data_needed = false;
}
void init(MySQL_Data_Stream **, MySQL_Connection_userinfo *, MySQL_Session *);

Expand Down Expand Up @@ -139,6 +183,24 @@ class MySQL_Protocol {
// - pointer to the packet
// - size of the packet
bool process_pkt_handshake_response(unsigned char *pkt, unsigned int len);

// all the following functions were inline inside process_pkt_handshake_response() , but it was split for readibility
int PPHR_1(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
bool PPHR_2(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
void PPHR_3(MyProt_tmp_auth_vars& vars1);
bool PPHR_4auth0(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
bool PPHR_4auth1(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1);
void PPHR_5passwordTrue(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, MyProt_tmp_auth_attrs& attr1);
void PPHR_5passwordFalse_0(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, MyProt_tmp_auth_attrs& attr1);
void PPHR_5passwordFalse_auth2(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, MyProt_tmp_auth_attrs& attr1 , void *& sha1_pass);
void PPHR_6auth2(bool& ret, MyProt_tmp_auth_vars& vars1);
void PPHR_sha2full(bool& ret, MyProt_tmp_auth_vars& vars1, enum proxysql_auth_plugins passformat);
void PPHR_7auth1(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, MyProt_tmp_auth_attrs& attr1 , void *& sha1_pass);
void PPHR_7auth2(unsigned char *pkt, unsigned int len, bool& ret, MyProt_tmp_auth_vars& vars1, char * reply, MyProt_tmp_auth_attrs& attr1 , void *& sha1_pass);
void PPHR_SetConnAttrs(MyProt_tmp_auth_vars& vars1, MyProt_tmp_auth_attrs& attr1);

void generate_one_byte_pkt(unsigned char b);

bool process_pkt_COM_CHANGE_USER(unsigned char *pkt, unsigned int len);
void * Query_String_to_packet(uint8_t sid, std::string *s, unsigned int *l);
/**
Expand Down
2 changes: 2 additions & 0 deletions include/MySQL_Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,10 @@ class MySQL_Threads_Handler
char *interfaces;
char *server_version;
char *keep_multiplexing_variables;
char *default_authentication_plugin;
//unsigned int default_charset; // removed in 2.0.13 . Obsoleted previously using MySQL_Variables instead
int handle_unknown_charset;
int default_authentication_plugin_int;
bool servers_stats;
bool commands_stats;
bool query_digests;
Expand Down
2 changes: 1 addition & 1 deletion include/SQLite3_Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class SQLite3_Server {
char *telnet_admin_ifaces;
char *telnet_stats_ifaces;
bool read_only;
bool hash_passwords;
// bool hash_passwords;
char * admin_version;
#ifdef DEBUG
bool debug;
Expand Down
2 changes: 1 addition & 1 deletion include/proxysql_admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ class ProxySQL_Admin {
char *telnet_admin_ifaces;
char *telnet_stats_ifaces;
bool admin_read_only;
bool hash_passwords;
// bool hash_passwords;
bool vacuum_stats;
char * admin_version;
char * cluster_username;
Expand Down
4 changes: 4 additions & 0 deletions include/proxysql_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -775,11 +775,13 @@ MySQL_HostGroups_Manager *MyHGM;
__thread char *mysql_thread___default_schema;
__thread char *mysql_thread___server_version;
__thread char *mysql_thread___keep_multiplexing_variables;
__thread char *mysql_thread___default_authentication_plugin;
__thread char *mysql_thread___init_connect;
__thread char *mysql_thread___ldap_user_variable;
__thread char *mysql_thread___default_tx_isolation;
__thread char *mysql_thread___default_session_track_gtids;
__thread char *mysql_thread___firewall_whitelist_errormsg;
__thread int mysql_thread___default_authentication_plugin_int;
__thread int mysql_thread___max_allowed_packet;
__thread bool mysql_thread___automatic_detect_sqli;
__thread bool mysql_thread___firewall_whitelist_enabled;
Expand Down Expand Up @@ -944,11 +946,13 @@ extern MySQL_HostGroups_Manager *MyHGM;
extern __thread char *mysql_thread___default_schema;
extern __thread char *mysql_thread___server_version;
extern __thread char *mysql_thread___keep_multiplexing_variables;
extern __thread char *mysql_thread___default_authentication_plugin;
extern __thread char *mysql_thread___init_connect;
extern __thread char *mysql_thread___ldap_user_variable;
extern __thread char *mysql_thread___default_tx_isolation;
extern __thread char *mysql_thread___default_session_track_gtids;
extern __thread char *mysql_thread___firewall_whitelist_errormsg;
extern __thread int mysql_thread___default_authentication_plugin_int;
extern __thread int mysql_thread___max_allowed_packet;
extern __thread bool mysql_thread___automatic_detect_sqli;
extern __thread bool mysql_thread___firewall_whitelist_enabled;
Expand Down
3 changes: 2 additions & 1 deletion lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ MYCXXFLAGS=-std=c++11 $(MYCFLAGS) $(PSQLCH) $(ENABLE_EPOLL)
default: libproxysql.a
.PHONY: default

_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo ProxySQL_Config.oo ProxySQL_Restapi.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo ClickHouse_Authentication.oo ClickHouse_Server.oo ProxySQL_Statistics.oo Chart_bundle_js.oo ProxySQL_HTTP_Server.oo ProxySQL_RESTAPI_Server.oo font-awesome.min.css.oo main-bundle.min.css.oo set_parser.oo MySQL_Variables.oo c_tokenizer.oo proxysql_utils.oo proxysql_coredump.oo proxysql_sslkeylog.oo
_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo ProxySQL_Config.oo ProxySQL_Restapi.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo ClickHouse_Authentication.oo ClickHouse_Server.oo ProxySQL_Statistics.oo Chart_bundle_js.oo ProxySQL_HTTP_Server.oo ProxySQL_RESTAPI_Server.oo font-awesome.min.css.oo main-bundle.min.css.oo set_parser.oo MySQL_Variables.oo c_tokenizer.oo proxysql_utils.oo proxysql_coredump.oo proxysql_sslkeylog.oo \
sha256crypt.oo
OBJ_CXX = $(patsubst %,$(ODIR)/%,$(_OBJ_CXX))
HEADERS = ../include/*.h ../include/*.hpp

Expand Down
56 changes: 55 additions & 1 deletion lib/MySQL_Authentication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,18 @@ bool MySQL_Authentication::add(char * username, char * password, enum cred_usern
if (lookup != cg.bt_map.end()) {
ad=lookup->second;
if (strcmp(ad->password,password)) {
// the password has changed
free(ad->password);
ad->password=strdup(password);
if (ad->sha1_pass) {
free(ad->sha1_pass);
ad->sha1_pass=NULL;
}
if (ad->clear_text_password) {
free(ad->clear_text_password);
ad->clear_text_password=NULL;
}
// FIXME: if the password is a clear text password, automatically generate sha1_pass and clear_text_password
}
if (strcmp(ad->default_schema,default_schema)) {
free(ad->default_schema);
Expand Down Expand Up @@ -195,6 +201,8 @@ bool MySQL_Authentication::add(char * username, char * password, enum cred_usern
new_ad=true;
ad->sha1_pass=NULL;
ad->num_connections_used=0;
ad->clear_text_password = NULL;
// FIXME: if the password is a clear text password, automatically generate sha1_pass and clear_text_password
}

ad->use_ssl=use_ssl;
Expand Down Expand Up @@ -233,6 +241,7 @@ unsigned int MySQL_Authentication::memory_usage() {
if (ado->username) ret += strlen(ado->username) + 1;
if (ado->password) ret += strlen(ado->password) + 1;
if (ado->sha1_pass) ret += SHA_DIGEST_LENGTH;
if (ado->clear_text_password) ret += strlen(ado->clear_text_password) + 1;
if (ado->default_schema) ret += strlen(ado->default_schema) + 1;
if (ado->comment) ret += strlen(ado->comment) + 1;
if (ado->attributes) ret += strlen(ado->attributes) + 1;
Expand All @@ -246,6 +255,7 @@ unsigned int MySQL_Authentication::memory_usage() {
if (ado->username) ret += strlen(ado->username) + 1;
if (ado->password) ret += strlen(ado->password) + 1;
if (ado->sha1_pass) ret += SHA_DIGEST_LENGTH;
if (ado->clear_text_password) ret += strlen(ado->clear_text_password) + 1;
if (ado->default_schema) ret += strlen(ado->default_schema) + 1;
if (ado->comment) ret += strlen(ado->comment) + 1;
if (ado->attributes) ret += strlen(ado->attributes) + 1;
Expand Down Expand Up @@ -297,6 +307,7 @@ int MySQL_Authentication::dump_all_users(account_details_t ***ads, bool _complet
ad->num_connections_used=ado->num_connections_used;
ad->password=strdup(ado->password);
ad->sha1_pass=NULL;
ad->clear_text_password = NULL;
ad->use_ssl=ado->use_ssl;
ad->default_schema=strdup(ado->default_schema);
ad->attributes=strdup(ado->attributes);
Expand All @@ -318,6 +329,7 @@ int MySQL_Authentication::dump_all_users(account_details_t ***ads, bool _complet
ad->username=strdup(ado->username);
ad->password=strdup(ado->password);
ad->sha1_pass=NULL;
ad->clear_text_password = NULL;
ad->use_ssl=ado->use_ssl;
ad->default_hostgroup=ado->default_hostgroup;
ad->default_schema=strdup(ado->default_schema);
Expand Down Expand Up @@ -434,6 +446,7 @@ bool MySQL_Authentication::del(char * username, enum cred_username_type usertype
free(ad->username);
free(ad->password);
if (ad->sha1_pass) { free(ad->sha1_pass); ad->sha1_pass=NULL; }
if (ad->clear_text_password) { free(ad->clear_text_password); ad->clear_text_password=NULL; }
free(ad->default_schema);
free(ad->attributes);
free(ad->comment);
Expand Down Expand Up @@ -484,6 +497,40 @@ bool MySQL_Authentication::set_SHA1(char * username, enum cred_username_type use
return ret;
};

bool MySQL_Authentication::set_clear_text_password(char * username, enum cred_username_type usertype, const char *clear_text_password) {
bool ret=false;
uint64_t hash1, hash2;
SpookyHash *myhash=new SpookyHash();
myhash->Init(1,2);
myhash->Update(username,strlen(username));
myhash->Final(&hash1,&hash2);
delete myhash;

creds_group_t &cg=(usertype==USERNAME_BACKEND ? creds_backends : creds_frontends);

#ifdef PROXYSQL_AUTH_PTHREAD_MUTEX
pthread_rwlock_wrlock(&cg.lock);
#else
spin_wrlock(&cg.lock);
#endif
std::map<uint64_t, account_details_t *>::iterator lookup;
lookup = cg.bt_map.find(hash1);
if (lookup != cg.bt_map.end()) {
account_details_t *ad=lookup->second;
if (ad->clear_text_password) { free(ad->clear_text_password); ad->clear_text_password=NULL; }
if (clear_text_password) {
ad->clear_text_password = strdup(clear_text_password);
}
ret=true;
}
#ifdef PROXYSQL_AUTH_PTHREAD_MUTEX
pthread_rwlock_unlock(&cg.lock);
#else
spin_wrunlock(&cg.lock);
#endif
return ret;
};

bool MySQL_Authentication::exists(char * username) {
bool ret = false;
uint64_t hash1, hash2;
Expand Down Expand Up @@ -522,7 +569,13 @@ char * MySQL_Authentication::lookup(char * username, enum cred_username_type use
lookup = cg.bt_map.find(hash1);
if (lookup != cg.bt_map.end()) {
account_details_t *ad=lookup->second;
ret=l_strdup(ad->password);
if (ad->clear_text_password == NULL) {
ret=strdup(ad->password);
} else {
// we return the best password we have
// if we were able to derive the clear text password, we provide that
ret=strdup(ad->clear_text_password);
}
if (use_ssl) *use_ssl=ad->use_ssl;
if (default_hostgroup) *default_hostgroup=ad->default_hostgroup;
if (default_schema) *default_schema=l_strdup(ad->default_schema);
Expand Down Expand Up @@ -565,6 +618,7 @@ bool MySQL_Authentication::_reset(enum cred_username_type usertype) {
free(ad->username);
free(ad->password);
if (ad->sha1_pass) { free(ad->sha1_pass); ad->sha1_pass=NULL; }
if (ad->clear_text_password) { free(ad->clear_text_password); ad->clear_text_password=NULL; }
free(ad->default_schema);
free(ad->comment);
free(ad->attributes);
Expand Down
Loading
Loading