MXS-3345: Defer path permission checks
Doing the directory permission checks after all the values have been set helps avoid problems with intermediate values that aren't valid. This happens when --basedir generates invalid derived paths and the correct path is provided as an argument right after it. The path parameter is read from the configuration file only if it hasn't been modified by a command line option. The case where an invalid command line option is given but a valid configuration parameter would override it is still treated as an error. Also added a clarifying comment into set_dirs to make sure the handling for the two path parameters is not moved inside set_runtime_dirs. Fixed the testing scripts for the REST API and MaxCtrl now that the directory permission checks are done correctly. Previously some paths seem to have been ignored.
This commit is contained in:
@ -182,7 +182,8 @@ static bool resolve_maxscale_conf_fname(char** cnf_full_path,
|
||||
const char* home_dir,
|
||||
char* cnf_file_arg);
|
||||
|
||||
static char* check_dir_access(char* dirname, bool, bool);
|
||||
static bool check_dir_access(const char* dirname, bool wr, bool rd);
|
||||
bool check_paths();
|
||||
static int set_user(const char* user);
|
||||
bool pid_file_exists();
|
||||
void write_child_exit_code(int fd, int code);
|
||||
@ -714,51 +715,32 @@ static bool resolve_maxscale_conf_fname(char** cnf_full_path,
|
||||
* @return NULL if directory can be read and written, an error message if either
|
||||
* read or write is not permitted.
|
||||
*/
|
||||
static char* check_dir_access(char* dirname, bool rd, bool wr)
|
||||
static bool check_dir_access(const char* dirname, bool rd, bool wr)
|
||||
{
|
||||
char errbuf[PATH_MAX * 2];
|
||||
char* errstr = NULL;
|
||||
|
||||
if (dirname == NULL)
|
||||
{
|
||||
errstr = MXS_STRDUP_A("Directory argument is NULL");
|
||||
goto retblock;
|
||||
}
|
||||
mxb_assert(dirname);
|
||||
std::ostringstream ss;
|
||||
|
||||
if (access(dirname, F_OK) != 0)
|
||||
{
|
||||
snprintf(errbuf, PATH_MAX * 2 - 1, "Can't access '%s'.", dirname);
|
||||
errbuf[PATH_MAX * 2 - 1] = '\0';
|
||||
errstr = MXS_STRDUP_A(errbuf);
|
||||
goto retblock;
|
||||
ss << "Can't access '" << dirname << "'.";
|
||||
}
|
||||
|
||||
if (rd && !path_is_readable(dirname))
|
||||
else if (rd && access(dirname, R_OK) != 0)
|
||||
{
|
||||
snprintf(errbuf,
|
||||
PATH_MAX * 2 - 1,
|
||||
"MaxScale doesn't have read permission "
|
||||
"to '%s'.",
|
||||
dirname);
|
||||
errbuf[PATH_MAX * 2 - 1] = '\0';
|
||||
errstr = MXS_STRDUP_A(errbuf);
|
||||
goto retblock;
|
||||
ss << "MaxScale doesn't have read permission to '" << dirname << "'.";
|
||||
}
|
||||
|
||||
if (wr && !path_is_writable(dirname))
|
||||
else if (wr && access(dirname, W_OK) != 0)
|
||||
{
|
||||
snprintf(errbuf,
|
||||
PATH_MAX * 2 - 1,
|
||||
"MaxScale doesn't have write permission "
|
||||
"to '%s'.",
|
||||
dirname);
|
||||
errbuf[PATH_MAX * 2 - 1] = '\0';
|
||||
errstr = MXS_STRDUP_A(errbuf);
|
||||
goto retblock;
|
||||
ss << "MaxScale doesn't have write permission to '" << dirname << "'.";
|
||||
}
|
||||
|
||||
retblock:
|
||||
return errstr;
|
||||
auto err = ss.str();
|
||||
|
||||
if (!err.empty())
|
||||
{
|
||||
print_log_n_stderr(true, true, err.c_str(), err.c_str(), errno);
|
||||
}
|
||||
|
||||
return err.empty();
|
||||
}
|
||||
|
||||
static bool init_log()
|
||||
@ -1427,6 +1409,10 @@ bool set_dirs(const char* basedir)
|
||||
|
||||
rv = set_runtime_dirs(basedir);
|
||||
|
||||
// The two paths here are not inside set_runtime_dirs on purpose: they are set by --basedir but not by
|
||||
// --runtimedir. The former is used with tarball installations and the latter is used to run multiple
|
||||
// MaxScale instances on the same server.
|
||||
|
||||
if (rv && (rv = handle_path_arg(&path, basedir, MXS_DEFAULT_LIB_SUBPATH, true, false)))
|
||||
{
|
||||
set_libdir(path);
|
||||
@ -1824,7 +1810,10 @@ int main(int argc, char** argv)
|
||||
break;
|
||||
|
||||
case '?':
|
||||
if (check_paths())
|
||||
{
|
||||
usage();
|
||||
}
|
||||
rc = EXIT_SUCCESS;
|
||||
goto return_main;
|
||||
|
||||
@ -2058,6 +2047,12 @@ int main(int argc, char** argv)
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
if (!check_paths())
|
||||
{
|
||||
rc = MAXSCALE_BADCONFIG;
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
if (daemon_mode)
|
||||
{
|
||||
if (!change_cwd())
|
||||
@ -2690,22 +2685,28 @@ bool handle_path_arg(char** dest, const char* path, const char* arg, bool rd, bo
|
||||
strcat(pathbuffer, arg);
|
||||
}
|
||||
|
||||
if ((errstr = check_dir_access(pathbuffer, rd, wr)) == NULL)
|
||||
{
|
||||
*dest = MXS_STRDUP_A(pathbuffer);
|
||||
rval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
print_log_n_stderr(true, true, errstr, errstr, 0);
|
||||
MXS_FREE(errstr);
|
||||
errstr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool check_paths()
|
||||
{
|
||||
return check_dir_access(get_logdir(), true, false)
|
||||
&& check_dir_access(get_cachedir(), true, true)
|
||||
&& check_dir_access(get_configdir(), true, false)
|
||||
&& check_dir_access(get_module_configdir(), true, false)
|
||||
&& check_dir_access(get_datadir(), true, false)
|
||||
&& check_dir_access(get_langdir(), true, false)
|
||||
&& check_dir_access(get_piddir(), true, true)
|
||||
&& check_dir_access(get_config_persistdir(), true, true)
|
||||
&& check_dir_access(get_connector_plugindir(), true, false)
|
||||
&& check_dir_access(get_libdir(), true, false)
|
||||
&& check_dir_access(get_execdir(), true, false);
|
||||
}
|
||||
|
||||
void set_log_augmentation(const char* value)
|
||||
{
|
||||
// Command line arguments are handled first, thus command line argument
|
||||
|
||||
@ -6,6 +6,10 @@ datadir=@CMAKE_INSTALL_PREFIX@/lib/maxscale
|
||||
cachedir=@CMAKE_INSTALL_PREFIX@/cache/maxscale
|
||||
language=@CMAKE_INSTALL_PREFIX@/lib/maxscale/
|
||||
piddir=@CMAKE_INSTALL_PREFIX@/run/maxscale/
|
||||
persistdir=@CMAKE_INSTALL_PREFIX@/lib/maxscale/maxscale.cnf.d/
|
||||
module_configdir=@CMAKE_INSTALL_PREFIX@/etc/maxscale.modules.d/
|
||||
# This isn't really correct but it's OK as long as it's an empty directory
|
||||
connector_plugindir=@CMAKE_INSTALL_PREFIX@/etc/maxscale.modules.d/
|
||||
admin_auth=false
|
||||
|
||||
[server1]
|
||||
|
||||
@ -7,6 +7,9 @@ cachedir=@CMAKE_INSTALL_PREFIX@/secondary/cache/maxscale
|
||||
language=@CMAKE_INSTALL_PREFIX@/secondary/lib/maxscale/
|
||||
piddir=@CMAKE_INSTALL_PREFIX@/secondary/run/maxscale
|
||||
persistdir=@CMAKE_INSTALL_PREFIX@/secondary/lib/maxscale/maxscale.cnf.d/
|
||||
module_configdir=@CMAKE_INSTALL_PREFIX@/secondary/etc/maxscale.modules.d/
|
||||
# This isn't really correct but it's OK as long as it's an empty directory
|
||||
connector_plugindir=@CMAKE_INSTALL_PREFIX@/secondary/etc/maxscale.modules.d/
|
||||
admin_auth=false
|
||||
admin_port=8990
|
||||
|
||||
|
||||
@ -20,10 +20,12 @@ rm -r $maxscaledir/secondary/run/maxscale
|
||||
test -f /tmp/maxadmin.sock && rm /tmp/maxadmin.sock
|
||||
test -f /tmp/maxadmin2.sock && rm /tmp/maxadmin2.sock
|
||||
|
||||
mkdir -m 0755 -p $maxscaledir/etc/maxscale.modules.d/
|
||||
mkdir -m 0755 -p $maxscaledir/lib/maxscale/maxscale.cnf.d
|
||||
mkdir -m 0755 -p $maxscaledir/cache/maxscale
|
||||
mkdir -m 0755 -p $maxscaledir/run/maxscale
|
||||
mkdir -m 0755 -p $maxscaledir/log/maxscale
|
||||
mkdir -m 0755 -p $maxscaledir/secondary/etc/maxscale.modules.d/
|
||||
mkdir -m 0755 -p $maxscaledir/secondary/lib/maxscale/maxscale.cnf.d
|
||||
mkdir -m 0755 -p $maxscaledir/secondary/cache/maxscale
|
||||
mkdir -m 0755 -p $maxscaledir/secondary/run/maxscale
|
||||
|
||||
Reference in New Issue
Block a user