~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

Viewing changes to libmysql/authentication_win/common.cc

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "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
 
 
25
/**
 
26
  Option indicating desired level of logging. Values:
 
27
 
 
28
  0 - no logging
 
29
  1 - log only error messages
 
30
  2 - additionally log warnings
 
31
  3 - additionally log info notes
 
32
  4 - also log debug messages
 
33
 
 
34
  Value of this option should be taken into account in the 
 
35
  implementation of  error_log_vprint() function (see 
 
36
  log_client.cc).
 
37
 
 
38
  Note: No error or debug messages are logged in production code
 
39
  (see logging macros in common.h).
 
40
*/
 
41
int opt_auth_win_log_level= 2;
 
42
 
 
43
 
 
44
/** Connection class **************************************************/
 
45
 
 
46
/**
 
47
  Create connection out of an active MYSQL_PLUGIN_VIO object.
 
48
 
 
49
  @param[in] vio  pointer to a @c MYSQL_PLUGIN_VIO object used for
 
50
                  connection - it can not be NULL
 
51
*/
 
52
 
 
53
Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0)
 
54
{
 
55
  DBUG_ASSERT(vio);
 
56
}
 
57
 
 
58
 
 
59
/**
 
60
  Write data to the connection.
 
61
 
 
62
  @param[in]  blob  data to be written
 
63
 
 
64
  @return 0 on success, VIO error code on failure.
 
65
 
 
66
  @note In case of error, VIO error code is stored in the connection object
 
67
  and can be obtained with @c error() method.
 
68
*/
 
69
 
 
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
 
 
83
/**
 
84
  Read data from connection.
 
85
 
 
86
  @return A Blob containing read packet or null Blob in case of error.
 
87
 
 
88
  @note In case of error, VIO error code is stored in the connection object
 
89
  and can be obtained with @c error() method.
 
90
*/
 
91
 
 
92
Blob Connection::read()
 
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
 
 
107
/** Sid class *****************************************************/
 
108
 
 
109
 
 
110
/**
 
111
  Create Sid object corresponding to a given account name.
 
112
 
 
113
  @param[in]  account_name  name of a Windows account
 
114
 
 
115
  The account name can be in any form accepted by @c LookupAccountName()
 
116
  function.
 
117
 
 
118
  @note In case of errors created object is invalid and its @c is_valid()
 
119
  method returns @c false.
 
120
*/
 
121
 
 
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
 
 
182
/**
 
183
  Create Sid object corresponding to a given security token.
 
184
 
 
185
  @param[in]  token   security token of a Windows account
 
186
 
 
187
  @note In case of errors created object is invalid and its @c is_valid()
 
188
  method returns @c false.
 
189
*/
 
190
 
 
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
 
 
243
/// Check if Sid object is valid.
 
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
 
 
252
/**
 
253
  Produces string representation of the SID.
 
254
 
 
255
  @return String representation of the SID or NULL in case of errors.
 
256
 
 
257
  @note Memory allocated for the string is automatically freed in Sid's
 
258
  destructor.
 
259
*/
 
260
 
 
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
 
 
298
/** Generating User Principal Name *************************/
 
299
 
 
300
/**
 
301
  Call Windows API functions to get UPN of the current user and store it
 
302
  in internal buffer.
 
303
*/
 
304
 
 
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
 
 
355
/**
 
356
  Convert a wide-char string to utf8 representation.
 
357
 
 
358
  @param[in]     string   null-terminated wide-char string to be converted
 
359
  @param[in,out] len      length of the string to be converted or 0; on
 
360
                          return length (in bytes, excluding terminating
 
361
                          null character) of the converted string
 
362
 
 
363
  If len is 0 then the length of the string will be computed by this function.
 
364
 
 
365
  @return Pointer to a buffer containing utf8 representation or NULL in
 
366
          case of error.
 
367
 
 
368
  @note The returned buffer must be freed with @c free() call.          
 
369
*/
 
370
 
 
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
 
 
424
/**
 
425
  Convert an utf8 string to a wide-char string.
 
426
 
 
427
  @param[in]     string   null-terminated utf8 string to be converted
 
428
  @param[in,out] len      length of the string to be converted or 0; on
 
429
                          return length (in chars) of the converted string
 
430
 
 
431
  If len is 0 then the length of the string will be computed by this function.
 
432
 
 
433
  @return Pointer to a buffer containing wide-char representation or NULL in
 
434
          case of error.
 
435
 
 
436
  @note The returned buffer must be freed with @c free() call.          
 
437
*/
 
438
 
 
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
 
 
489
/** Error handling ****************************************************/
 
490
 
 
491
 
 
492
/**
 
493
  Returns error message corresponding to the last Windows error given
 
494
  by GetLastError().
 
495
 
 
496
  @note Error message is overwritten by next call to
 
497
  @c get_last_error_message().
 
498
*/
 
499
 
 
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
}