1
/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
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.
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.
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 */
17
#include <sddl.h> // for ConvertSidToStringSid()
18
#include <secext.h> // for GetUserNameEx()
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, ...);
26
Option indicating desired level of logging. Values:
29
1 - log only error messages
30
2 - additionally log warnings
31
3 - additionally log info notes
32
4 - also log debug messages
34
Value of this option should be taken into account in the
35
implementation of error_log_vprint() function (see
38
Note: No error or debug messages are logged in production code
39
(see logging macros in common.h).
41
int opt_auth_win_log_level= 2;
44
/** Connection class **************************************************/
47
Create connection out of an active MYSQL_PLUGIN_VIO object.
49
@param[in] vio pointer to a @c MYSQL_PLUGIN_VIO object used for
50
connection - it can not be NULL
53
Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0)
60
Write data to the connection.
62
@param[in] blob data to be written
64
@return 0 on success, VIO error code on failure.
66
@note In case of error, VIO error code is stored in the connection object
67
and can be obtained with @c error() method.
70
int Connection::write(const Blob &blob)
72
m_error= m_vio->write_packet(m_vio, blob.ptr(), blob.len());
76
DBUG_PRINT("error", ("vio write error %d", m_error));
84
Read data from connection.
86
@return A Blob containing read packet or null Blob in case of error.
88
@note In case of error, VIO error code is stored in the connection object
89
and can be obtained with @c error() method.
92
Blob Connection::read()
95
int len= m_vio->read_packet(m_vio, &ptr);
103
return Blob(ptr, len);
107
/** Sid class *****************************************************/
111
Create Sid object corresponding to a given account name.
113
@param[in] account_name name of a Windows account
115
The account name can be in any form accepted by @c LookupAccountName()
118
@note In case of errors created object is invalid and its @c is_valid()
119
method returns @c false.
122
Sid::Sid(const wchar_t *account_name): m_data(NULL)
127
DWORD sid_size= 0, domain_size= 0;
130
// Determine required buffer sizes
132
success= LookupAccountNameW(NULL, account_name, NULL, &sid_size,
133
NULL, &domain_size, &m_type);
135
if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
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)));
146
// Query for SID (domain is ignored)
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);
152
success= LookupAccountNameW(NULL, account_name,
153
m_data->User.Sid, &sid_size,
154
domain, &domain_size,
157
if (!success || !is_valid())
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)));
183
Create Sid object corresponding to a given security token.
185
@param[in] token security token of a Windows account
187
@note In case of errors created object is invalid and its @c is_valid()
188
method returns @c false.
191
Sid::Sid(HANDLE token): m_data(NULL)
199
// Determine required buffer size
201
success= GetTokenInformation(token, TokenUser, NULL, 0, &req_size);
202
if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
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)));
213
m_data= (TOKEN_USER*) new BYTE[req_size];
214
success= GetTokenInformation(token, TokenUser, m_data, req_size, &req_size);
216
if (!success || !is_valid())
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)));
239
LocalFree(m_as_string);
243
/// Check if Sid object is valid.
244
bool Sid::is_valid(void) const
246
return m_data && m_data->User.Sid && IsValidSid(m_data->User.Sid);
253
Produces string representation of the SID.
255
@return String representation of the SID or NULL in case of errors.
257
@note Memory allocated for the string is automatically freed in Sid's
261
const char* Sid::as_string()
268
bool success= ConvertSidToStringSid(m_data->User.Sid, &m_as_string);
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)));
289
bool Sid::operator ==(const Sid &other)
291
if (!is_valid() || !other.is_valid())
294
return EqualSid(m_data->User.Sid, other.m_data->User.Sid);
298
/** Generating User Principal Name *************************/
301
Call Windows API functions to get UPN of the current user and store it
305
UPN::UPN(): m_buf(NULL)
307
wchar_t buf1[MAX_SERVICE_NAME_LENGTH];
309
// First we try to use GetUserNameEx.
311
m_len= sizeof(buf1)/sizeof(wchar_t);
313
if (!GetUserNameExW(NameUserPrincipal, buf1, (PULONG)&m_len))
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)));
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)));
329
m_len= 0; // m_len == 0 indicates invalid UPN
334
UPN is stored in buf1 in wide-char format - convert it to utf8
335
for sending over network.
338
m_buf= wchar_to_utf8(buf1, &m_len);
341
ERROR_LOG(ERROR, ("Failed to convert UPN to utf8"));
343
// Note: possible error would be indicated by the fact that m_buf is NULL.
356
Convert a wide-char string to utf8 representation.
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
363
If len is 0 then the length of the string will be computed by this function.
365
@return Pointer to a buffer containing utf8 representation or NULL in
368
@note The returned buffer must be freed with @c free() call.
371
char* wchar_to_utf8(const wchar_t *string, size_t *len)
374
size_t str_len= len && *len ? *len : wcslen(string);
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.
382
size_t buf_len= 3 * str_len;
384
buf= (char*)malloc(buf_len + 1);
387
DBUG_PRINT("error",("Out of memory when converting string '%S' to utf8",
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)
407
// res is 0 which indicates error
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)));
417
// Let's check our assumption about sufficient buffer size
418
DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
425
Convert an utf8 string to a wide-char string.
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
431
If len is 0 then the length of the string will be computed by this function.
433
@return Pointer to a buffer containing wide-char representation or NULL in
436
@note The returned buffer must be freed with @c free() call.
439
wchar_t* utf8_to_wchar(const char *string, size_t *len)
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.
449
buf_len= len && *len ? *len : strlen(string);
450
wchar_t *buf= (wchar_t*)malloc((buf_len+1)*sizeof(wchar_t));
454
DBUG_PRINT("error",("Out of memory when converting utf8 string '%s'"
455
" to wide-char representation", string));
460
res= MultiByteToWideChar(CP_UTF8, // convert from UTF-8
461
0, // conversion flags
462
string, // input buffer
464
buf, buf_len); // output buffer and its size
473
// error in MultiByteToWideChar()
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)));
482
// Let's check our assumption about sufficient buffer size
483
DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
489
/** Error handling ****************************************************/
493
Returns error message corresponding to the last Windows error given
496
@note Error message is overwritten by next call to
497
@c get_last_error_message().
500
const char* get_last_error_message(Error_message_buf buf)
502
int error= GetLastError();
505
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
506
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
507
(LPTSTR)buf, sizeof(buf), NULL );