Commit 43c3be4a authored by unknown's avatar unknown

A fix for Bug#8226 "Cannot connect via shared memory":

provide created shared memory objects with proper
access rights to make them usable when client and server
are running under different accounts. 
Post review fixes.


VC++Files/mysys/mysys.dsp:
  Add my_windac.c to mysys.lib
include/my_sys.h:
  Declarations for SECURITY_ATTRIBUTES create/destroy functions.
mysys/Makefile.am:
  Add my_windac.c to the list of compiled files.
sql-common/client.c:
  Lower requested access rights for events as the server won't 
  provide clients with ALL access in order to prevent denial
  of service attack.
sql/mysqld.cc:
  Set proper security attributes for the kernel objects to make them
  usable when mysqld is running as a Windows service.
parent a4410a00
......@@ -532,6 +532,11 @@ SOURCE=.\my_wincond.c
# End Source File
# Begin Source File
SOURCE=.\my_windac.c
# End Source File
# Begin Source File
SOURCE=.\my_winsem.c
# End Source File
# Begin Source File
......
......@@ -780,6 +780,14 @@ extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to,
#ifdef __WIN__
extern my_bool have_tcpip; /* Is set if tcpip is used */
/* implemented in my_windac.c */
int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror,
DWORD owner_rights, DWORD everybody_rights);
void my_security_attr_free(SECURITY_ATTRIBUTES *sa);
#endif
#ifdef __NETWARE__
void netware_reg_user(const char *ip, const char *user,
......
......@@ -53,7 +53,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c \
my_net.c my_semaphore.c my_port.c my_sleep.c \
charset.c charset-def.c my_bitmap.c my_bit.c md5.c \
my_gethostbyname.c rijndael.c my_aes.c sha1.c \
my_handler.c my_netware.c
my_handler.c my_netware.c my_windac.c
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
thr_mutex.c thr_rwlock.c
libmysys_a_LIBADD = @THREAD_LOBJECTS@
......
/* Copyright (C) 2000-2005 MySQL AB
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; either version 2 of the License, or
(at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include "m_string.h"
#ifdef __WIN__
/* Windows NT/2000 discretionary access control utility functions. */
/*
Check if the operating system is built on NT technology.
RETURN
0 Windows 95/98/Me
1 otherwise
*/
static my_bool is_nt()
{
return GetVersion() < 0x80000000;
}
/*
Auxilary structure to store pointers to the data which we need to keep
around while SECURITY_ATTRIBUTES is in use.
*/
typedef struct st_my_security_attr
{
PSID everyone_sid;
PACL dacl;
} My_security_attr;
/*
Allocate and initialize SECURITY_ATTRIBUTES setting up access
rights for the owner and group `Everybody'.
SYNOPSIS
my_security_attr_create()
psa [OUT] pointer to store the pointer to SA in
perror [OUT] pointer to store error message if there was an
error
owner_rights [IN] access rights for the owner
everyone_rights [IN] access rights for group Everybody
DESCRIPTION
Set up the security attributes to provide clients with sufficient
access rights to a kernel object. We need this function
because if we simply grant all access to everybody (by installing
a NULL DACL) a mailicious user can attempt a denial of service
attack by taking ownership over the kernel object. Upon successful
return `psa' contains a pointer to SECUIRITY_ATTRIBUTES that can be used
to create kernel objects with proper access rights.
RETURN
0 success, psa is 0 or points to a valid SA structure,
perror is left intact
!0 error, SA is set to 0, error message is stored in perror
*/
int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror,
DWORD owner_rights, DWORD everyone_rights)
{
/* Top-level SID authority */
SID_IDENTIFIER_AUTHORITY world_auth= SECURITY_WORLD_SID_AUTHORITY;
PSID everyone_sid= 0;
HANDLE htoken= 0;
SECURITY_ATTRIBUTES *sa= 0;
PACL dacl= 0;
DWORD owner_token_length, dacl_length;
SECURITY_DESCRIPTOR *sd;
PTOKEN_USER owner_token;
PSID owner_sid;
My_security_attr *attr;
if (! is_nt())
{
*psa= 0;
return 0;
}
/*
Get SID of Everyone group. Easier to retrieve all SIDs each time
this function is called than worry about thread safety.
*/
if (! AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &everyone_sid))
{
*perror= "Failed to retrieve the SID of Everyone group";
goto error;
}
/*
Get SID of the owner. Using GetSecurityInfo this task can be done
in just one call instead of five, but GetSecurityInfo declared in
aclapi.h, so I hesitate to use it.
SIC: OpenThreadToken works only if there is an active impersonation
token, hence OpenProcessToken is used.
*/
if (! OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htoken))
{
*perror= "Failed to retrieve thread access token";
goto error;
}
GetTokenInformation(htoken, TokenUser, 0, 0, &owner_token_length);
if (! my_multi_malloc(MYF(MY_WME),
&sa, ALIGN_SIZE(sizeof(SECURITY_ATTRIBUTES)) +
sizeof(My_security_attr),
&sd, sizeof(SECURITY_DESCRIPTOR),
&owner_token, owner_token_length,
0))
{
*perror= "Failed to allocate memory for SECURITY_ATTRIBUTES";
goto error;
}
bzero(owner_token, owner_token_length);
if (! GetTokenInformation(htoken, TokenUser, owner_token,
owner_token_length, &owner_token_length))
{
*perror= "GetTokenInformation failed";
goto error;
}
owner_sid= owner_token->User.Sid;
if (! IsValidSid(owner_sid))
{
*perror= "IsValidSid failed";
goto error;
}
/* Calculate the amount of memory that must be allocated for the DACL */
dacl_length= sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)) * 2 +
GetLengthSid(everyone_sid) + GetLengthSid(owner_sid);
/* Create an ACL */
if (! (dacl= (PACL) my_malloc(dacl_length, MYF(MY_ZEROFILL|MY_WME))))
{
*perror= "Failed to allocate memory for DACL";
goto error;
}
if (! InitializeAcl(dacl, dacl_length, ACL_REVISION))
{
*perror= "Failed to initialize DACL";
goto error;
}
if (! AddAccessAllowedAce(dacl, ACL_REVISION, everyone_rights, everyone_sid))
{
*perror= "Failed to set up DACL";
goto error;
}
if (! AddAccessAllowedAce(dacl, ACL_REVISION, owner_rights, owner_sid))
{
*perror= "Failed to set up DACL";
goto error;
}
if (! InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION))
{
*perror= "Could not initialize security descriptor";
goto error;
}
if (! SetSecurityDescriptorDacl(sd, TRUE, dacl, FALSE))
{
*perror= "Failed to install DACL";
goto error;
}
sa->nLength= sizeof(*sa);
sa->bInheritHandle= TRUE;
sa->lpSecurityDescriptor= sd;
/* Save pointers to everyone_sid and dacl to be able to clean them up */
attr= (My_security_attr*) (((char*) sa) + ALIGN_SIZE(sizeof(*sa)));
attr->everyone_sid= everyone_sid;
attr->dacl= dacl;
*psa= sa;
CloseHandle(htoken);
return 0;
error:
if (everyone_sid)
FreeSid(everyone_sid);
if (htoken)
CloseHandle(htoken);
my_free((gptr) sa, MYF(MY_ALLOW_ZERO_PTR));
my_free((gptr) dacl, MYF(MY_ALLOW_ZERO_PTR));
*psa= 0;
return 1;
}
/*
Cleanup security attributes freeing used memory.
SYNOPSIS
my_security_attr_free()
sa security attributes
*/
void my_security_attr_free(SECURITY_ATTRIBUTES *sa)
{
if (sa)
{
My_security_attr *attr= (My_security_attr*)
(((char*)sa) + ALIGN_SIZE(sizeof(*sa)));
FreeSid(attr->everyone_sid);
my_free((gptr) attr->dacl, MYF(0));
my_free((gptr) sa, MYF(0));
}
}
#endif /* __WIN__ */
......@@ -408,6 +408,7 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
char *suffix_pos;
DWORD error_allow = 0;
DWORD error_code = 0;
DWORD event_access_rights= SYNCHRONIZE | EVENT_MODIFY_STATE;
char *shared_memory_base_name = mysql->options.shared_memory_base_name;
/*
......@@ -419,13 +420,13 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
*/
suffix_pos = strxmov(tmp,shared_memory_base_name,"_",NullS);
strmov(suffix_pos, "CONNECT_REQUEST");
if (!(event_connect_request= OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)))
if (!(event_connect_request= OpenEvent(event_access_rights, FALSE, tmp)))
{
error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
goto err;
}
strmov(suffix_pos, "CONNECT_ANSWER");
if (!(event_connect_answer= OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)))
if (!(event_connect_answer= OpenEvent(event_access_rights,FALSE,tmp)))
{
error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
goto err;
......@@ -487,35 +488,35 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
}
strmov(suffix_pos, "SERVER_WROTE");
if ((event_server_wrote = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL)
if ((event_server_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
{
error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
goto err2;
}
strmov(suffix_pos, "SERVER_READ");
if ((event_server_read = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL)
if ((event_server_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
{
error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
goto err2;
}
strmov(suffix_pos, "CLIENT_WROTE");
if ((event_client_wrote = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL)
if ((event_client_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
{
error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
goto err2;
}
strmov(suffix_pos, "CLIENT_READ");
if ((event_client_read = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL)
if ((event_client_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
{
error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
goto err2;
}
strmov(suffix_pos, "CONNECTION_CLOSED");
if ((event_conn_closed = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL)
if ((event_conn_closed = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
{
error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
goto err2;
......
......@@ -3817,10 +3817,19 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
char *suffix_pos;
char connect_number_char[22], *p;
const char *errmsg= 0;
SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0;
my_thread_init();
DBUG_ENTER("handle_connections_shared_memorys");
DBUG_PRINT("general",("Waiting for allocated shared memory."));
if (my_security_attr_create(&sa_event, &errmsg,
GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE))
goto error;
if (my_security_attr_create(&sa_mapping, &errmsg,
GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE))
goto error;
/*
The name of event and file-mapping events create agree next rule:
shared_memory_base_name+unique_part
......@@ -3830,22 +3839,22 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
*/
suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS);
strmov(suffix_pos, "CONNECT_REQUEST");
if ((smem_event_connect_request= CreateEvent(0,FALSE,FALSE,tmp)) == 0)
if ((smem_event_connect_request= CreateEvent(sa_event,
FALSE, FALSE, tmp)) == 0)
{
errmsg= "Could not create request event";
goto error;
}
strmov(suffix_pos, "CONNECT_ANSWER");
if ((event_connect_answer= CreateEvent(0,FALSE,FALSE,tmp)) == 0)
if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
{
errmsg="Could not create answer event";
goto error;
}
strmov(suffix_pos, "CONNECT_DATA");
if ((handle_connect_file_map= CreateFileMapping(INVALID_HANDLE_VALUE,0,
PAGE_READWRITE,
0,sizeof(connect_number),
tmp)) == 0)
if ((handle_connect_file_map=
CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0)
{
errmsg= "Could not create file mapping";
goto error;
......@@ -3890,10 +3899,9 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char,
"_",NullS);
strmov(suffix_pos, "DATA");
if ((handle_client_file_map= CreateFileMapping(INVALID_HANDLE_VALUE,0,
PAGE_READWRITE,0,
smem_buffer_length,
tmp)) == 0)
if ((handle_client_file_map=
CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0)
{
errmsg= "Could not create file mapping";
goto errorconn;
......@@ -3906,31 +3914,33 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
goto errorconn;
}
strmov(suffix_pos, "CLIENT_WROTE");
if ((event_client_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
{
errmsg= "Could not create client write event";
goto errorconn;
}
strmov(suffix_pos, "CLIENT_READ");
if ((event_client_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
{
errmsg= "Could not create client read event";
goto errorconn;
}
strmov(suffix_pos, "SERVER_READ");
if ((event_server_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
{
errmsg= "Could not create server read event";
goto errorconn;
}
strmov(suffix_pos, "SERVER_WROTE");
if ((event_server_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
if ((event_server_wrote= CreateEvent(sa_event,
FALSE, FALSE, tmp)) == 0)
{
errmsg= "Could not create server write event";
goto errorconn;
}
strmov(suffix_pos, "CONNECTION_CLOSED");
if ((event_conn_closed= CreateEvent(0, TRUE , FALSE, tmp)) == 0)
if ((event_conn_closed= CreateEvent(sa_event,
TRUE, FALSE, tmp)) == 0)
{
errmsg= "Could not create closed connection event";
goto errorconn;
......@@ -3980,6 +3990,8 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
NullS);
sql_perror(buff);
}
my_security_attr_free(sa_event);
my_security_attr_free(sa_mapping);
if (handle_client_file_map)
CloseHandle(handle_client_file_map);
if (handle_client_map)
......@@ -4005,6 +4017,8 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS);
sql_perror(buff);
}
my_security_attr_free(sa_event);
my_security_attr_free(sa_mapping);
if (handle_connect_map) UnmapViewOfFile(handle_connect_map);
if (handle_connect_file_map) CloseHandle(handle_connect_file_map);
if (event_connect_answer) CloseHandle(event_connect_answer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment