MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
common.cc
1 /* Copyright (c) 2011, 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 "common.h"
17 #include <sddl.h> // for ConvertSidToStringSid()
18 #include <secext.h> // for GetUserNameEx()
19 
20 
21 template <> void error_log_print<error_log_level::INFO>(const char *fmt, ...);
22 template <> void error_log_print<error_log_level::WARNING>(const char *fmt, ...);
23 template <> void error_log_print<error_log_level::ERROR>(const char *fmt, ...);
24 
41 int opt_auth_win_log_level= 2;
42 
43 
53 Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0)
54 {
55  DBUG_ASSERT(vio);
56 }
57 
58 
70 int Connection::write(const Blob &blob)
71 {
72  m_error= m_vio->write_packet(m_vio, blob.ptr(), blob.len());
73 
74 #ifndef DBUG_OFF
75  if (m_error)
76  DBUG_PRINT("error", ("vio write error %d", m_error));
77 #endif
78 
79  return m_error;
80 }
81 
82 
93 {
94  unsigned char *ptr;
95  int len= m_vio->read_packet(m_vio, &ptr);
96 
97  if (len < 0)
98  {
99  m_error= true;
100  return Blob();
101  }
102 
103  return Blob(ptr, len);
104 }
105 
106 
122 Sid::Sid(const wchar_t *account_name): m_data(NULL)
123 #ifndef DBUG_OFF
124 , m_as_string(NULL)
125 #endif
126 {
127  DWORD sid_size= 0, domain_size= 0;
128  bool success;
129 
130  // Determine required buffer sizes
131 
132  success= LookupAccountNameW(NULL, account_name, NULL, &sid_size,
133  NULL, &domain_size, &m_type);
134 
135  if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
136  {
137 #ifndef DBUG_OFF
138  Error_message_buf error_buf;
139  DBUG_PRINT("error", ("Could not determine SID buffer size, "
140  "LookupAccountName() failed with error %X (%s)",
141  GetLastError(), get_last_error_message(error_buf)));
142 #endif
143  return;
144  }
145 
146  // Query for SID (domain is ignored)
147 
148  wchar_t *domain= new wchar_t[domain_size];
149  m_data= (TOKEN_USER*) new BYTE[sid_size + sizeof(TOKEN_USER)];
150  m_data->User.Sid= (BYTE*)m_data + sizeof(TOKEN_USER);
151 
152  success= LookupAccountNameW(NULL, account_name,
153  m_data->User.Sid, &sid_size,
154  domain, &domain_size,
155  &m_type);
156 
157  if (!success || !is_valid())
158  {
159 #ifndef DBUG_OFF
160  Error_message_buf error_buf;
161  DBUG_PRINT("error", ("Could not determine SID of '%S', "
162  "LookupAccountName() failed with error %X (%s)",
163  account_name, GetLastError(),
164  get_last_error_message(error_buf)));
165 #endif
166  goto fail;
167  }
168 
169  goto end;
170 
171 fail:
172  if (m_data)
173  delete [] m_data;
174  m_data= NULL;
175 
176 end:
177  if (domain)
178  delete [] domain;
179 }
180 
181 
191 Sid::Sid(HANDLE token): m_data(NULL)
192 #ifndef DBUG_OFF
193 , m_as_string(NULL)
194 #endif
195 {
196  DWORD req_size= 0;
197  bool success;
198 
199  // Determine required buffer size
200 
201  success= GetTokenInformation(token, TokenUser, NULL, 0, &req_size);
202  if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
203  {
204 #ifndef DBUG_OFF
205  Error_message_buf error_buf;
206  DBUG_PRINT("error", ("Could not determine SID buffer size, "
207  "GetTokenInformation() failed with error %X (%s)",
208  GetLastError(), get_last_error_message(error_buf)));
209 #endif
210  return;
211  }
212 
213  m_data= (TOKEN_USER*) new BYTE[req_size];
214  success= GetTokenInformation(token, TokenUser, m_data, req_size, &req_size);
215 
216  if (!success || !is_valid())
217  {
218  delete [] m_data;
219  m_data= NULL;
220 #ifndef DBUG_OFF
221  if (!success)
222  {
223  Error_message_buf error_buf;
224  DBUG_PRINT("error", ("Could not read SID from security token, "
225  "GetTokenInformation() failed with error %X (%s)",
226  GetLastError(), get_last_error_message(error_buf)));
227  }
228 #endif
229  }
230 }
231 
232 
233 Sid::~Sid()
234 {
235  if (m_data)
236  delete [] m_data;
237 #ifndef DBUG_OFF
238  if (m_as_string)
239  LocalFree(m_as_string);
240 #endif
241 }
242 
244 bool Sid::is_valid(void) const
245 {
246  return m_data && m_data->User.Sid && IsValidSid(m_data->User.Sid);
247 }
248 
249 
250 #ifndef DBUG_OFF
251 
261 const char* Sid::as_string()
262 {
263  if (!m_data)
264  return NULL;
265 
266  if (!m_as_string)
267  {
268  bool success= ConvertSidToStringSid(m_data->User.Sid, &m_as_string);
269 
270  if (!success)
271  {
272 #ifndef DBUG_OFF
273  Error_message_buf error_buf;
274  DBUG_PRINT("error", ("Could not get textual representation of a SID, "
275  "ConvertSidToStringSid() failed with error %X (%s)",
276  GetLastError(), get_last_error_message(error_buf)));
277 #endif
278  m_as_string= NULL;
279  return NULL;
280  }
281  }
282 
283  return m_as_string;
284 }
285 
286 #endif
287 
288 
289 bool Sid::operator ==(const Sid &other)
290 {
291  if (!is_valid() || !other.is_valid())
292  return false;
293 
294  return EqualSid(m_data->User.Sid, other.m_data->User.Sid);
295 }
296 
297 
305 UPN::UPN(): m_buf(NULL)
306 {
307  wchar_t buf1[MAX_SERVICE_NAME_LENGTH];
308 
309  // First we try to use GetUserNameEx.
310 
311  m_len= sizeof(buf1)/sizeof(wchar_t);
312 
313  if (!GetUserNameExW(NameUserPrincipal, buf1, (PULONG)&m_len))
314  {
315  if (GetLastError())
316  {
317 #ifndef DBUG_OFF
318  Error_message_buf error_buf;
319  DBUG_PRINT("note", ("When determining UPN"
320  ", GetUserNameEx() failed with error %X (%s)",
321  GetLastError(), get_last_error_message(error_buf)));
322 #endif
323  if (ERROR_MORE_DATA == GetLastError())
324  ERROR_LOG(INFO, ("Buffer overrun when determining UPN:"
325  " need %ul characters but have %ul",
326  m_len, sizeof(buf1)/sizeof(WCHAR)));
327  }
328 
329  m_len= 0; // m_len == 0 indicates invalid UPN
330  return;
331  }
332 
333  /*
334  UPN is stored in buf1 in wide-char format - convert it to utf8
335  for sending over network.
336  */
337 
338  m_buf= wchar_to_utf8(buf1, &m_len);
339 
340  if(!m_buf)
341  ERROR_LOG(ERROR, ("Failed to convert UPN to utf8"));
342 
343  // Note: possible error would be indicated by the fact that m_buf is NULL.
344  return;
345 }
346 
347 
348 UPN::~UPN()
349 {
350  if (m_buf)
351  free(m_buf);
352 }
353 
354 
371 char* wchar_to_utf8(const wchar_t *string, size_t *len)
372 {
373  char *buf= NULL;
374  size_t str_len= len && *len ? *len : wcslen(string);
375 
376  /*
377  A conversion from utf8 to wchar_t will never take more than 3 bytes per
378  character, so a buffer of length 3 * str_len schould be sufficient.
379  We check that assumption with an assertion later.
380  */
381 
382  size_t buf_len= 3 * str_len;
383 
384  buf= (char*)malloc(buf_len + 1);
385  if (!buf)
386  {
387  DBUG_PRINT("error",("Out of memory when converting string '%S' to utf8",
388  string));
389  return NULL;
390  }
391 
392  int res= WideCharToMultiByte(CP_UTF8, // convert to UTF-8
393  0, // conversion flags
394  string, // input buffer
395  str_len, // its length
396  buf, buf_len, // output buffer and its size
397  NULL, NULL); // default character (not used)
398 
399  if (res)
400  {
401  buf[res]= '\0';
402  if (len)
403  *len= res;
404  return buf;
405  }
406 
407  // res is 0 which indicates error
408 
409 #ifndef DBUG_OFF
410  Error_message_buf error_buf;
411  DBUG_PRINT("error", ("Could not convert string '%S' to utf8"
412  ", WideCharToMultiByte() failed with error %X (%s)",
413  string, GetLastError(),
414  get_last_error_message(error_buf)));
415 #endif
416 
417  // Let's check our assumption about sufficient buffer size
418  DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
419 
420  return NULL;
421 }
422 
423 
439 wchar_t* utf8_to_wchar(const char *string, size_t *len)
440 {
441  size_t buf_len;
442 
443  /*
444  Note: length (in bytes) of an utf8 string is always bigger than the
445  number of characters in this string. Hence a buffer of size len will
446  be sufficient. We add 1 for the terminating null character.
447  */
448 
449  buf_len= len && *len ? *len : strlen(string);
450  wchar_t *buf= (wchar_t*)malloc((buf_len+1)*sizeof(wchar_t));
451 
452  if (!buf)
453  {
454  DBUG_PRINT("error",("Out of memory when converting utf8 string '%s'"
455  " to wide-char representation", string));
456  return NULL;
457  }
458 
459  size_t res;
460  res= MultiByteToWideChar(CP_UTF8, // convert from UTF-8
461  0, // conversion flags
462  string, // input buffer
463  buf_len, // its size
464  buf, buf_len); // output buffer and its size
465  if (res)
466  {
467  buf[res]= '\0';
468  if (len)
469  *len= res;
470  return buf;
471  }
472 
473  // error in MultiByteToWideChar()
474 
475 #ifndef DBUG_OFF
476  Error_message_buf error_buf;
477  DBUG_PRINT("error", ("Could not convert UPN from UTF-8"
478  ", MultiByteToWideChar() failed with error %X (%s)",
479  GetLastError(), get_last_error_message(error_buf)));
480 #endif
481 
482  // Let's check our assumption about sufficient buffer size
483  DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
484 
485  return NULL;
486 }
487 
488 
500 const char* get_last_error_message(Error_message_buf buf)
501 {
502  int error= GetLastError();
503 
504  buf[0]= '\0';
505  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
506  NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
507  (LPTSTR)buf, sizeof(buf), NULL );
508 
509  return buf;
510 }