Skip to content

Commit

Permalink
Merge pull request #4258 from sysown/v2.x_sha2pass_draft3
Browse files Browse the repository at this point in the history
V2.x sha2pass draft3
  • Loading branch information
renecannao authored Feb 26, 2024
2 parents ee3d241 + ab741ee commit b7f53c1
Show file tree
Hide file tree
Showing 27 changed files with 7,238 additions and 518 deletions.
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

0 comments on commit b7f53c1

Please sign in to comment.