1 /* 2 * Copyright (c) 2015, 2021, Oracle and/or its affiliates. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License, version 2.0, 6 * as published by the Free Software Foundation. 7 * 8 * This program is also distributed with certain software (including 9 * but not limited to OpenSSL) that is licensed under separate terms, 10 * as designated in a particular file or component or in included license 11 * documentation. The authors of MySQL hereby grant you an additional 12 * permission to link the program and your derivative works with the 13 * separately licensed software that they have included with MySQL. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License, version 2.0, for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 23 * 02110-1301 USA 24 */ 25 26 27 #ifndef _AUTH_PLAIN_H_ 28 #define _AUTH_PLAIN_H_ 29 30 31 #include "ngs/protocol_encoder.h" 32 #include "ngs/protocol_authentication.h" 33 #include "xpl_session.h" 34 #include "xpl_server.h" 35 #include "sql_data_context.h" 36 #include "xpl_client.h" 37 38 #include "xpl_log.h" 39 40 41 namespace xpl 42 { 43 44 45 class Sasl_plain_auth : public ngs::Authentication_handler 46 { 47 public: create(ngs::Session_interface * session)48 static ngs::Authentication_handler_ptr create(ngs::Session_interface *session) 49 { 50 return Authentication_handler::wrap_ptr(new Sasl_plain_auth((xpl::Session*)session)); 51 } 52 handle_start(const std::string & mechanism,const std::string & data,const std::string & initial_response)53 virtual Response handle_start(const std::string &mechanism, 54 const std::string &data, 55 const std::string &initial_response) 56 { 57 Response r; 58 const char* client_address = m_session->client().client_address(); 59 std::string client_hostname = m_session->client().client_hostname(); 60 ngs::Error_code error = sasl_message(client_hostname.empty() ? NULL : client_hostname.c_str(), client_address, data); 61 62 // data is the username and initial_response is password 63 if (!error) 64 { 65 r.status = Succeeded; 66 r.data = ""; 67 r.error_code = 0; 68 } 69 else 70 { 71 r.status = Failed; 72 r.data = error.message; 73 r.error_code = error.error; 74 } 75 76 return r; 77 } 78 handle_continue(const std::string & data)79 virtual Response handle_continue(const std::string &data) 80 { 81 // never supposed to get called 82 Response r; 83 r.status = Error; 84 r.error_code = ER_NET_PACKETS_OUT_OF_ORDER; 85 return r; 86 } 87 done()88 virtual void done() 89 { 90 delete this; 91 } 92 93 protected: Sasl_plain_auth(xpl::Session * session)94 Sasl_plain_auth(xpl::Session *session) : m_session(session) {} 95 96 private: 97 xpl::Session *m_session; 98 sasl_message(const char * client_hostname,const char * client_address,const std::string & message)99 ngs::Error_code sasl_message(const char *client_hostname, const char *client_address, const std::string &message) 100 { 101 try 102 { 103 const std::size_t sasl_element_max_with_two_additional_bytes = 256; 104 std::size_t message_position = 0; 105 106 char authzid_db[sasl_element_max_with_two_additional_bytes]; 107 char authcid[sasl_element_max_with_two_additional_bytes]; 108 char passwd[sasl_element_max_with_two_additional_bytes]; 109 110 if (!extract_null_terminated_element(message, message_position, sasl_element_max_with_two_additional_bytes, authzid_db) || 111 !extract_null_terminated_element(message, message_position, sasl_element_max_with_two_additional_bytes, authcid) || 112 !extract_null_terminated_element(message, message_position, sasl_element_max_with_two_additional_bytes, passwd)) 113 { 114 // throw ngs::Error_code(ER_INVALID_CHARACTER_STRING, "Invalid format of login string"); 115 throw ngs::Error_code(ER_NO_SUCH_USER, "Invalid user or password"); 116 } 117 118 if (strlen(authcid) == 0) 119 throw ngs::Error_code(ER_NO_SUCH_USER, "Invalid user or password"); 120 std::string password_hash = *passwd ? compute_password_hash(passwd) : ""; 121 On_user_password_hash check_password_hash = ngs::bind(&Sasl_plain_auth::compare_hashes, this, password_hash, ngs::placeholders::_1); 122 ngs::IOptions_session_ptr options_session = m_session->client().connection().options(); 123 const ngs::Connection_type connection_type = m_session->client().connection().connection_type(); 124 125 return m_session->data_context().authenticate(authcid, client_hostname, client_address, authzid_db, check_password_hash, 126 ((xpl::Client&)m_session->client()).supports_expired_passwords(), options_session, connection_type); 127 } 128 catch(const ngs::Error_code &error_code) 129 { 130 return error_code; 131 } 132 return ngs::Error_code(); 133 } 134 compare_hashes(const std::string & user_password_hash,const std::string & db_password_hash)135 bool compare_hashes(const std::string &user_password_hash, const std::string &db_password_hash) 136 { 137 const bool result = (user_password_hash == db_password_hash); 138 return result; 139 } 140 }; 141 142 } // namespace xpl 143 144 145 #endif // _AUTH_PLAIN_H_ 146