/* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
#include "common.h"
#include <sddl.h> // for ConvertSidToStringSid()
#include <secext.h> // for GetUserNameEx()
template <> void error_log_print<error_log_level::INFO>(const char *fmt, ...);
template <> void error_log_print<error_log_level::WARNING>(const char *fmt, ...);
template <> void error_log_print<error_log_level::ERROR>(const char *fmt, ...);
/**
Option indicating desired level of logging . Values :
0 - no logging
1 - log only error messages
2 - additionally log warnings
3 - additionally log info notes
4 - also log debug messages
Value of this option should be taken into account in the
implementation of error_log_vprint ( ) function ( see
log_client . cc ) .
Note : No error or debug messages are logged in production code
( see logging macros in common . h ) .
*/
int opt_auth_win_log_level= 2 ;
/** Connection class **************************************************/
/**
Create connection out of an active MYSQL_PLUGIN_VIO object .
@ param [ in ] vio pointer to a @ c MYSQL_PLUGIN_VIO object used for
connection - it can not be NULL
*/
Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0 )
{
DBUG_ASSERT(vio);
}
/**
Write data to the connection .
@ param [ in ] blob data to be written
@ return 0 on success , VIO error code on failure .
@ note In case of error , VIO error code is stored in the connection object
and can be obtained with @ c error ( ) method .
*/
int Connection::write(const Blob &blob)
{
m_error= m_vio->write_packet(m_vio, blob.ptr(), (int )blob.len());
#ifndef DBUG_OFF
if (m_error)
DBUG_PRINT("error" , ("vio write error %d" , m_error));
#endif
return m_error;
}
/**
Read data from connection .
@ return A Blob containing read packet or null Blob in case of error .
@ note In case of error , VIO error code is stored in the connection object
and can be obtained with @ c error ( ) method .
*/
Blob Connection::read()
{
unsigned char *ptr;
int len= m_vio->read_packet(m_vio, &ptr);
if (len < 0 )
{
m_error= true ;
return Blob();
}
return Blob(ptr, len);
}
/** Sid class *****************************************************/
/**
Create Sid object corresponding to a given account name .
@ param [ in ] account_name name of a Windows account
The account name can be in any form accepted by @ c LookupAccountName ( )
function .
@ note In case of errors created object is invalid and its @ c is_valid ( )
method returns @ c false .
*/
Sid::Sid(const wchar_t *account_name): m_data(NULL)
#ifndef DBUG_OFF
, m_as_string(NULL)
#endif
{
DWORD sid_size= 0 , domain_size= 0 ;
bool success;
// Determine required buffer sizes
success= LookupAccountNameW(NULL, account_name, NULL, &sid_size,
NULL, &domain_size, &m_type);
if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
#ifndef DBUG_OFF
Error_message_buf error_buf;
DBUG_PRINT("error" , ("Could not determine SID buffer size, "
"LookupAccountName() failed with error %X (%s)" ,
GetLastError(), get_last_error_message(error_buf)));
#endif
return ;
}
// Query for SID (domain is ignored)
wchar_t *domain= new wchar_t [domain_size];
m_data= (TOKEN_USER*) new BYTE[sid_size + sizeof (TOKEN_USER)];
m_data->User.Sid= (BYTE*)m_data + sizeof (TOKEN_USER);
success= LookupAccountNameW(NULL, account_name,
m_data->User.Sid, &sid_size,
domain, &domain_size,
&m_type);
if (!success || !is_valid())
{
#ifndef DBUG_OFF
Error_message_buf error_buf;
DBUG_PRINT("error" , ("Could not determine SID of '%S', "
"LookupAccountName() failed with error %X (%s)" ,
account_name, GetLastError(),
get_last_error_message(error_buf)));
#endif
goto fail;
}
goto end;
fail:
if (m_data)
delete [] m_data;
m_data= NULL;
end:
if (domain)
delete [] domain;
}
/**
Create Sid object corresponding to a given security token .
@ param [ in ] token security token of a Windows account
@ note In case of errors created object is invalid and its @ c is_valid ( )
method returns @ c false .
*/
Sid::Sid(HANDLE token): m_data(NULL)
#ifndef DBUG_OFF
, m_as_string(NULL)
#endif
{
DWORD req_size= 0 ;
bool success;
// Determine required buffer size
success= GetTokenInformation(token, TokenUser, NULL, 0 , &req_size);
if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
#ifndef DBUG_OFF
Error_message_buf error_buf;
DBUG_PRINT("error" , ("Could not determine SID buffer size, "
"GetTokenInformation() failed with error %X (%s)" ,
GetLastError(), get_last_error_message(error_buf)));
#endif
return ;
}
m_data= (TOKEN_USER*) new BYTE[req_size];
success= GetTokenInformation(token, TokenUser, m_data, req_size, &req_size);
if (!success || !is_valid())
{
delete [] m_data;
m_data= NULL;
#ifndef DBUG_OFF
if (!success)
{
Error_message_buf error_buf;
DBUG_PRINT("error" , ("Could not read SID from security token, "
"GetTokenInformation() failed with error %X (%s)" ,
GetLastError(), get_last_error_message(error_buf)));
}
#endif
}
}
Sid::~Sid()
{
if (m_data)
delete [] m_data;
#ifndef DBUG_OFF
if (m_as_string)
LocalFree(m_as_string);
#endif
}
/// Check if Sid object is valid.
bool Sid::is_valid(void ) const
{
return m_data && m_data->User.Sid && IsValidSid(m_data->User.Sid);
}
#ifndef DBUG_OFF
/**
Produces string representation of the SID .
@ return String representation of the SID or NULL in case of errors .
@ note Memory allocated for the string is automatically freed in Sid ' s
destructor .
*/
const char * Sid::as_string()
{
if (!m_data)
return NULL;
if (!m_as_string)
{
bool success= ConvertSidToStringSid(m_data->User.Sid, &m_as_string);
if (!success)
{
#ifndef DBUG_OFF
Error_message_buf error_buf;
DBUG_PRINT("error" , ("Could not get textual representation of a SID, "
"ConvertSidToStringSid() failed with error %X (%s)" ,
GetLastError(), get_last_error_message(error_buf)));
#endif
m_as_string= NULL;
return NULL;
}
}
return m_as_string;
}
#endif
bool Sid::operator ==(const Sid &other)
{
if (!is_valid() || !other.is_valid())
return false ;
return EqualSid(m_data->User.Sid, other.m_data->User.Sid);
}
/** Generating User Principal Name *************************/
/**
Call Windows API functions to get UPN of the current user and store it
in internal buffer .
*/
UPN::UPN(): m_buf(NULL)
{
wchar_t buf1[MAX_SERVICE_NAME_LENGTH];
// First we try to use GetUserNameEx.
m_len= sizeof (buf1)/sizeof (wchar_t );
if (!GetUserNameExW(NameUserPrincipal, buf1, (PULONG)&m_len))
{
if (GetLastError())
{
#ifndef DBUG_OFF
Error_message_buf error_buf;
DBUG_PRINT("note" , ("When determining UPN"
", GetUserNameEx() failed with error %X (%s)" ,
GetLastError(), get_last_error_message(error_buf)));
#endif
if (ERROR_MORE_DATA == GetLastError())
ERROR_LOG(INFO, ("Buffer overrun when determining UPN:"
" need %ul characters but have %ul" ,
m_len, sizeof (buf1)/sizeof (WCHAR)));
}
m_len= 0 ; // m_len == 0 indicates invalid UPN
return ;
}
/*
UPN is stored in buf1 in wide - char format - convert it to utf8
for sending over network .
*/
m_buf= wchar_to_utf8(buf1, &m_len);
if (!m_buf)
ERROR_LOG(ERROR, ("Failed to convert UPN to utf8" ));
// Note: possible error would be indicated by the fact that m_buf is NULL.
return ;
}
UPN::~UPN()
{
if (m_buf)
free(m_buf);
}
/**
Convert a wide - char string to utf8 representation .
@ param [ in ] string null - terminated wide - char string to be converted
@ param [ in , out ] len length of the string to be converted or 0 ; on
return length ( in bytes , excluding terminating
null character ) of the converted string
If len is 0 then the length of the string will be computed by this function .
@ return Pointer to a buffer containing utf8 representation or NULL in
case of error .
@ note The returned buffer must be freed with @ c free ( ) call .
*/
char * wchar_to_utf8(const wchar_t *string, size_t *len)
{
char *buf= NULL;
size_t str_len= len && *len ? *len : wcslen(string);
/*
A conversion from utf8 to wchar_t will never take more than 3 bytes per
character , so a buffer of length 3 * str_len should be sufficient .
We check that assumption with an assertion later .
*/
size_t buf_len= 3 * str_len;
buf= (char *)malloc(buf_len + 1 );
if (!buf)
{
DBUG_PRINT("error" ,("Out of memory when converting string '%S' to utf8" ,
string));
return NULL;
}
int res= WideCharToMultiByte(CP_UTF8, // convert to UTF-8
0 , // conversion flags
string, // input buffer
(int )str_len, // its length
buf, (int )buf_len, // output buffer and its size
NULL, NULL); // default character (not used)
if (res)
{
buf[res]= '\0' ;
if (len)
*len= res;
return buf;
}
// res is 0 which indicates error
#ifndef DBUG_OFF
Error_message_buf error_buf;
DBUG_PRINT("error" , ("Could not convert string '%S' to utf8"
", WideCharToMultiByte() failed with error %X (%s)" ,
string, GetLastError(),
get_last_error_message(error_buf)));
#endif
// Let's check our assumption about sufficient buffer size
DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
return NULL;
}
/**
Convert an utf8 string to a wide - char string .
@ param [ in ] string null - terminated utf8 string to be converted
@ param [ in , out ] len length of the string to be converted or 0 ; on
return length ( in chars ) of the converted string
If len is 0 then the length of the string will be computed by this function .
@ return Pointer to a buffer containing wide - char representation or NULL in
case of error .
@ note The returned buffer must be freed with @ c free ( ) call .
*/
wchar_t * utf8_to_wchar(const char *string, size_t *len)
{
size_t buf_len;
/*
Note : length ( in bytes ) of an utf8 string is always bigger than the
number of characters in this string . Hence a buffer of size len will
be sufficient . We add 1 for the terminating null character .
*/
buf_len= len && *len ? *len : strlen(string);
wchar_t *buf= (wchar_t *)malloc((buf_len+1 )*sizeof (wchar_t ));
if (!buf)
{
DBUG_PRINT("error" ,("Out of memory when converting utf8 string '%s'"
" to wide-char representation" , string));
return NULL;
}
size_t res;
res= MultiByteToWideChar(CP_UTF8, // convert from UTF-8
0 , // conversion flags
string, // input buffer
(int )buf_len, // its size
buf, (int )buf_len); // output buffer and its size
if (res)
{
buf[res]= '\0' ;
if (len)
*len= res;
return buf;
}
// error in MultiByteToWideChar()
#ifndef DBUG_OFF
Error_message_buf error_buf;
DBUG_PRINT("error" , ("Could not convert UPN from UTF-8"
", MultiByteToWideChar() failed with error %X (%s)" ,
GetLastError(), get_last_error_message(error_buf)));
#endif
// Let's check our assumption about sufficient buffer size
DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
return NULL;
}
/** Error handling ****************************************************/
/**
Returns error message corresponding to the last Windows error given
by GetLastError ( ) .
@ note Error message is overwritten by next call to
@ c get_last_error_message ( ) .
*/
const char * get_last_error_message(Error_message_buf buf)
{
int error= GetLastError();
buf[0 ]= '\0' ;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)buf, ERRMSG_BUFSIZE , NULL );
return buf;
}
Messung V0.5 in Prozent C=92 H=97 G=94
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland