mirror of
https://github.com/sogou/workflow.git
synced 2026-10-24 16:33:15 +08:00
Merge pull request #1163 from Barenboim/mysql
Support MySQL 8 sha256 and caching_sha2 auth plugin.
This commit is contained in:
@@ -550,10 +550,7 @@ CommMessageIn *ComplexHttpProxyTask::message_in()
|
||||
return get_ssl_handshaker();
|
||||
|
||||
auto *msg = (ProtocolMessage *)this->ComplexHttpTask::message_in();
|
||||
if (is_ssl_)
|
||||
return get_ssl_wrapper(msg);
|
||||
|
||||
return msg;
|
||||
return is_ssl_ ? get_ssl_wrapper(msg) : msg;
|
||||
}
|
||||
|
||||
int ComplexHttpProxyTask::keep_alive_timeout()
|
||||
|
||||
+153
-43
@@ -13,8 +13,8 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Authors: Wu Jiaxu (wujiaxu@sogou-inc.com)
|
||||
Xie Han (xiehan@sogou-inc.com)
|
||||
Authors: Xie Han (xiehan@sogou-inc.com)
|
||||
Wu Jiaxu (wujiaxu@sogou-inc.com)
|
||||
Li Yingxin (liyingxin@sogou-inc.com)
|
||||
*/
|
||||
|
||||
@@ -68,6 +68,11 @@ private:
|
||||
{
|
||||
ST_SSL_REQUEST,
|
||||
ST_AUTH_REQUEST,
|
||||
ST_AUTH_SWITCH_REQUEST,
|
||||
ST_CLEAR_PASSWORD_REQUEST,
|
||||
ST_SHA256_PUBLIC_KEY_REQUEST,
|
||||
ST_CSHA2_PUBLIC_KEY_REQUEST,
|
||||
ST_RSA_AUTH_REQUEST,
|
||||
ST_CHARSET_REQUEST,
|
||||
ST_FIRST_USER_REQUEST,
|
||||
ST_USER_REQUEST
|
||||
@@ -75,9 +80,10 @@ private:
|
||||
|
||||
struct MyConnection : public WFConnection
|
||||
{
|
||||
char challenge[20];
|
||||
unsigned char mysql_seqid;
|
||||
std::string str; // shared by auth, auth_swich and rsa_auth requests
|
||||
unsigned char seed[20];
|
||||
enum ConnState state;
|
||||
unsigned char mysql_seqid;
|
||||
SSL *ssl;
|
||||
SSLWrapper wrapper;
|
||||
MyConnection(SSL *ssl) : wrapper(&wrapper, ssl)
|
||||
@@ -86,19 +92,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
int check_handshake();
|
||||
|
||||
SSL *get_ssl() const
|
||||
{
|
||||
return ((MyConnection *)this->get_connection())->ssl;
|
||||
}
|
||||
|
||||
SSLWrapper *get_ssl_wrapper(ProtocolMessage *msg) const
|
||||
{
|
||||
auto *conn = (MyConnection *)this->get_connection();
|
||||
conn->wrapper = SSLWrapper(msg, conn->ssl);
|
||||
return &conn->wrapper;
|
||||
}
|
||||
int check_handshake(MySQLHandshakeResponse *resp);
|
||||
int auth_switch(MySQLAuthResponse *resp, MyConnection *conn);
|
||||
|
||||
struct MySSLWrapper : public SSLWrapper
|
||||
{
|
||||
@@ -184,6 +179,8 @@ static SSL *__create_ssl(SSL_CTX *ssl_ctx)
|
||||
|
||||
CommMessageOut *ComplexMySQLTask::message_out()
|
||||
{
|
||||
MySQLAuthSwitchRequest *auth_switch_req;
|
||||
MySQLRSAAuthRequest *rsa_auth_req;
|
||||
MySQLAuthRequest *auth_req;
|
||||
MySQLRequest *req;
|
||||
|
||||
@@ -195,16 +192,44 @@ CommMessageOut *ComplexMySQLTask::message_out()
|
||||
switch (conn->state)
|
||||
{
|
||||
case ST_SSL_REQUEST:
|
||||
req = new MySQLSSLRequest(character_set_, get_ssl());
|
||||
req->set_seqid(conn->mysql_seqid++);
|
||||
req = new MySQLSSLRequest(character_set_, conn->ssl);
|
||||
req->set_seqid(conn->mysql_seqid);
|
||||
return req;
|
||||
|
||||
case ST_AUTH_REQUEST:
|
||||
req = new MySQLAuthRequest;
|
||||
auth_req = (MySQLAuthRequest *)req;
|
||||
auth_req->set_challenge(conn->challenge);
|
||||
auth_req->set_auth(username_, password_, db_, character_set_);
|
||||
req->set_seqid(conn->mysql_seqid++);
|
||||
auth_req->set_auth_plugin_name(std::move(conn->str));
|
||||
auth_req->set_seed(conn->seed);
|
||||
break;
|
||||
|
||||
case ST_CLEAR_PASSWORD_REQUEST:
|
||||
conn->str = "mysql_clear_password";
|
||||
case ST_AUTH_SWITCH_REQUEST:
|
||||
req = new MySQLAuthSwitchRequest;
|
||||
auth_switch_req = (MySQLAuthSwitchRequest *)req;
|
||||
auth_switch_req->set_password(password_);
|
||||
auth_switch_req->set_auth_plugin_name(std::move(conn->str));
|
||||
auth_switch_req->set_seed(conn->seed);
|
||||
break;
|
||||
|
||||
case ST_SHA256_PUBLIC_KEY_REQUEST:
|
||||
req = new MySQLPublicKeyRequest;
|
||||
((MySQLPublicKeyRequest *)req)->set_sha256();
|
||||
break;
|
||||
|
||||
case ST_CSHA2_PUBLIC_KEY_REQUEST:
|
||||
req = new MySQLPublicKeyRequest;
|
||||
((MySQLPublicKeyRequest *)req)->set_caching_sha2();
|
||||
break;
|
||||
|
||||
case ST_RSA_AUTH_REQUEST:
|
||||
req = new MySQLRSAAuthRequest;
|
||||
rsa_auth_req = (MySQLRSAAuthRequest *)req;
|
||||
rsa_auth_req->set_password(password_);
|
||||
rsa_auth_req->set_public_key(std::move(conn->str));
|
||||
rsa_auth_req->set_seed(conn->seed);
|
||||
break;
|
||||
|
||||
case ST_CHARSET_REQUEST:
|
||||
@@ -238,13 +263,19 @@ CommMessageOut *ComplexMySQLTask::message_out()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!is_user_request_ && conn->state != ST_CHARSET_REQUEST)
|
||||
req->set_seqid(conn->mysql_seqid);
|
||||
|
||||
if (!is_ssl_)
|
||||
return req;
|
||||
|
||||
if (is_user_request_)
|
||||
return get_ssl_wrapper(req);
|
||||
{
|
||||
conn->wrapper = SSLWrapper(req, conn->ssl);
|
||||
return &conn->wrapper;
|
||||
}
|
||||
else
|
||||
return new MySSLWrapper(req, get_ssl());
|
||||
return new MySSLWrapper(req, conn->ssl);
|
||||
}
|
||||
|
||||
CommMessageIn *ComplexMySQLTask::message_in()
|
||||
@@ -258,12 +289,23 @@ CommMessageIn *ComplexMySQLTask::message_in()
|
||||
switch (conn->state)
|
||||
{
|
||||
case ST_SSL_REQUEST:
|
||||
return new SSLHandshaker(get_ssl());
|
||||
return new SSLHandshaker(conn->ssl);
|
||||
|
||||
case ST_AUTH_REQUEST:
|
||||
case ST_AUTH_SWITCH_REQUEST:
|
||||
resp = new MySQLAuthResponse;
|
||||
break;
|
||||
|
||||
case ST_CLEAR_PASSWORD_REQUEST:
|
||||
case ST_RSA_AUTH_REQUEST:
|
||||
resp = new MySQLResponse;
|
||||
break;
|
||||
|
||||
case ST_SHA256_PUBLIC_KEY_REQUEST:
|
||||
case ST_CSHA2_PUBLIC_KEY_REQUEST:
|
||||
resp = new MySQLPublicKeyResponse;
|
||||
break;
|
||||
|
||||
case ST_CHARSET_REQUEST:
|
||||
resp = new MySQLResponse;
|
||||
break;
|
||||
@@ -282,14 +324,16 @@ CommMessageIn *ComplexMySQLTask::message_in()
|
||||
return resp;
|
||||
|
||||
if (is_user_request_)
|
||||
return get_ssl_wrapper(resp);
|
||||
{
|
||||
conn->wrapper = SSLWrapper(resp, conn->ssl);
|
||||
return &conn->wrapper;
|
||||
}
|
||||
else
|
||||
return new MySSLWrapper(resp, get_ssl());
|
||||
return new MySSLWrapper(resp, conn->ssl);
|
||||
}
|
||||
|
||||
int ComplexMySQLTask::check_handshake()
|
||||
int ComplexMySQLTask::check_handshake(MySQLHandshakeResponse *resp)
|
||||
{
|
||||
auto *resp = (MySQLHandshakeResponse *)this->get_message_in();
|
||||
SSL *ssl = NULL;
|
||||
|
||||
if (resp->host_disallowed())
|
||||
@@ -324,9 +368,13 @@ int ComplexMySQLTask::check_handshake()
|
||||
auto *conn = this->get_connection();
|
||||
auto *my_conn = new MyConnection(ssl);
|
||||
|
||||
my_conn->mysql_seqid = resp->get_seqid() + 1;
|
||||
resp->get_challenge(my_conn->challenge);
|
||||
my_conn->str = resp->get_auth_plugin_name();
|
||||
if (my_conn->str == "sha256_password")
|
||||
my_conn->str = "caching_sha2_password";
|
||||
|
||||
resp->get_seed(my_conn->seed);
|
||||
my_conn->state = is_ssl_ ? ST_SSL_REQUEST : ST_AUTH_REQUEST;
|
||||
my_conn->mysql_seqid = resp->get_seqid() + 1;
|
||||
conn->set_context(my_conn, [](void *ctx) {
|
||||
auto *my_conn = (MyConnection *)ctx;
|
||||
if (my_conn->ssl)
|
||||
@@ -337,16 +385,54 @@ int ComplexMySQLTask::check_handshake()
|
||||
return MYSQL_KEEPALIVE_DEFAULT;
|
||||
}
|
||||
|
||||
int ComplexMySQLTask::auth_switch(MySQLAuthResponse *resp, MyConnection *conn)
|
||||
{
|
||||
std::string name = resp->get_auth_plugin_name();
|
||||
|
||||
if (conn->state != ST_AUTH_REQUEST ||
|
||||
(name == "mysql_clear_password" && !is_ssl_))
|
||||
{
|
||||
state_ = WFT_STATE_SYS_ERROR;
|
||||
error_ = EBADMSG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name == "sha256_password")
|
||||
{
|
||||
if (is_ssl_)
|
||||
conn->state = ST_CLEAR_PASSWORD_REQUEST;
|
||||
else
|
||||
conn->state = ST_SHA256_PUBLIC_KEY_REQUEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->str = std::move(name);
|
||||
conn->state = ST_AUTH_SWITCH_REQUEST;
|
||||
}
|
||||
|
||||
resp->get_seed(conn->seed);
|
||||
conn->mysql_seqid = resp->get_seqid() + 1;
|
||||
return MYSQL_KEEPALIVE_DEFAULT;
|
||||
}
|
||||
|
||||
int ComplexMySQLTask::keep_alive_timeout()
|
||||
{
|
||||
auto *msg = (ProtocolMessage *)this->get_message_in();
|
||||
MySQLAuthResponse *auth_resp;
|
||||
MySQLResponse *resp;
|
||||
|
||||
state_ = WFT_STATE_SUCCESS;
|
||||
error_ = 0;
|
||||
if (this->get_seq() == 0)
|
||||
return check_handshake();
|
||||
return check_handshake((MySQLHandshakeResponse *)msg);
|
||||
|
||||
auto *conn = (MyConnection *)this->get_connection();
|
||||
auto *msg = (ProtocolMessage *)this->get_message_in();
|
||||
MySQLResponse *resp;
|
||||
if (conn->state == ST_SSL_REQUEST)
|
||||
{
|
||||
conn->state = ST_AUTH_REQUEST;
|
||||
conn->mysql_seqid++;
|
||||
return MYSQL_KEEPALIVE_DEFAULT;
|
||||
}
|
||||
|
||||
if (is_ssl_)
|
||||
resp = (MySQLResponse *)((MySSLWrapper *)msg)->get_msg();
|
||||
@@ -355,12 +441,23 @@ int ComplexMySQLTask::keep_alive_timeout()
|
||||
|
||||
switch (conn->state)
|
||||
{
|
||||
case ST_SSL_REQUEST:
|
||||
conn->state = ST_AUTH_REQUEST;
|
||||
break;
|
||||
|
||||
case ST_AUTH_REQUEST:
|
||||
if (!resp->is_ok_packet())
|
||||
case ST_AUTH_SWITCH_REQUEST:
|
||||
case ST_CLEAR_PASSWORD_REQUEST:
|
||||
case ST_RSA_AUTH_REQUEST:
|
||||
if (resp->is_ok_packet())
|
||||
{
|
||||
if (!res_charset_.empty())
|
||||
conn->state = ST_CHARSET_REQUEST;
|
||||
else
|
||||
conn->state = ST_FIRST_USER_REQUEST;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (resp->is_error_packet() ||
|
||||
conn->state == ST_CLEAR_PASSWORD_REQUEST ||
|
||||
conn->state == ST_RSA_AUTH_REQUEST)
|
||||
{
|
||||
this->resp = std::move(*resp);
|
||||
state_ = WFT_STATE_TASK_ERROR;
|
||||
@@ -368,11 +465,23 @@ int ComplexMySQLTask::keep_alive_timeout()
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (res_charset_.size() != 0)
|
||||
conn->state = ST_CHARSET_REQUEST;
|
||||
else
|
||||
conn->state = ST_FIRST_USER_REQUEST;
|
||||
auth_resp = (MySQLAuthResponse *)resp;
|
||||
if (auth_resp->is_continue())
|
||||
{
|
||||
if (is_ssl_)
|
||||
conn->state = ST_CLEAR_PASSWORD_REQUEST;
|
||||
else
|
||||
conn->state = ST_CSHA2_PUBLIC_KEY_REQUEST;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return auth_switch(auth_resp, conn);
|
||||
|
||||
case ST_SHA256_PUBLIC_KEY_REQUEST:
|
||||
case ST_CSHA2_PUBLIC_KEY_REQUEST:
|
||||
conn->str = ((MySQLPublicKeyResponse *)resp)->get_public_key();
|
||||
conn->state = ST_RSA_AUTH_REQUEST;
|
||||
break;
|
||||
|
||||
case ST_CHARSET_REQUEST:
|
||||
@@ -385,7 +494,7 @@ int ComplexMySQLTask::keep_alive_timeout()
|
||||
}
|
||||
|
||||
conn->state = ST_FIRST_USER_REQUEST;
|
||||
break;
|
||||
return MYSQL_KEEPALIVE_DEFAULT;
|
||||
|
||||
case ST_FIRST_USER_REQUEST:
|
||||
conn->state = ST_USER_REQUEST;
|
||||
@@ -397,6 +506,7 @@ int ComplexMySQLTask::keep_alive_timeout()
|
||||
return 0;
|
||||
}
|
||||
|
||||
conn->mysql_seqid = resp->get_seqid() + 1;
|
||||
return MYSQL_KEEPALIVE_DEFAULT;
|
||||
}
|
||||
|
||||
|
||||
+262
-35
@@ -13,11 +13,10 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Authors: Wu Jiaxu (wujiaxu@sogou-inc.com)
|
||||
Xie Han (xiehan@sogou-inc.com)
|
||||
Authors: Xie Han (xiehan@sogou-inc.com)
|
||||
Wu Jiaxu (wujiaxu@sogou-inc.com)
|
||||
*/
|
||||
|
||||
#include <sys/uio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@@ -36,6 +35,10 @@ namespace protocol
|
||||
|
||||
#define MYSQL_PAYLOAD_MAX ((1 << 24) - 1)
|
||||
|
||||
#define MYSQL_NATIVE_PASSWORD "mysql_native_password"
|
||||
#define CACHING_SHA2_PASSWORD "caching_sha2_password"
|
||||
#define MYSQL_CLEAR_PASSWORD "mysql_clear_password"
|
||||
|
||||
MySQLMessage::~MySQLMessage()
|
||||
{
|
||||
if (parser_)
|
||||
@@ -186,17 +189,27 @@ int MySQLHandshakeResponse::encode(struct iovec vectors[], int max)
|
||||
buf_.append((const char *)&protocol_version_, 1);
|
||||
buf_.append(server_version_.c_str(), server_version_.size() + 1);
|
||||
buf_.append((const char *)&connection_id_, 4);
|
||||
buf_.append((const char *)auth_plugin_data_part_1_, 8);
|
||||
buf_.append((const char *)auth_plugin_data_, 8);
|
||||
buf_.append(empty, 1);
|
||||
buf_.append((const char *)&cap_flags_lower, 2);
|
||||
buf_.append((const char *)&character_set_, 1);
|
||||
buf_.append((const char *)&status_flags_, 2);
|
||||
buf_.append((const char *)&cap_flags_upper, 2);
|
||||
buf_.append(empty, 11);
|
||||
buf_.append((const char *)auth_plugin_data_part_2_, 12);
|
||||
buf_.append((const char *)auth_plugin_data_ + 8, 12);
|
||||
return this->MySQLMessage::encode(vectors, max);
|
||||
}
|
||||
|
||||
#define MYSQL_CAPFLAG_CLIENT_SSL 0x00000800
|
||||
#define MYSQL_CAPFLAG_CLIENT_PROTOCOL_41 0x00000200
|
||||
#define MYSQL_CAPFLAG_CLIENT_SECURE_CONNECTION 0x00008000
|
||||
#define MYSQL_CAPFLAG_CLIENT_CONNECT_WITH_DB 0x00000008
|
||||
#define MYSQL_CAPFLAG_CLIENT_MULTI_STATEMENTS 0x00010000
|
||||
#define MYSQL_CAPFLAG_CLIENT_MULTI_RESULTS 0x00020000
|
||||
#define MYSQL_CAPFLAG_CLIENT_PS_MULTI_RESULTS 0x00040000
|
||||
#define MYSQL_CAPFLAG_CLIENT_PLUGIN_AUTH 0x00080000
|
||||
#define MYSQL_CAPFLAG_CLIENT_LOCAL_FILES 0x00000080
|
||||
|
||||
int MySQLHandshakeResponse::decode_packet(const unsigned char *buf, size_t buflen)
|
||||
{
|
||||
const unsigned char *end = buf + buflen;
|
||||
@@ -228,14 +241,15 @@ int MySQLHandshakeResponse::decode_packet(const unsigned char *buf, size_t bufle
|
||||
while (pos < end && *pos)
|
||||
pos++;
|
||||
|
||||
if (pos >= end || end - pos < 43)
|
||||
if (pos >= end || end - pos < 45)
|
||||
return -2;
|
||||
|
||||
server_version_.assign((const char *)buf, pos - buf);
|
||||
buf = pos + 1;
|
||||
|
||||
connection_id_ = uint4korr(buf);
|
||||
buf += 4;
|
||||
memcpy(auth_plugin_data_part_1_, buf, 8);
|
||||
memcpy(auth_plugin_data_, buf, 8);
|
||||
buf += 9;
|
||||
cap_flags_lower = uint2korr(buf);
|
||||
buf += 2;
|
||||
@@ -243,30 +257,63 @@ int MySQLHandshakeResponse::decode_packet(const unsigned char *buf, size_t bufle
|
||||
status_flags_ = uint2korr(buf);
|
||||
buf += 2;
|
||||
cap_flags_upper = uint2korr(buf);
|
||||
buf += 13;
|
||||
memcpy(auth_plugin_data_part_2_, buf, 12);
|
||||
buf += 2;
|
||||
capability_flags_ = (cap_flags_upper << 16U) + cap_flags_lower;
|
||||
auth_plugin_data_len_ = *buf++;
|
||||
// 10 bytes reserved. All 0s.
|
||||
buf += 10;
|
||||
// auth_plugin_data always 20 bytes
|
||||
if (auth_plugin_data_len_ > 21)
|
||||
return -2;
|
||||
|
||||
memcpy(auth_plugin_data_ + 8, buf, 12);
|
||||
buf += 13;
|
||||
if (capability_flags_ & MYSQL_CAPFLAG_CLIENT_PLUGIN_AUTH)
|
||||
{
|
||||
if (buf == end || *(end - 1) != '\0')
|
||||
return -2;
|
||||
|
||||
auth_plugin_name_.assign((const char *)buf, end - 1 - buf);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline std::string __sha1_str(const std::string& str)
|
||||
static std::string __native_password_encrypt(const std::string& password,
|
||||
unsigned char seed[20])
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
SHA_CTX ctx;
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, str.c_str(), str.size());
|
||||
SHA1_Final(sha1, &ctx);
|
||||
return std::string((const char *)sha1, 20);
|
||||
unsigned char buf1[20];
|
||||
unsigned char buf2[40];
|
||||
int i;
|
||||
|
||||
// SHA1( password ) ^ SHA1( seed + SHA1( SHA1( password ) ) )
|
||||
SHA1((unsigned char *)password.c_str(), password.size(), buf1);
|
||||
SHA1(buf1, 20, buf2 + 20);
|
||||
memcpy(buf2, seed, 20);
|
||||
SHA1(buf2, 40, buf2);
|
||||
for (i = 0; i < 20; i++)
|
||||
buf1[i] ^= buf2[i];
|
||||
|
||||
return std::string((const char *)buf1, 20);
|
||||
}
|
||||
|
||||
#define MYSQL_CAPFLAG_CLIENT_SSL 0x00000800
|
||||
#define MYSQL_CAPFLAG_CLIENT_PROTOCOL_41 0x00000200
|
||||
#define MYSQL_CAPFLAG_CLIENT_SECURE_CONNECTION 0x00008000
|
||||
#define MYSQL_CAPFLAG_CLIENT_CONNECT_WITH_DB 0x00000008
|
||||
#define MYSQL_CAPFLAG_CLIENT_MULTI_STATEMENTS 0x00010000
|
||||
#define MYSQL_CAPFLAG_CLIENT_MULTI_RESULTS 0x00020000
|
||||
#define MYSQL_CAPFLAG_CLIENT_PS_MULTI_RESULTS 0x00040000
|
||||
#define MYSQL_CAPFLAG_CLIENT_LOCAL_FILES 0x00000080
|
||||
static std::string __caching_sha2_password_encrypt(const std::string& password,
|
||||
unsigned char seed[20])
|
||||
{
|
||||
unsigned char buf1[32];
|
||||
unsigned char buf2[52];
|
||||
int i;
|
||||
|
||||
// SHA256( password ) ^ SHA256( SHA256( SHA256( password ) ) + seed)
|
||||
SHA256((unsigned char *)password.c_str(), password.size(), buf1);
|
||||
SHA256(buf1, 32, buf2);
|
||||
memcpy(buf2 + 32, seed, 20);
|
||||
SHA256(buf2, 52, buf2);
|
||||
for (i = 0; i < 32; i++)
|
||||
buf1[i] ^= buf2[i];
|
||||
|
||||
return std::string((const char *)buf1, 32);
|
||||
}
|
||||
|
||||
int MySQLSSLRequest::encode(struct iovec vectors[], int max)
|
||||
{
|
||||
@@ -281,7 +328,8 @@ int MySQLSSLRequest::encode(struct iovec vectors[], int max)
|
||||
MYSQL_CAPFLAG_CLIENT_MULTI_RESULTS|
|
||||
MYSQL_CAPFLAG_CLIENT_LOCAL_FILES |
|
||||
MYSQL_CAPFLAG_CLIENT_MULTI_STATEMENTS |
|
||||
MYSQL_CAPFLAG_CLIENT_PS_MULTI_RESULTS);
|
||||
MYSQL_CAPFLAG_CLIENT_PS_MULTI_RESULTS |
|
||||
MYSQL_CAPFLAG_CLIENT_PLUGIN_AUTH);
|
||||
pos += 4;
|
||||
int4store(pos, 0);
|
||||
pos += 4;
|
||||
@@ -308,9 +356,9 @@ int MySQLSSLRequest::encode(struct iovec vectors[], int max)
|
||||
|
||||
int MySQLAuthRequest::encode(struct iovec vectors[], int max)
|
||||
{
|
||||
std::string native;
|
||||
unsigned char header[32] = {0};
|
||||
unsigned char *pos = header;
|
||||
std::string str;
|
||||
|
||||
int4store(pos, MYSQL_CAPFLAG_CLIENT_PROTOCOL_41 |
|
||||
MYSQL_CAPFLAG_CLIENT_SECURE_CONNECTION |
|
||||
@@ -318,29 +366,34 @@ int MySQLAuthRequest::encode(struct iovec vectors[], int max)
|
||||
MYSQL_CAPFLAG_CLIENT_MULTI_RESULTS|
|
||||
MYSQL_CAPFLAG_CLIENT_LOCAL_FILES |
|
||||
MYSQL_CAPFLAG_CLIENT_MULTI_STATEMENTS |
|
||||
MYSQL_CAPFLAG_CLIENT_PS_MULTI_RESULTS);
|
||||
MYSQL_CAPFLAG_CLIENT_PS_MULTI_RESULTS |
|
||||
MYSQL_CAPFLAG_CLIENT_PLUGIN_AUTH);
|
||||
pos += 4;
|
||||
int4store(pos, 0);
|
||||
pos += 4;
|
||||
*pos = (uint8_t)character_set_;
|
||||
|
||||
if (password_.empty())
|
||||
native.push_back((char)0);
|
||||
str.push_back(0);
|
||||
else if (auth_plugin_name_ == CACHING_SHA2_PASSWORD)
|
||||
{
|
||||
str.push_back(32);
|
||||
str += __caching_sha2_password_encrypt(password_, seed_);
|
||||
}
|
||||
else
|
||||
{
|
||||
native.push_back((char)20);
|
||||
std::string first = __sha1_str(password_);
|
||||
std::string second = __sha1_str(challenge_ + __sha1_str(first));
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
native.push_back(first[i] ^ second[i]);
|
||||
str.push_back(20);
|
||||
str += __native_password_encrypt(password_, seed_);
|
||||
}
|
||||
|
||||
buf_.clear();
|
||||
buf_.append((char *)header, 32);
|
||||
buf_.append(username_.c_str(), username_.size() + 1);
|
||||
buf_.append(native);
|
||||
buf_.append(str);
|
||||
buf_.append(db_.c_str(), db_.size() + 1);
|
||||
if (auth_plugin_name_.size() != 0)
|
||||
buf_.append(auth_plugin_name_.c_str(), auth_plugin_name_.size() + 1);
|
||||
|
||||
return this->MySQLMessage::encode(vectors, max);
|
||||
}
|
||||
|
||||
@@ -374,6 +427,180 @@ int MySQLAuthRequest::decode_packet(const unsigned char *buf, size_t buflen)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MySQLAuthResponse::decode_packet(const unsigned char *buf, size_t buflen)
|
||||
{
|
||||
const unsigned char *end = buf + buflen;
|
||||
const unsigned char *pos;
|
||||
const unsigned char *str;
|
||||
unsigned long long len;
|
||||
int ret;
|
||||
|
||||
if (end == buf)
|
||||
return -2;
|
||||
|
||||
switch (*buf)
|
||||
{
|
||||
case 0x00:
|
||||
case 0xff:
|
||||
return MySQLResponse::decode_packet(buf, buflen);
|
||||
|
||||
case 0xfe:
|
||||
pos = ++buf;
|
||||
while (pos < end && *pos)
|
||||
pos++;
|
||||
|
||||
if (pos >= end)
|
||||
return -2;
|
||||
|
||||
auth_plugin_name_.assign((const char *)buf, pos - buf);
|
||||
buf = pos + 1;
|
||||
if (buf == end || *(end - 1) != '\0')
|
||||
return -2;
|
||||
|
||||
if (end - 1 - buf != 20)
|
||||
return -2;
|
||||
|
||||
memcpy(seed_, buf, 20);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
pos = buf;
|
||||
ret = decode_string(&str, &len, &pos, end);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
if (len == 1)
|
||||
{
|
||||
if (*str == 0x03)
|
||||
{
|
||||
if (end > pos)
|
||||
return MySQLResponse::decode_packet(pos, end - pos);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if (*str == 0x04)
|
||||
{
|
||||
continue_ = true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
int MySQLAuthSwitchRequest::encode(struct iovec vectors[], int max)
|
||||
{
|
||||
if (auth_plugin_name_ == MYSQL_NATIVE_PASSWORD)
|
||||
{
|
||||
buf_ = __native_password_encrypt(password_, seed_);
|
||||
}
|
||||
else if (auth_plugin_name_ == CACHING_SHA2_PASSWORD)
|
||||
{
|
||||
buf_ = __caching_sha2_password_encrypt(password_, seed_);
|
||||
}
|
||||
else if (auth_plugin_name_ == MYSQL_CLEAR_PASSWORD)
|
||||
{
|
||||
buf_ = password_;
|
||||
buf_.push_back('\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return this->MySQLMessage::encode(vectors, max);
|
||||
}
|
||||
|
||||
int MySQLPublicKeyResponse::decode_packet(const unsigned char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
if (buflen == 0 || *buf != 0x01)
|
||||
return -2;
|
||||
|
||||
if (buflen == 1)
|
||||
return 0;
|
||||
|
||||
public_key_.assign((const char *)buf + 1, buflen - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MySQLPublicKeyResponse::encode(struct iovec vectors[], int max)
|
||||
{
|
||||
buf_.clear();
|
||||
buf_.push_back(0x01);
|
||||
buf_ += public_key_;
|
||||
return MySQLMessage::encode(vectors, max);
|
||||
}
|
||||
|
||||
int MySQLRSAAuthRequest::rsa_encrypt(void *ctx)
|
||||
{
|
||||
EVP_PKEY_CTX *pkey_ctx = (EVP_PKEY_CTX *)ctx;
|
||||
unsigned char out[256];
|
||||
size_t outlen = 256;
|
||||
std::string pass;
|
||||
unsigned char *p;
|
||||
size_t i;
|
||||
|
||||
if (EVP_PKEY_encrypt_init(pkey_ctx) > 0 &&
|
||||
EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_OAEP_PADDING) > 0)
|
||||
{
|
||||
pass.reserve(password_.size() + 1);
|
||||
p = (unsigned char *)pass.c_str();
|
||||
for (i = 0; i <= password_.size(); i++)
|
||||
p[i] = (unsigned char)password_[i] ^ seed_[i % 20];
|
||||
|
||||
if (EVP_PKEY_encrypt(pkey_ctx, out, &outlen, p, i) > 0)
|
||||
{
|
||||
buf_.assign((char *)out, 256);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MySQLRSAAuthRequest::encode(struct iovec vectors[], int max)
|
||||
{
|
||||
RSA *rsa;
|
||||
BIO *bio;
|
||||
|
||||
bio = BIO_new_mem_buf(public_key_.c_str(), public_key_.size());
|
||||
if (!bio)
|
||||
return -1;
|
||||
|
||||
rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
if (!rsa)
|
||||
return -1;
|
||||
|
||||
EVP_PKEY_CTX *pkey_ctx;
|
||||
EVP_PKEY *pkey;
|
||||
int ret = -1;
|
||||
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey)
|
||||
{
|
||||
EVP_PKEY_assign_RSA(pkey, rsa);
|
||||
pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||
if (pkey_ctx)
|
||||
{
|
||||
ret = rsa_encrypt(pkey_ctx);
|
||||
EVP_PKEY_CTX_free(pkey_ctx);
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
else
|
||||
RSA_free(rsa);
|
||||
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return MySQLMessage::encode(vectors, max);
|
||||
}
|
||||
|
||||
void MySQLResponse::set_ok_packet()
|
||||
{
|
||||
uint16_t zero16 = 0;
|
||||
|
||||
+197
-23
@@ -13,12 +13,13 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Authors: Wu Jiaxu (wujiaxu@sogou-inc.com)
|
||||
Xie Han (xiehan@sogou-inc.com)
|
||||
Authors: Xie Han (xiehan@sogou-inc.com)
|
||||
Wu Jiaxu (wujiaxu@sogou-inc.com)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <openssl/ssl.h>
|
||||
#include "SSLWrapper.h"
|
||||
@@ -35,27 +36,28 @@ private:
|
||||
class MySQLHandshakeResponse : public MySQLResponse
|
||||
{
|
||||
public:
|
||||
void get_challenge(char *arr) const
|
||||
std::string get_server_version() const { return server_version_; }
|
||||
std::string get_auth_plugin_name() const { return auth_plugin_name_; }
|
||||
|
||||
void get_seed(unsigned char seed[20]) const
|
||||
{
|
||||
memcpy(arr, auth_plugin_data_part_1_, 8);
|
||||
memcpy(arr + 8, auth_plugin_data_part_2_, 12);
|
||||
memcpy(seed, auth_plugin_data_, 20);
|
||||
}
|
||||
|
||||
virtual int encode(struct iovec vectors[], int max);
|
||||
|
||||
void server_set(uint8_t protocol_version, const std::string server_version,
|
||||
uint32_t connection_id, const uint8_t *auth1,
|
||||
uint32_t connection_id, const unsigned char seed[20],
|
||||
uint32_t capability_flags, uint8_t character_set,
|
||||
uint16_t status_flags, const uint8_t *auth2)
|
||||
uint16_t status_flags)
|
||||
{
|
||||
protocol_version_ = protocol_version;
|
||||
server_version_ = server_version;
|
||||
connection_id_ = connection_id;
|
||||
memcpy(auth_plugin_data_part_1_, auth1, 8);
|
||||
memcpy(auth_plugin_data_, seed, 20);
|
||||
capability_flags_ = capability_flags;
|
||||
character_set_ = character_set;
|
||||
status_flags_ = status_flags;
|
||||
memcpy(auth_plugin_data_part_2_, auth2, 12);
|
||||
}
|
||||
|
||||
bool host_disallowed() const { return disallowed_; }
|
||||
@@ -65,14 +67,15 @@ public:
|
||||
private:
|
||||
virtual int decode_packet(const unsigned char *buf, size_t buflen);
|
||||
|
||||
uint8_t protocol_version_;
|
||||
std::string server_version_;
|
||||
std::string auth_plugin_name_;
|
||||
unsigned char auth_plugin_data_[20];
|
||||
uint32_t connection_id_;
|
||||
uint8_t auth_plugin_data_part_1_[8];
|
||||
uint32_t capability_flags_;
|
||||
uint8_t character_set_;
|
||||
uint16_t status_flags_;
|
||||
uint8_t auth_plugin_data_part_2_[12];
|
||||
uint8_t character_set_;
|
||||
uint8_t auth_plugin_data_len_;
|
||||
uint8_t protocol_version_;
|
||||
bool disallowed_;
|
||||
|
||||
public:
|
||||
@@ -111,20 +114,25 @@ public:
|
||||
class MySQLAuthRequest : public MySQLRequest
|
||||
{
|
||||
public:
|
||||
void set_auth(const std::string& username,
|
||||
const std::string& password,
|
||||
const std::string& db,
|
||||
void set_auth(const std::string username,
|
||||
const std::string password,
|
||||
const std::string db,
|
||||
int character_set)
|
||||
{
|
||||
username_ = username;
|
||||
password_ = password;
|
||||
db_ = db;
|
||||
username_ = std::move(username);
|
||||
password_ = std::move(password);
|
||||
db_ = std::move(db);
|
||||
character_set_ = character_set;
|
||||
}
|
||||
|
||||
void set_challenge(const char *arr)
|
||||
void set_auth_plugin_name(std::string name)
|
||||
{
|
||||
challenge_.assign(arr, 20);
|
||||
auth_plugin_name_ = std::move(name);
|
||||
}
|
||||
|
||||
void set_seed(const unsigned char seed[20])
|
||||
{
|
||||
memcpy(seed_, seed, 20);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -134,7 +142,8 @@ private:
|
||||
std::string username_;
|
||||
std::string password_;
|
||||
std::string db_;
|
||||
std::string challenge_;
|
||||
std::string auth_plugin_name_;
|
||||
unsigned char seed_[20];
|
||||
int character_set_;
|
||||
|
||||
public:
|
||||
@@ -145,7 +154,172 @@ public:
|
||||
MySQLAuthRequest& operator= (MySQLAuthRequest&& move) = default;
|
||||
};
|
||||
|
||||
using MySQLAuthResponse = MySQLResponse;
|
||||
class MySQLAuthResponse : public MySQLResponse
|
||||
{
|
||||
public:
|
||||
std::string get_auth_plugin_name() const { return auth_plugin_name_; }
|
||||
|
||||
void get_seed(unsigned char seed[20]) const
|
||||
{
|
||||
memcpy(seed, seed_, 20);
|
||||
}
|
||||
|
||||
bool is_continue() const
|
||||
{
|
||||
return continue_;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int decode_packet(const unsigned char *buf, size_t buflen);
|
||||
|
||||
private:
|
||||
std::string auth_plugin_name_;
|
||||
unsigned char seed_[20];
|
||||
bool continue_;
|
||||
|
||||
public:
|
||||
MySQLAuthResponse() : continue_(false) { }
|
||||
//move constructor
|
||||
MySQLAuthResponse(MySQLAuthResponse&& move) = default;
|
||||
//move operator
|
||||
MySQLAuthResponse& operator= (MySQLAuthResponse&& move) = default;
|
||||
};
|
||||
|
||||
class MySQLAuthSwitchRequest : public MySQLRequest
|
||||
{
|
||||
public:
|
||||
void set_password(std::string password)
|
||||
{
|
||||
password_ = std::move(password);
|
||||
}
|
||||
|
||||
void set_auth_plugin_name(std::string name)
|
||||
{
|
||||
auth_plugin_name_ = std::move(name);
|
||||
}
|
||||
|
||||
void set_seed(const unsigned char seed[20])
|
||||
{
|
||||
memcpy(seed_, seed, 20);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int encode(struct iovec vectors[], int max);
|
||||
|
||||
/* Not implemented. */
|
||||
virtual int decode_packet(const unsigned char *buf, size_t buflen)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
std::string password_;
|
||||
std::string auth_plugin_name_;
|
||||
unsigned char seed_[20];
|
||||
|
||||
public:
|
||||
MySQLAuthSwitchRequest() { }
|
||||
//move constructor
|
||||
MySQLAuthSwitchRequest(MySQLAuthSwitchRequest&& move) = default;
|
||||
//move operator
|
||||
MySQLAuthSwitchRequest& operator= (MySQLAuthSwitchRequest&& move) = default;
|
||||
};
|
||||
|
||||
class MySQLPublicKeyRequest : public MySQLRequest
|
||||
{
|
||||
public:
|
||||
void set_caching_sha2() { byte_ = 0x02; }
|
||||
void set_sha256() { byte_ = 0x01; }
|
||||
|
||||
private:
|
||||
virtual int encode(struct iovec vectors[], int max)
|
||||
{
|
||||
buf_.assign(&byte_, 1);
|
||||
return MySQLRequest::encode(vectors, max);
|
||||
}
|
||||
|
||||
/* Not implemented. */
|
||||
virtual int decode_packet(const unsigned char *buf, size_t buflen)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
char byte_;
|
||||
|
||||
public:
|
||||
MySQLPublicKeyRequest() : byte_(0x01) { }
|
||||
//move constructor
|
||||
MySQLPublicKeyRequest(MySQLPublicKeyRequest&& move) = default;
|
||||
//move operator
|
||||
MySQLPublicKeyRequest& operator= (MySQLPublicKeyRequest&& move) = default;
|
||||
};
|
||||
|
||||
class MySQLPublicKeyResponse : public MySQLResponse
|
||||
{
|
||||
public:
|
||||
std::string get_public_key() const
|
||||
{
|
||||
return public_key_;
|
||||
}
|
||||
|
||||
void set_public_key(std::string key)
|
||||
{
|
||||
public_key_ = std::move(key);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int encode(struct iovec vectors[], int max);
|
||||
virtual int decode_packet(const unsigned char *buf, size_t buflen);
|
||||
|
||||
std::string public_key_;
|
||||
|
||||
public:
|
||||
MySQLPublicKeyResponse() { }
|
||||
//move constructor
|
||||
MySQLPublicKeyResponse(MySQLPublicKeyResponse&& move) = default;
|
||||
//move operator
|
||||
MySQLPublicKeyResponse& operator= (MySQLPublicKeyResponse&& move) = default;
|
||||
};
|
||||
|
||||
class MySQLRSAAuthRequest : public MySQLRequest
|
||||
{
|
||||
public:
|
||||
void set_password(std::string password)
|
||||
{
|
||||
password_ = std::move(password);
|
||||
}
|
||||
|
||||
void set_public_key(std::string key)
|
||||
{
|
||||
public_key_ = std::move(key);
|
||||
}
|
||||
|
||||
void set_seed(const unsigned char seed[20])
|
||||
{
|
||||
memcpy(seed_, seed, 20);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int encode(struct iovec vectors[], int max);
|
||||
|
||||
/* Not implemented. */
|
||||
virtual int decode_packet(const unsigned char *buf, size_t buflen)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
int rsa_encrypt(void *ctx);
|
||||
|
||||
std::string password_;
|
||||
std::string public_key_;
|
||||
unsigned char seed_[20];
|
||||
|
||||
public:
|
||||
MySQLRSAAuthRequest() { }
|
||||
//move constructor
|
||||
MySQLRSAAuthRequest(MySQLRSAAuthRequest&& move) = default;
|
||||
//move operator
|
||||
MySQLRSAAuthRequest& operator= (MySQLRSAAuthRequest&& move) = default;
|
||||
};
|
||||
|
||||
//////////
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ WFConnection *WFMySQLServer::new_connection(int accept_fd)
|
||||
struct iovec vec[8];
|
||||
int count;
|
||||
|
||||
resp.server_set(0x0a, "5.5", 1, (const uint8_t *)"12345678",
|
||||
0, 33, 0, (const uint8_t *)"123456789abc");
|
||||
resp.server_set(0x0a, "5.5", 1, (const uint8_t *)"12345678901234567890",
|
||||
0, 33, 0);
|
||||
count = resp.encode(vec, 8);
|
||||
if (count >= 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user