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

V2.x sha2pass draft3 #4258

Merged
merged 42 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5091edc
Refactoring of process_pkt_handshake_response
renecannao Feb 17, 2023
1b3ee81
Cleanup on MySQL_Protocol.h
renecannao Feb 17, 2023
d23b286
2nd refactoring of process_pkt_handshake_response
renecannao Feb 23, 2023
5c40ee5
Fix clickhouse compiling
renecannao Feb 23, 2023
1fa074a
3rd refactoring of process_pkt_handshake_response
renecannao Mar 3, 2023
b9473aa
Deprecate SHA1_* also in this branch
renecannao May 9, 2023
094f77a
Temporary commit 01 for caching_sha2_password
renecannao May 10, 2023
76bb204
New variable mysql-default_authentication_plugin
renecannao May 13, 2023
117b9d3
caching_sha2_password automatically enables SSL
renecannao May 13, 2023
29da662
enum proxysql_auth_plugins for mysql plugin ids
renecannao May 13, 2023
e7745fe
First implementation of caching_sha2_password
renecannao May 13, 2023
e6e6bb0
Adding sha256crypt.cpp
renecannao May 13, 2023
cf6f4f7
Working prototype of caching_sha2_password
renecannao May 14, 2023
4c704e2
Deprecate admin-hash_passwords #4218
renecannao May 14, 2023
52052de
Adding warning for deprecated admin-hash_passwords #4218
renecannao May 14, 2023
1799f7a
Stop dumping the list of cipher avaiable in DEBUG
renecannao May 14, 2023
7690798
Deprecate admin-hash_passwords in TAP tests #4218
renecannao May 14, 2023
7e5b3e8
Rememeber clear text password if provided by client
renecannao May 14, 2023
08cc2f0
Fixed length of hash + salt
renecannao May 14, 2023
a593407
Removing commented code used for POC
renecannao May 14, 2023
33b4f30
Fix TAP reg_test_3504-change_user-t for new values of switching_auth_…
renecannao May 16, 2023
629aa3d
Drafting TAP test_change_user-t
renecannao Jun 13, 2023
36183a4
Further testing in TAP test_change_user-t
renecannao Jun 13, 2023
8106ae5
Merge branch 'v2.x' into v2.x_sha2pass_draft3
renecannao Jun 14, 2023
9ede04d
Merge branch 'v2.x' into v2.x_sha2pass_draft3
renecannao Jul 1, 2023
f9b3b70
Create ProxySQL_Authentication.md
renecannao Jul 2, 2023
e3865be
Minor changes in branches
renecannao Jul 2, 2023
636d81e
Merge branch 'v2.x_sha2pass_draft3' of https://github.com/sysown/prox…
renecannao Jul 2, 2023
3c24182
Merge branch 'v2.x' into v2.x_sha2pass_draft3
renecannao Dec 8, 2023
c3c9746
Merge branch 'v2.x' into v2.x_sha2pass_draft3
renecannao Jan 15, 2024
29b7cd0
Modify generate_one_byte_pkt()
renecannao Jan 17, 2024
e93b243
Fix variable overflow on 'sha256_crypt_r'
JavierJF Jan 22, 2024
bd7ab0d
Fix empty passwords handling for 'caching_sha2_password'
JavierJF Jan 26, 2024
ce67a50
Fix missing update for session 'clear_text_password'
JavierJF Jan 31, 2024
3f2a7aa
Fix memory issues during 'chaching_sha2' auth
JavierJF Jan 31, 2024
ab8af07
Add 'switching_auth_sent' to 'PROXYSQL INTERNAL SESSION'
JavierJF Feb 22, 2024
ed3a5d7
Add doc for 'switching_auth_type' in SHA2 full
JavierJF Feb 22, 2024
1bc309b
Fix buffer over-read on concurrent SHA2 auths
JavierJF Feb 22, 2024
355d002
Add new test for supported authentication methods
JavierJF Feb 22, 2024
ab39679
Make 'tap' library counting multi-thread resilient
JavierJF Feb 22, 2024
caed360
Merge branch 'v2.x' of github.com:sysown/proxysql into v2.x_sha2pass_…
JavierJF Feb 22, 2024
ab741ee
Fix env vars support for 'test_auth_methods-t'
JavierJF Feb 22, 2024
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
798 changes: 798 additions & 0 deletions doc/internal/ProxySQL_Authentication.md

Large diffs are not rendered by default.

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
5 changes: 4 additions & 1 deletion include/MySQL_Data_Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ 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;
// Updated **only** when an 'auth_switch' has been sent to client
enum proxysql_auth_plugins switching_auth_sent;
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 @@ -447,8 +447,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 @@ -35,7 +35,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 @@ -226,7 +226,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 @@ -776,10 +776,12 @@ 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_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 @@ -945,10 +947,12 @@ 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_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
1 change: 1 addition & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ 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 \
sha256crypt.oo \
proxysql_find_charset.oo ProxySQL_Poll.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