MDEV-7021 Pass directory security descriptor from mysql_install_db.exe to bootstrap

This ensures that directory permissions are correct in all cases, even if
boostrap is passed non-standard locations for innodb.

Directory permissions are copied from the datadir.
This commit is contained in:
Vladislav Vaintroub 2020-05-11 22:01:40 +02:00
parent d9b81210fd
commit e2bc029211
9 changed files with 98 additions and 42 deletions

View File

@ -60,12 +60,9 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
#ifdef _WIN32
#include <aclapi.h>
/* During copyback, store datadir permissions,
use them to create paths for tables specified
with DATA DIRECTORY.*/
PSECURITY_DESCRIPTOR datadir_security_descriptor;
#endif
#define ROCKSDB_BACKUP_DIR "#rocksdb"
/* list of files to sync for --rsync mode */
@ -664,19 +661,6 @@ mkdirp(const char *pathname, int Flags, myf MyFlags)
return(-1);
}
#ifdef _WIN32
SECURITY_ATTRIBUTES sa{};
sa.lpSecurityDescriptor= datadir_security_descriptor;
sa.nLength= sizeof(sa);
if (CreateDirectory(pathname, datadir_security_descriptor?&sa : NULL)
|| GetLastError() == ERROR_ALREADY_EXISTS
|| GetLastError() == ERROR_ACCESS_DENIED && strlen(pathname) == 2 && pathname[1]==':')
{
free(parent);
return 0;
}
return -1;
#else
/* make this one if parent has been made */
if (my_mkdir(pathname, Flags, MyFlags) == 0) {
free(parent);
@ -688,7 +672,6 @@ mkdirp(const char *pathname, int Flags, myf MyFlags)
free(parent);
return(0);
}
#endif
free(parent);
return(-1);
@ -1757,13 +1740,12 @@ copy_back()
}
#ifdef _WIN32
/* If we create paths for DATA DIRECTORY, they need
the same permissions as the datadir, or service won't
be able to access the files. */
/* Initialize security descriptor for the new directories
to be the same as for datadir */
DWORD res = GetNamedSecurityInfoA(mysql_data_home,
SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, NULL, NULL,
&datadir_security_descriptor);
&my_dir_security_attributes.lpSecurityDescriptor);
if (res != ERROR_SUCCESS) {
msg("Unable to read security descriptor of %s",mysql_data_home);
}

View File

@ -271,6 +271,10 @@ extern int my_umask_dir,
my_recived_signals, /* Signals we have got */
my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */
my_dont_interrupt; /* call remember_intr when set */
#ifdef _WIN32
extern SECURITY_ATTRIBUTES my_dir_security_attributes;
LPSECURITY_ATTRIBUTES my_win_file_secattr();
#endif
extern my_bool my_use_symdir;
extern ulong my_default_record_cache_size;

View File

@ -26,13 +26,18 @@ int my_mkdir(const char *dir, int Flags, myf MyFlags)
{
DBUG_ENTER("my_dir");
DBUG_PRINT("enter",("dir: %s",dir));
#if defined(__WIN__)
if (mkdir((char*) dir))
#ifdef _WIN32
LPSECURITY_ATTRIBUTES attr =
my_dir_security_attributes.lpSecurityDescriptor?
&my_dir_security_attributes : NULL;
BOOL ok = CreateDirectory(dir, attr);
if (!ok)
{
my_osmaperr(GetLastError());
#else
if (mkdir((char*) dir, Flags & my_umask_dir))
#endif
{
#endif
my_errno=errno;
DBUG_PRINT("error",("error %d when creating direcory %s",my_errno,dir));
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))

View File

@ -63,7 +63,9 @@ char curr_dir[FN_REFLEN]= {0},
ulong my_stream_opened=0,my_tmp_file_created=0;
ulong my_file_total_opened= 0;
int my_umask=0664, my_umask_dir=0777;
#ifdef _WIN32
SECURITY_ATTRIBUTES my_dir_security_attributes= {sizeof(SECURITY_ATTRIBUTES),NULL,FALSE};
#endif
myf my_global_flags= 0;
#ifndef DBUG_OFF
my_bool my_assert= 1;

View File

@ -103,6 +103,25 @@ static int my_get_open_flags(File fd)
}
/*
Default security attributes for files and directories
Usually NULL, but can be set
- by either mysqld --bootstrap when started from
mysql_install_db.exe, and creating windows service
- or by mariabackup --copy-back.
The objective in both cases is to fix file or directory
privileges for those files that are outside of the usual
datadir, so that unprivileged service account has full
access to the files.
*/
LPSECURITY_ATTRIBUTES my_win_file_secattr()
{
return my_dir_security_attributes.lpSecurityDescriptor?
&my_dir_security_attributes : NULL;
}
/*
Open a file with sharing. Similar to _sopen() from libc, but allows managing
share delete on win32
@ -128,7 +147,6 @@ File my_win_sopen(const char *path, int oflag, int shflag, int pmode)
DWORD fileshare; /* OS file sharing mode */
DWORD filecreate; /* OS method of opening/creating */
DWORD fileattrib; /* OS file attribute flags */
SECURITY_ATTRIBUTES SecurityAttributes;
DBUG_ENTER("my_win_sopen");
@ -137,9 +155,6 @@ File my_win_sopen(const char *path, int oflag, int shflag, int pmode)
errno= EACCES;
DBUG_RETURN(-1);
}
SecurityAttributes.nLength= sizeof(SecurityAttributes);
SecurityAttributes.lpSecurityDescriptor= NULL;
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
/* decode the access flags */
switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
@ -247,7 +262,7 @@ File my_win_sopen(const char *path, int oflag, int shflag, int pmode)
fileattrib|= FILE_FLAG_RANDOM_ACCESS;
/* try to open/create the file */
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
if ((osfh= CreateFile(path, fileaccess, fileshare,my_win_file_secattr(),
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
{
/*

View File

@ -27,6 +27,7 @@
#include <accctrl.h>
#include <aclapi.h>
#include <ntsecapi.h>
#include <sddl.h>
struct IUnknown;
#include <shlwapi.h>
@ -729,6 +730,26 @@ static int create_db_instance()
set_directory_permissions(opt_datadir, service_user.c_str());
set_directory_permissions("mysql",service_user.c_str());
}
/*
Get security descriptor for the new directory.
It will be passed, as SDDL text, to the mysqld bootstrap subprocess,
to allow for correct subdirectory permissions.
*/
PSECURITY_DESCRIPTOR pSD;
if (GetNamedSecurityInfoA(opt_datadir,SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
0,0,0,0,&pSD) == ERROR_SUCCESS)
{
char* string_sd = NULL;
if (ConvertSecurityDescriptorToStringSecurityDescriptor(pSD, SDDL_REVISION_1,
DACL_SECURITY_INFORMATION,&string_sd,0))
{
_putenv_s("MARIADB_NEW_DIRECTORY_SDDL",string_sd);
LocalFree(string_sd);
}
LocalFree(pSD);
}
/* Do mysqld --bootstrap. */
init_bootstrap_command_line(cmdline, sizeof(cmdline));
@ -843,7 +864,7 @@ end:
/*Remove all service user privileges for the user.*/
if(strncmp(service_user.c_str(), "NT SERVICE\\",
sizeof("NT SERVICE\\")-1)
sizeof("NT SERVICE\\")-1))
{
handle_user_privileges(service_user.c_str(), 0, false);
}

View File

@ -123,6 +123,7 @@
#ifdef _WIN32
#include <handle_connections_win.h>
#include <sddl.h>
#endif
#include <my_service_manager.h>
@ -8166,6 +8167,23 @@ mysqld_get_one_option(const struct my_option *opt, char *argument,
break;
case OPT_BOOTSTRAP:
opt_noacl=opt_bootstrap=1;
#ifdef _WIN32
{
/*
Check if security descriptor is passed from
mysql_install_db.exe.
Used by Windows installer to correctly setup
privileges on the new directories.
*/
char* dir_sddl = getenv("MARIADB_NEW_DIRECTORY_SDDL");
if (dir_sddl)
{
ConvertStringSecurityDescriptorToSecurityDescriptor(
dir_sddl, SDDL_REVISION_1, &my_dir_security_attributes.lpSecurityDescriptor, NULL);
DBUG_ASSERT(my_dir_security_attributes.lpSecurityDescriptor);
}
}
#endif
break;
case OPT_SERVER_ID:
::server_id= global_system_variables.server_id;

View File

@ -233,6 +233,7 @@ static void buf_dump_generate_path(char *path, size_t path_size)
}
}
/*****************************************************************//**
Perform a buffer pool dump into the file specified by
innodb_buffer_pool_filename. If any errors occur then the value of
@ -262,7 +263,10 @@ buf_dump(
buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) to %s",
full_filename);
#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
#ifdef _WIN32
/* use my_fopen() for correct permissions during bootstrap*/
f = my_fopen(tmp_filename, O_RDWR|O_TRUNC|O_CREAT, 0);
#elif defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
#else
{
@ -375,7 +379,7 @@ buf_dump(
ut_free(dump);
done:
ret = fclose(f);
ret = IF_WIN(my_fclose(f,0),fclose(f));
if (ret != 0) {
buf_dump_status(STATUS_ERR,
"Cannot close '%s': %s",

View File

@ -73,11 +73,11 @@ Created 10/21/1995 Heikki Tuuri
#ifdef _WIN32
#include <winioctl.h>
#else
// my_test_if_atomic_write()
#include <my_sys.h>
#endif
// my_test_if_atomic_write() , my_win_secattr()
#include <my_sys.h>
#include <thread>
#include <chrono>
@ -2005,6 +2005,10 @@ os_file_get_last_error_low(
" because of either a thread exit"
" or an application request."
" Retry attempt is made.";
} else if (err == ERROR_PATH_NOT_FOUND) {
ib::error()
<< "This error means that directory did not exist"
" during file creation.";
} else {
ib::info() << OPERATING_SYSTEM_ERROR_MSG;
@ -2137,7 +2141,7 @@ os_file_create_simple_func(
file = CreateFile(
(LPCTSTR) name, access,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL, create_flag, attributes, NULL);
my_win_file_secattr(), create_flag, attributes, NULL);
if (file == INVALID_HANDLE_VALUE) {
@ -2543,7 +2547,7 @@ os_file_create_func(
/* Use default security attributes and no template file. */
file = CreateFile(
name, access, share_mode, NULL,
name, access, share_mode, my_win_file_secattr(),
create_flag, attributes, NULL);
/* If FILE_FLAG_NO_BUFFERING was set, check if this can work at all,
@ -2597,6 +2601,7 @@ A simple function to open or create a file.
@param[out] success true if succeeded
@return own: handle to the file, not defined if error, error number
can be retrieved with os_file_get_last_error */
pfs_os_file_t
os_file_create_simple_no_error_handling_func(
const char* name,
@ -2678,7 +2683,7 @@ os_file_create_simple_no_error_handling_func(
file = CreateFile((LPCTSTR) name,
access,
share_mode,
NULL, // Security attributes
my_win_file_secattr(),
create_flag,
attributes,
NULL); // No template file
@ -2968,7 +2973,7 @@ os_file_get_status_win32(
access,
FILE_SHARE_READ | FILE_SHARE_WRITE
| FILE_SHARE_DELETE, // Full sharing
NULL, // Default security
my_win_file_secattr(),
OPEN_EXISTING, // Existing file only
FILE_ATTRIBUTE_NORMAL, // Normal file
NULL); // No attr. template