1 /*
2 * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
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 #include "xpl_dispatcher.h"
27 #include "xpl_session.h"
28 #include "xpl_log.h"
29 #include "xpl_server.h"
30
31 #include "crud_cmd_handler.h"
32 #include "sql_data_context.h"
33 #include "notices.h"
34
35 #include "ngs/scheduler.h"
36 #include "ngs/interface/client_interface.h"
37 #include "ngs/ngs_error.h"
38 #include "ngs_common/protocol_protobuf.h"
39
40 #include <iostream>
41
42
Session(ngs::Client_interface & client,ngs::Protocol_encoder * proto,const Session_id session_id)43 xpl::Session::Session(ngs::Client_interface &client, ngs::Protocol_encoder *proto, const Session_id session_id)
44 : ngs::Session(client, proto, session_id),
45 m_sql(proto),
46 m_was_authenticated(false)
47 {
48 }
49
50
~Session()51 xpl::Session::~Session()
52 {
53 if (m_was_authenticated)
54 --Global_status_variables::instance().m_sessions_count;
55
56 m_sql.deinit();
57 }
58
59
60 // handle a message while in Ready state
handle_ready_message(ngs::Request & command)61 bool xpl::Session::handle_ready_message(ngs::Request &command)
62 {
63 // check if the session got killed
64 if (m_sql.is_killed())
65 {
66 m_encoder->send_result(ngs::Error_code(ER_QUERY_INTERRUPTED, "Query execution was interrupted", "70100", ngs::Error_code::FATAL));
67 // close as fatal_error instead of killed. killed is for when the client is idle
68 on_close();
69 return true;
70 }
71
72 if (ngs::Session::handle_ready_message(command))
73 return true;
74
75 try
76 {
77 return dispatcher::dispatch_command(*this, m_crud_handler, m_expect_stack, command);
78 }
79 catch (ngs::Error_code &err)
80 {
81 m_encoder->send_result(err);
82 on_close();
83 return true;
84 }
85 catch (std::exception &exc)
86 {
87 // not supposed to happen, but catch exceptions as a last defense..
88 log_error("%s: Unexpected exception dispatching command: %s\n", m_client.client_id(), exc.what());
89 on_close();
90 return true;
91 }
92 return false;
93 }
94
95
init()96 ngs::Error_code xpl::Session::init()
97 {
98 const unsigned short port = m_client.client_port();
99 const ngs::Connection_type type = m_client.connection().connection_type();
100
101 return m_sql.init(port, type);
102 }
103
104
on_kill()105 void xpl::Session::on_kill()
106 {
107 if (!m_sql.is_killed())
108 {
109 if (!m_sql.kill())
110 log_info("%s: Could not interrupt client session", m_client.client_id());
111 }
112
113 on_close(true);
114 }
115
116
on_auth_success(const ngs::Authentication_handler::Response & response)117 void xpl::Session::on_auth_success(const ngs::Authentication_handler::Response &response)
118 {
119 xpl::notices::send_client_id(proto(), m_client.client_id_num());
120 ngs::Session::on_auth_success(response);
121
122 ++Global_status_variables::instance().m_accepted_sessions_count;
123 ++Global_status_variables::instance().m_sessions_count;
124
125 m_was_authenticated = true;
126 }
127
128
on_auth_failure(const ngs::Authentication_handler::Response & response)129 void xpl::Session::on_auth_failure(const ngs::Authentication_handler::Response &response)
130 {
131 if (response.error_code == ER_MUST_CHANGE_PASSWORD && !m_sql.password_expired())
132 {
133 ngs::Authentication_handler::Response r = {"Password for " MYSQLXSYS_ACCOUNT " account has been expired", response.status, response.error_code};
134 ngs::Session::on_auth_failure(r);
135 }
136 else
137 ngs::Session::on_auth_failure(response);
138
139 ++Global_status_variables::instance().m_rejected_sessions_count;
140 }
141
142
mark_as_tls_session()143 void xpl::Session::mark_as_tls_session()
144 {
145 data_context().set_connection_type(ngs::Connection_tls);
146 }
147
148
is_handled_by(const void * handler) const149 bool xpl::Session::is_handled_by(const void *handler) const
150 {
151 return m_sql.get_thd() == handler;
152 }
153
154
155 /** Checks whether things owned by the given user are visible to this session.
156 Returns true if we're SUPER or the same user as the given one.
157 If user is NULL, then it's only visible for SUPER users.
158 */
can_see_user(const std::string & user) const159 bool xpl::Session::can_see_user(const std::string &user) const
160 {
161 const std::string owner = m_sql.get_authenticated_user_name();
162
163 if (is_ready() && !owner.empty())
164 {
165 if (m_sql.has_authenticated_user_a_super_priv()
166 || (owner == user))
167 return true;
168 }
169 return false;
170 }
171
172
update_status(Common_status_variables::Variable Common_status_variables::* variable)173 void xpl::Session::update_status(Common_status_variables::Variable
174 Common_status_variables::*variable)
175 {
176 ++(m_status_variables.*variable);
177 ++(Global_status_variables::instance().*variable);
178 }
179