From 128ff3dedaa8472c88fd95d8a453d2ebbe76c4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Sun, 11 Sep 2016 22:54:53 +0000 Subject: [PATCH] Introduce new variable admin-hash_passwords #676 New variable admin-hash_passwords , default true When set, passwords in mysql_users are automatically hashed in runtime when running LOAD MYSQL USERS TO RUNTIME. For backward compatibility, passwords in mysql_users in memory and disk aren't automatically hashed. Although, they can be easily hashed running SAVE MYSQL USERS TO MEMORY (and eventually SAVE MYSQL USERS TO DISK) immediately after running LOAD MYSQL USERS TO RUNTIME --- include/proxysql_admin.h | 1 + lib/ProxySQL_Admin.cpp | 65 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/include/proxysql_admin.h b/include/proxysql_admin.h index f1f645e4b..3dcf4f9ab 100644 --- a/include/proxysql_admin.h +++ b/include/proxysql_admin.h @@ -71,6 +71,7 @@ class ProxySQL_Admin { char *telnet_admin_ifaces; char *telnet_stats_ifaces; bool admin_read_only; + bool hash_passwords; char * admin_version; #ifdef DEBUG bool debug; diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 4c68587c3..f569ce0f4 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -54,6 +54,21 @@ char *s_strdup(char *s) { return ret; } + +static char *sha1_pass_hex(char *sha1_pass) { // copied from MySQL_Protocol.cpp + if (sha1_pass==NULL) return NULL; + char *buff=(char *)malloc(SHA_DIGEST_LENGTH*2+2); + buff[0]='*'; + buff[SHA_DIGEST_LENGTH*2+1]='\0'; + int i; + uint8_t a; + for (i=0;i::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; + char *password=NULL; + if (variables.hash_passwords) { // We must use hashed password. See issue #676 + // Admin needs to hash the password + if (r->fields[1] && strlen(r->fields[1])) { + if (r->fields[1][0]=='*') { // the password is already hashed + password=strdup(r->fields[1]); + } else { // we must hash it + uint8 hash_stage1[SHA_DIGEST_LENGTH]; + uint8 hash_stage2[SHA_DIGEST_LENGTH]; + SHA_CTX sha1_context; + SHA1_Init(&sha1_context); + SHA1_Update(&sha1_context, r->fields[1], strlen(r->fields[1])); + SHA1_Final(hash_stage1, &sha1_context); + SHA1_Init(&sha1_context); + SHA1_Update(&sha1_context,hash_stage1,SHA_DIGEST_LENGTH); + SHA1_Final(hash_stage2, &sha1_context); + password=sha1_pass_hex((char *)hash_stage2); // note that sha1_pass_hex() returns a new buffer + } + } else { + password=strdup((char *)""); // we also generate a new string if hash_passwords is set + } + } else { + if (r->fields[1]) { + password=r->fields[1]; + } else { + password=(char *)""; + } + } GloMyAuth->add( r->fields[0], // username - (r->fields[1]==NULL ? (char *)"" : r->fields[1]), //password + //(r->fields[1]==NULL ? (char *)"" : r->fields[1]), //password + password, // before #676, wewere always passing the password. Now it is possible that the password can be hashed usertype, // backend/frontend (strcmp(r->fields[2],"1")==0 ? true : false) , // use_ssl atoi(r->fields[3]), // default_hostgroup @@ -3765,6 +3825,9 @@ void ProxySQL_Admin::__add_active_users(enum cred_username_type usertype) { (strcmp(r->fields[7],"1")==0 ? true : false), // fast_forward ( atoi(r->fields[8])>0 ? atoi(r->fields[8]) : 0) // max_connections ); + if (variables.hash_passwords) { + free(password); // because we always generate a new string + } } } // if (error) free(error);