MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
handshake.cc
1 /* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 #include "handshake.h"
17 
18 
35 Handshake::Handshake(const char *ssp, side_t side)
36 : m_atts(0L), m_error(0), m_complete(FALSE),
37  m_have_credentials(false), m_have_sec_context(false)
38 #ifndef DBUG_OFF
39  , m_ssp_info(NULL)
40 #endif
41 {
42  SECURITY_STATUS ret;
43 
44  // Obtain credentials for the authentication handshake.
45 
46  ret= AcquireCredentialsHandle(NULL, (SEC_CHAR*)ssp,
47  side == SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
48  NULL, NULL, NULL, NULL, &m_cred, &m_expire);
49 
50  if (ret != SEC_E_OK)
51  {
52  DBUG_PRINT("error", ("AcqireCredentialsHandle() failed"
53  " with error %X", ret));
54  ERROR_LOG(ERROR, ("Could not obtain local credentials"
55  " required for authentication"));
56  m_error= ret;
57  }
58 
59  m_have_credentials= true;
60 }
61 
62 
63 Handshake::~Handshake()
64 {
66  FreeCredentialsHandle(&m_cred);
68  DeleteSecurityContext(&m_sctx);
69  m_output.free();
70 
71 #ifndef DBUG_OFF
72  if (m_ssp_info)
73  FreeContextBuffer(m_ssp_info);
74 #endif
75 }
76 
77 
94 {
95  m_round= 0;
96 
97  do {
98  ++m_round;
99  // Read packet send by the peer
100 
101  DBUG_PRINT("info", ("Waiting for packet"));
102  Blob packet= read_packet();
103  if (error())
104  {
105  ERROR_LOG(ERROR, ("Error reading packet in round %d", m_round));
106  return 1;
107  }
108  DBUG_PRINT("info", ("Got packet of length %d", packet.len()));
109 
110  /*
111  Process received data, possibly generating new data to be sent.
112  */
113 
114  Blob new_data= process_data(packet);
115 
116  if (error())
117  {
118  ERROR_LOG(ERROR, ("Error processing packet in round %d", m_round));
119  return 1;
120  }
121 
122  /*
123  If new data has been generated, send it to the peer. Otherwise
124  handshake must be completed.
125  */
126 
127  if (!new_data.is_null())
128  {
129  DBUG_PRINT("info", ("Round %d started", m_round));
130 
131  DBUG_PRINT("info", ("Sending packet of length %d", new_data.len()));
132  int ret= write_packet(new_data);
133  if (ret)
134  {
135  ERROR_LOG(ERROR, ("Error writing packet in round %d", m_round));
136  return 1;
137  }
138  DBUG_PRINT("info", ("Data sent"));
139  }
140  else if (!is_complete())
141  {
142  ERROR_LOG(ERROR, ("No data to send in round %d"
143  " but handshake is not complete", m_round));
144  return 1;
145  }
146 
147  /*
148  To protect against malicious clients, break handshake exchange if
149  too many rounds.
150  */
151 
152  if (m_round > MAX_HANDSHAKE_ROUNDS)
153  {
154  ERROR_LOG(ERROR, ("Authentication handshake could not be completed"
155  " after %d rounds", m_round));
156  return 1;
157  }
158 
159  } while(!is_complete());
160 
161  ERROR_LOG(INFO, ("Handshake completed after %d rounds", m_round));
162  return 0;
163 }
164 
165 
166 #ifndef DBUG_OFF
167 
177 const char* Handshake::ssp_name()
178 {
179  if (!m_ssp_info && m_complete)
180  {
181  SecPkgContext_PackageInfo pinfo;
182 
183  int ret= QueryContextAttributes(&m_sctx, SECPKG_ATTR_PACKAGE_INFO, &pinfo);
184 
185  if (SEC_E_OK == ret)
186  {
187  m_ssp_info= pinfo.PackageInfo;
188  }
189  else
190  DBUG_PRINT("error",
191  ("Could not obtain SSP info from authentication context"
192  ", QueryContextAttributes() failed with error %X", ret));
193  }
194 
195  return m_ssp_info ? m_ssp_info->Name : NULL;
196 }
197 
198 #endif
199 
200 
217 {
218  /*
219  First check for errors and set the m_complete flag if the result
220  indicates that handshake is complete.
221  */
222 
223  switch (ret)
224  {
225  case SEC_E_OK:
226  case SEC_I_COMPLETE_NEEDED:
227  // Handshake completed
228  m_complete= true;
229  break;
230 
231  case SEC_I_CONTINUE_NEEDED:
232  case SEC_I_COMPLETE_AND_CONTINUE:
233  break;
234 
235  default:
236  m_error= ret;
237  return true;
238  }
239 
240  m_have_sec_context= true;
241 
242  /*
243  If the result indicates a need for this, complete the authentication
244  token.
245  */
246 
247  switch (ret)
248  {
249  case SEC_I_COMPLETE_NEEDED:
250  case SEC_I_COMPLETE_AND_CONTINUE:
251  ret= CompleteAuthToken(&m_sctx, &m_output);
252  if (ret != 0)
253  {
254  DBUG_PRINT("error", ("CompleteAuthToken() failed with error %X", ret));
255  m_error= ret;
256  return true;
257  }
258  default:
259  break;
260  }
261 
262  return false;
263 }
264 
265 
269 Security_buffer::Security_buffer(const Blob &blob): m_allocated(false)
270 {
271  init(blob.ptr(), blob.len());
272 }
273 
274 
275 Security_buffer::Security_buffer(): m_allocated(true)
276 {
277  init(NULL, 0);
278 }
279 
280 
281 void Security_buffer::free(void)
282 {
283  if (m_allocated && NULL != ptr())
284  {
285  FreeContextBuffer(ptr());
286  init(NULL, 0);
287  }
288 }